diff --git a/.bowerrc b/.bowerrc deleted file mode 100644 index 3c5e8c33..00000000 --- a/.bowerrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "directory" : "vendor" -} diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000..b26a34e4 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +7.2.1 diff --git a/scsslint.yml b/.scss-lint.yml similarity index 100% rename from scsslint.yml rename to .scss-lint.yml diff --git a/.travis.yml b/.travis.yml index 13337fbc..f5617c42 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,14 +1,17 @@ language: node_js +dist: trusty node_js: - - "4.1" + - "node" before_install: - - export CHROME_BIN=chromium-browser - - export DISPLAY=:99.0 - - sh -e /etc/init.d/xvfb start - - travis_retry npm install -g bower - - travis_retry npm install -g gulp + - sudo apt-get update + - sudo apt-get install -y libappindicator1 fonts-liberation + - wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb + - sudo dpkg -i google-chrome*.deb install: - travis_retry npm install - - travis_retry bower install before_script: + - export CHROME_BIN=/usr/bin/google-chrome + - export DISPLAY=:99.0 + - sh -e /etc/init.d/xvfb start + - travis_retry npm install -g gulp - gulp deploy diff --git a/CHANGELOG.md b/CHANGELOG.md index b4d17be6..e5f46512 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,32 @@ # Changelog # +## 3.1.0 Perovskia Atriplicifolia (2017-03-10) + +### Features +- New project creation form: Now you can: + - duplicate a project. + - import from Taiga. + - import from Trello. + - import from Jira. + - import from GitHub. + - import from Asana. +- Improve add-members form: Now users can select between their contacts or type an email. +- Contact with the project: if the projects have this module enabled Taiga users can contact them. +- Velocity forecasting. Create sprints according to team velocity. +- Add new wysiwyg editor (like the Medunm editor) with emojis, local storage changes, mentions... +- Add rich text custom fields (with a wysiwyg editor like descreption or comments). +- Add thumbnails and preview for: + - PSD files. + - SVG files. +- i18n: + - Add japanese (ja) translation. + - Add korean (ko) translation. + - Add chinese simplified (zh-Hans) translation. + +### Misc +- Lots of small and not so small bugfixes. +- Remove bower, now use only npm packages. + ## 3.0.0 Stellaria Borealis (2016-10-02) diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md index dc4f151d..068b5851 100644 --- a/ISSUE_TEMPLATE.md +++ b/ISSUE_TEMPLATE.md @@ -2,18 +2,18 @@ Please ensure that your issue is not already reported in our [issues list](https://tree.taiga.io/project/taiga/issues?order_by=-created_date). If this issue was already reported, remember that you can upvote it to raise its importance. -###Do you want to request a *feature* or report a *bug*? +**Do you want to request a *feature* or report a *bug*?** -###What is the current behavior? +**What is the current behavior?** -###If the current behavior is a bug, please provide the steps to reproduce. +**If the current behavior is a bug, please provide the steps to reproduce.** -###What is the expected behavior? +**What is the expected behavior?** -###Is it happening in taiga.io or in your own instance? +**Is it happening in taiga.io or in your own instance?** -###What browser/version are you using? +**What browser/version are you using?** -###Are there any console errors *(Ctrl + F12)* in red? +**Are there any console errors *(Ctrl + F12)* in red?** Thanks for reporting! diff --git a/README.md b/README.md index 14d6d7c0..dff5f181 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,8 @@ # Taiga Front # -![Kaleidos Project](http://kaleidos.net/static/img/badge.png "Kaleidos Project") -[![Managed with Taiga](https://taiga.io/media/support/attachments/article-22/banner-gh.png)](https://taiga.io "Managed with Taiga") -[![Build Status](https://travis-ci.org/taigaio/taiga-front.svg?branch=public-header-bar)](https://travis-ci.org/taigaio/taiga-front) -[![Dependency Status](https://www.versioneye.com/user/projects/561ba659a193340f280013f4/badge.svg?style=flat)](https://www.versioneye.com/user/projects/561ba659a193340f280013f4) - +![Kaleidos Project](http://kaleidos.net/static/img/badge.svg "Kaleidos Project") +[![Managed with Taiga.io](https://img.shields.io/badge/managed%20with-TAIGA.io-709f14.svg)](https://tree.taiga.io/project/taiga/ "Managed with Taiga.io") +[![Build Status](https://img.shields.io/travis/taigaio/taiga-front.svg)](https://travis-ci.org/taigaio/taiga-front "Build Status") ## Get the compiled version ## @@ -39,6 +37,7 @@ Every code patch accepted in taiga codebase is licensed under [AGPL v3.0](http:/ Please read carefully [our license](https://github.com/taigaio/taiga-front/blob/master/LICENSE) and ask us if you have any questions. +Emoji provided free by [Twemoji](https://github.com/twitter/twemoji) #### Bug reports, enhancements and support #### @@ -125,14 +124,12 @@ sass -v # should return Sass 3.3.8 (Maptastic Maple) Complete process for all OS at: http://sass-lang.com/install -**Node + Bower + Gulp** +**Node + Gulp** We recommend using [nvm](https://github.com/creationix/nvm) to manage different node versions ``` npm install -g gulp -npm install -g bower npm install -bower install gulp ``` diff --git a/app-loader/app-loader.coffee b/app-loader/app-loader.coffee index 2951fb09..b93e09e7 100644 --- a/app-loader/app-loader.coffee +++ b/app-loader/app-loader.coffee @@ -15,6 +15,7 @@ window.taigaConfig = { "privacyPolicyUrl": null, "termsOfServiceUrl": null, "maxUploadFileSize": null, + "importers": [], "contribPlugins": [] } diff --git a/app/coffee/app.coffee b/app/coffee/app.coffee index cca4eae4..3ee64100 100644 --- a/app/coffee/app.coffee +++ b/app/coffee/app.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -126,6 +126,54 @@ configure = ($routeProvider, $locationProvider, $httpProvider, $provide, $tgEven controllerAs: "vm" } ) + + # Project + $routeProvider.when("/project/new", + { + title: "PROJECT.CREATE.TITLE", + templateUrl: "projects/create/create-project.html", + loader: true, + controller: "CreateProjectCtrl", + controllerAs: "vm" + } + ) + + # Project - scrum + $routeProvider.when("/project/new/scrum", + { + title: "PROJECT.CREATE.TITLE", + template: "", + loader: true + } + ) + + # Project - kanban + $routeProvider.when("/project/new/kanban", + { + title: "PROJECT.CREATE.TITLE", + template: "", + loader: true + } + ) + + # Project - duplicate + $routeProvider.when("/project/new/duplicate", + { + title: "PROJECT.CREATE.TITLE", + template: "", + loader: true + } + ) + + # Project - import + $routeProvider.when("/project/new/import/:platform?", + { + title: "PROJECT.CREATE.TITLE", + template: "", + loader: true + } + ) + # Project $routeProvider.when("/project/:pslug/", { diff --git a/app/coffee/classes.coffee b/app/coffee/classes.coffee index 89a12998..9283e935 100644 --- a/app/coffee/classes.coffee +++ b/app/coffee/classes.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/admin.coffee b/app/coffee/modules/admin.coffee index f3a09d06..3fc427df 100644 --- a/app/coffee/modules/admin.coffee +++ b/app/coffee/modules/admin.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/admin/lightboxes.coffee b/app/coffee/modules/admin/lightboxes.coffee index 9802d72a..54a4c984 100644 --- a/app/coffee/modules/admin/lightboxes.coffee +++ b/app/coffee/modules/admin/lightboxes.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -27,112 +27,6 @@ debounce = @.taiga.debounce module = angular.module("taigaKanban") -############################################################################# -## Create Members Lightbox Directive -############################################################################# - -class LightboxAddMembersController - @.$inject = [ - "$scope", - "lightboxService", - "tgLoader", - "$tgConfirm", - "$tgResources", - "$rootScope", - ] - - constructor: (@scope, @lightboxService, @tgLoader, @confirm, @rs, @rootScope) -> - @._defaultMaxInvites = 4 - @._defaultRole = @.project.roles[0].id - @.form = null - @.submitInvites = false - @.canAddUsers = true - @.memberInvites = [] - - if @.project.max_memberships == null - @.membersLimit = @._defaultMaxInvites - else - pendingMembersCount = Math.max(@.project.max_memberships - @.project.total_memberships, 0) - @.membersLimit = Math.min(pendingMembersCount, @._defaultMaxInvites) - - @.addSingleMember() - - addSingleMember: () -> - @.memberInvites.push({email:'', role_id: @._defaultRole}) - - if @.memberInvites.length >= @.membersLimit - @.canAddUsers = false - @.showWarningMessage = (!@.canAddUsers && - @.project.total_memberships + @.memberInvites.length == @.project.max_memberships) - - removeSingleMember: (index) -> - @.memberInvites.splice(index, 1) - - @.canAddUsers = true - @.showWarningMessage = @.membersLimit == 1 - - submit: () -> - # Need to reset the form constrains - @.form.initializeFields() - @.form.reset() - return if not @.form.validate() - - @.memberInvites = _.filter(@.memberInvites, (invites) -> - invites.email != "") - - @.submitInvites = true - promise = @rs.memberships.bulkCreateMemberships( - @.project.id, - @.memberInvites, - @.invitationText - ) - promise.then( - @._onSuccessInvite.bind(this), - @._onErrorInvite.bind(this) - ) - - _onSuccessInvite: () -> - @.submitInvites = false - @rootScope.$broadcast("membersform:new:success") - @lightboxService.closeAll() - @confirm.notify("success") - - _onErrorInvite: (response) -> - @.submitInvites = false - errors = {} - _.each response.data.bulk_memberships, (value, index) => - if value.email - errors["email-#{index}"] = value.email[0] - if value.role - errors["role-#{index}"] = value.role[0] - - @.form.setErrors(errors) - if response.data._error_message - @confirm.notify("error", response.data._error_message) - -module.controller("LbAddMembersController", LightboxAddMembersController) - - - -LightboxAddMembersDirective = (lightboxService) -> - link = (scope, el, attrs, ctrl) -> - lightboxService.open(el) - ctrl.form = el.find("form").checksley() - - return { - scope: {}, - bindToController: { - project: '=', - }, - controller: 'LbAddMembersController', - controllerAs: 'vm', - templateUrl: 'admin/lightbox-add-members.html', - link: link - } - -module.directive("tgLbAddMembers", ["lightboxService", LightboxAddMembersDirective]) - - ############################################################################# ## Warning message directive ############################################################################# diff --git a/app/coffee/modules/admin/memberships.coffee b/app/coffee/modules/admin/memberships.coffee index 1ab6c54f..e297513f 100644 --- a/app/coffee/modules/admin/memberships.coffee +++ b/app/coffee/modules/admin/memberships.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -50,11 +50,12 @@ class MembershipsController extends mixOf(taiga.Controller, taiga.PageMixin, tai "$translate", "$tgAuth", "tgLightboxFactory", - "tgErrorHandlingService" + "tgErrorHandlingService", + "tgProjectService" ] constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, @navUrls, @analytics, - @appMetaService, @translate, @auth, @lightboxFactory, @errorHandlingService) -> + @appMetaService, @translate, @auth, @lightboxFactory, @errorHandlingService, @projectService) -> bindMethods(@) @scope.project = {} @@ -74,17 +75,18 @@ class MembershipsController extends mixOf(taiga.Controller, taiga.PageMixin, tai @analytics.trackEvent("membership", "create", "create memberships on admin", 1) loadProject: -> - return @rs.projects.getBySlug(@params.pslug).then (project) => - if not project.i_am_admin - @errorHandlingService.permissionDenied() + project = @projectService.project.toJS() - @scope.projectId = project.id - @scope.project = project + if not project.i_am_admin + @errorHandlingService.permissionDenied() - @scope.canAddUsers = project.max_memberships == null || project.max_memberships > project.total_memberships + @scope.projectId = project.id + @scope.project = project - @scope.$emit('project:loaded', project) - return project + @scope.canAddUsers = project.max_memberships == null || project.max_memberships > project.total_memberships + + @scope.$emit('project:loaded', project) + return project loadMembers: -> httpFilters = @.getUrlFilters() @@ -99,11 +101,12 @@ class MembershipsController extends mixOf(taiga.Controller, taiga.PageMixin, tai return data loadInitialData: -> - return @.loadProject().then () => - return @q.all([ - @.loadMembers(), - @auth.refresh() - ]) + @.loadProject() + + return @q.all([ + @.loadMembers(), + @auth.refresh() + ]) getUrlFilters: -> filters = _.pick(@location.search(), "page") @@ -392,7 +395,7 @@ module.directive("tgMembershipsRowRoleSelector", ["$log", "$tgRepo", "$tgConfirm ############################################################################# MembershipsRowActionsDirective = ($log, $repo, $rs, $confirm, $compile, $translate, $location, - $navUrls, lightboxFactory) -> + $navUrls, lightboxFactory, projectService) -> activedTemplate = """
@@ -455,7 +458,8 @@ MembershipsRowActionsDirective = ($log, $repo, $rs, $confirm, $compile, $transla if $scope.page > 1 && ($scope.count - 1) <= $scope.paginatedBy $ctrl.selectFilter("page", $scope.page - 1) - $ctrl.loadInitialData() + projectService.fetchProject().then => + $ctrl.loadInitialData() else $location.path($navUrls.resolve("home")) @@ -492,7 +496,7 @@ MembershipsRowActionsDirective = ($log, $repo, $rs, $confirm, $compile, $transla module.directive("tgMembershipsRowActions", ["$log", "$tgRepo", "$tgResources", "$tgConfirm", "$compile", "$translate", "$tgLocation", "$tgNavUrls", "tgLightboxFactory", - MembershipsRowActionsDirective]) + "tgProjectService", MembershipsRowActionsDirective]) ############################################################################# diff --git a/app/coffee/modules/admin/nav.coffee b/app/coffee/modules/admin/nav.coffee index e3fc1d71..b932e47d 100644 --- a/app/coffee/modules/admin/nav.coffee +++ b/app/coffee/modules/admin/nav.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/admin/project-profile.coffee b/app/coffee/modules/admin/project-profile.coffee index 65eb759c..669338b5 100644 --- a/app/coffee/modules/admin/project-profile.coffee +++ b/app/coffee/modules/admin/project-profile.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -54,15 +54,17 @@ class ProjectProfileController extends mixOf(taiga.Controller, taiga.PageMixin) "$translate", "$tgAuth", "tgCurrentUserService", - "tgErrorHandlingService" + "tgErrorHandlingService", + "tgProjectService", + "$tgModel" ] constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, @navUrls, - @appMetaService, @translate, @tgAuth, @currentUserService, @errorHandlingService) -> + @appMetaService, @translate, @tgAuth, @currentUserService, @errorHandlingService, @projectService, @model) -> @scope.project = {} - promise = @.loadInitialData() @scope.projectTags = [] + promise = @.loadInitialData() promise.then => sectionName = @translate.instant( @scope.sectionName) @@ -83,32 +85,33 @@ class ProjectProfileController extends mixOf(taiga.Controller, taiga.PageMixin) @appMetaService.setAll(title, description) loadProject: -> - return @rs.projects.getBySlug(@params.pslug).then (project) => - if not project.i_am_admin - @errorHandlingService.permissionDenied() + project = @projectService.project.toJS() + project = @model.make_model("projects", project) - @scope.projectId = project.id - @scope.project = project - @scope.epicStatusList = _.sortBy(project.epic_statuses, "order") - @scope.usStatusList = _.sortBy(project.us_statuses, "order") - @scope.pointsList = _.sortBy(project.points, "order") - @scope.taskStatusList = _.sortBy(project.task_statuses, "order") - @scope.issueTypesList = _.sortBy(project.issue_types, "order") - @scope.issueStatusList = _.sortBy(project.issue_statuses, "order") - @scope.prioritiesList = _.sortBy(project.priorities, "order") - @scope.severitiesList = _.sortBy(project.severities, "order") - @scope.$emit('project:loaded', project) + if not project.i_am_admin + @errorHandlingService.permissionDenied() - @scope.projectTags = _.map @scope.project.tags, (it) => - return [it, @scope.project.tags_colors[it]] + @scope.projectId = project.id + @scope.project = project + @scope.epicStatusList = _.sortBy(project.epic_statuses, "order") + @scope.usStatusList = _.sortBy(project.us_statuses, "order") + @scope.pointsList = _.sortBy(project.points, "order") + @scope.taskStatusList = _.sortBy(project.task_statuses, "order") + @scope.issueTypesList = _.sortBy(project.issue_types, "order") + @scope.issueStatusList = _.sortBy(project.issue_statuses, "order") + @scope.prioritiesList = _.sortBy(project.priorities, "order") + @scope.severitiesList = _.sortBy(project.severities, "order") + @scope.$emit('project:loaded', project) - return project + @scope.projectTags = _.map @scope.project.tags, (it) => + return [it, @scope.project.tags_colors[it]] + + return project loadInitialData: -> - return @q.all([ - @.loadProject(), - @tgAuth.refresh() - ]) + @.loadProject() + + return @tgAuth.refresh() openDeleteLightbox: -> @rootscope.$broadcast("deletelightbox:new", @scope.project) @@ -158,9 +161,9 @@ ProjectProfileDirective = ($repo, $confirm, $loading, $navurls, $location, proje }) $location.path(newUrl) - $ctrl.loadInitialData() + projectService.fetchProject().then () => + $ctrl.loadInitialData() - projectService.fetchProject() currentUserService.loadProjects() promise.then null, (data) -> diff --git a/app/coffee/modules/admin/project-values.coffee b/app/coffee/modules/admin/project-values.coffee index a00d4710..4cbe826e 100644 --- a/app/coffee/modules/admin/project-values.coffee +++ b/app/coffee/modules/admin/project-values.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -53,36 +53,36 @@ class ProjectValuesSectionController extends mixOf(taiga.Controller, taiga.PageM "$tgNavUrls", "tgAppMetaService", "$translate", - "tgErrorHandlingService" + "tgErrorHandlingService", + "tgProjectService" ] constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, @navUrls, - @appMetaService, @translate, @errorHandlingService) -> + @appMetaService, @translate, @errorHandlingService, @projectService) -> @scope.project = {} - promise = @.loadInitialData() + @.loadInitialData() - promise.then () => - sectionName = @translate.instant(@scope.sectionName) + sectionName = @translate.instant(@scope.sectionName) - title = @translate.instant("ADMIN.PROJECT_VALUES.PAGE_TITLE", { - "sectionName": sectionName, - "projectName": @scope.project.name - }) - description = @scope.project.description - @appMetaService.setAll(title, description) + title = @translate.instant("ADMIN.PROJECT_VALUES.PAGE_TITLE", { + "sectionName": sectionName, + "projectName": @scope.project.name + }) - promise.then null, @.onInitialDataError.bind(@) + description = @scope.project.description + @appMetaService.setAll(title, description) loadProject: -> - return @rs.projects.getBySlug(@params.pslug).then (project) => - if not project.i_am_admin - @errorHandlingService.permissionDenied() + project = @projectService.project.toJS() - @scope.projectId = project.id - @scope.project = project - @scope.$emit('project:loaded', project) - return project + if not project.i_am_admin + @errorHandlingService.permissionDenied() + + @scope.projectId = project.id + @scope.project = project + @scope.$emit('project:loaded', project) + return project loadInitialData: -> promise = @.loadProject() @@ -106,8 +106,11 @@ class ProjectValuesController extends taiga.Controller constructor: (@scope, @rootscope, @repo, @confirm, @rs) -> @scope.$on("admin:project-values:move", @.moveValue) - @rootscope.$on("project:loaded", @.loadValues) + unwatch = @scope.$watch "resource", (resource) => + if resource + @.loadValues() + unwatch() loadValues: => return @rs[@scope.resource].listValues(@scope.projectId, @scope.type).then (values) => @scope.values = values @@ -131,7 +134,7 @@ module.controller("ProjectValuesController", ProjectValuesController) ## Project values directive ############################################################################# -ProjectValuesDirective = ($log, $repo, $confirm, $location, animationFrame, $translate, $rootscope) -> +ProjectValuesDirective = ($log, $repo, $confirm, $location, animationFrame, $translate, $rootscope, projectService) -> ## Drag & Drop Link linkDragAndDrop = ($scope, $el, $attrs) -> @@ -211,6 +214,8 @@ ProjectValuesDirective = ($log, $repo, $confirm, $location, animationFrame, $tra row.addClass("hidden") row.siblings(".visualization").removeClass('hidden') + projectService.fetchProject() + promise.then null, (data) -> form.setErrors(data) @@ -325,7 +330,7 @@ ProjectValuesDirective = ($log, $repo, $confirm, $location, animationFrame, $tra return {link:link} module.directive("tgProjectValues", ["$log", "$tgRepo", "$tgConfirm", "$tgLocation", "animationFrame", - "$translate", "$rootScope", ProjectValuesDirective]) + "$translate", "$rootScope", "tgProjectService", ProjectValuesDirective]) ############################################################################# @@ -403,6 +408,7 @@ module.directive("tgColorSelection", ColorSelectionDirective) # Custom attributes types (see taiga-back/taiga/projects/custom_attributes/choices.py) TEXT_TYPE = "text" MULTILINE_TYPE = "multiline" +RICHTEXT_TYPE = "richtext" DATE_TYPE = "date" URL_TYPE = "url" @@ -416,6 +422,10 @@ TYPE_CHOICES = [ key: MULTILINE_TYPE, name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_MULTI" }, + { + key: RICHTEXT_TYPE, + name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_RICHTEXT" + }, { key: DATE_TYPE, name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_DATE" @@ -437,26 +447,28 @@ class ProjectCustomAttributesController extends mixOf(taiga.Controller, taiga.Pa "$tgLocation", "$tgNavUrls", "tgAppMetaService", - "$translate" + "$translate", + "tgProjectService" ] constructor: (@scope, @rootscope, @repo, @rs, @params, @q, @location, @navUrls, @appMetaService, - @translate) -> + @translate, @projectService) -> @scope.TYPE_CHOICES = TYPE_CHOICES + @scope.project = @projectService.project.toJS() + @scope.projectId = @scope.project.id - @scope.project = {} + sectionName = @translate.instant(@scope.sectionName) + title = @translate.instant("ADMIN.CUSTOM_ATTRIBUTES.PAGE_TITLE", { + "sectionName": sectionName, + "projectName": @scope.project.name + }) + description = @scope.project.description + @appMetaService.setAll(title, description) - @rootscope.$on "project:loaded", => + @scope.init = (type) => + @scope.type = type @.loadCustomAttributes() - sectionName = @translate.instant(@scope.sectionName) - title = @translate.instant("ADMIN.CUSTOM_ATTRIBUTES.PAGE_TITLE", { - "sectionName": sectionName, - "projectName": @scope.project.name - }) - description = @scope.project.description - @appMetaService.setAll(title, description) - ######################### # Custom Attribute ######################### @@ -716,22 +728,26 @@ class ProjectTagsController extends taiga.Controller "$tgConfirm", "$tgResources", "$tgModel", + "tgProjectService" ] - constructor: (@scope, @rootscope, @repo, @confirm, @rs, @model) -> + constructor: (@scope, @rootscope, @repo, @confirm, @rs, @model, @projectService) -> @.loading = true - @rootscope.$on("project:loaded", @.loadTags) + @.loadTags() loadTags: => - return @rs.projects.tagsColors(@scope.projectId).then (tags) => + project = @projectService.project.toJS() + return @rs.projects.tagsColors(project.id).then (tags) => @scope.projectTagsAll = _.map tags.getAttrs(), (color, name) => @model.make_model('tag', {name: name, color: color}) @.filterAndSortTags() @.loading = false filterAndSortTags: => + @scope.projectTags = _.sortBy @scope.projectTagsAll, (it) -> it.name.toLowerCase() + @scope.projectTags = _.filter( - _.sortBy(@scope.projectTagsAll, "name"), + @scope.projectTags, (tag) => tag.name.indexOf(@scope.tagsFilter.name) != -1 ) diff --git a/app/coffee/modules/admin/roles.coffee b/app/coffee/modules/admin/roles.coffee index e60daa13..e66af245 100644 --- a/app/coffee/modules/admin/roles.coffee +++ b/app/coffee/modules/admin/roles.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -47,13 +47,15 @@ class RolesController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fil "$q", "$tgLocation", "$tgNavUrls", + "$tgModel", "tgAppMetaService", "$translate", - "tgErrorHandlingService" + "tgErrorHandlingService", + "tgProjectService" ] constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, @navUrls, - @appMetaService, @translate, @errorHandlingService) -> + @model, @appMetaService, @translate, @errorHandlingService, @projectService) -> bindMethods(@) @scope.sectionName = "ADMIN.MENU.PERMISSIONS" @@ -70,17 +72,19 @@ class RolesController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fil promise.then null, @.onInitialDataError.bind(@) loadProject: -> - return @rs.projects.getBySlug(@params.pslug).then (project) => - if not project.i_am_admin - @errorHandlingService.permissionDenied() + project = @projectService.project.toJS() + project = @model.make_model("projects", project) - @scope.projectId = project.id - @scope.project = project + if not project.i_am_admin + @errorHandlingService.permissionDenied() - @scope.$emit('project:loaded', project) - @scope.anyComputableRole = _.some(_.map(project.roles, (point) -> point.computable)) + @scope.projectId = project.id + @scope.project = project - return project + @scope.$emit('project:loaded', project) + @scope.anyComputableRole = _.some(_.map(project.roles, (point) -> point.computable)) + + return project loadRoles: -> return @rs.roles.list(@scope.projectId).then (roles) => @@ -103,9 +107,12 @@ class RolesController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fil return roles loadInitialData: -> - promise = @.loadProject() - promise.then(=> @.loadRoles()) - return promise + @.loadProject() + return @.loadRoles() + + forceLoadProject: () -> + @projectService.fetchProject () => + @.loadProject() setRole: (role) -> @scope.role = role @@ -126,7 +133,7 @@ class RolesController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fil warning = @translate.instant("ADMIN.ROLES.WARNING_DELETE_ROLE") return @confirm.askChoice(title, subtitle, choices, replacement, warning).then (response) => onSuccess = => - @.loadProject() + @.forceLoadProject() @.loadRoles().finally => response.finish() onError = => @@ -137,7 +144,7 @@ class RolesController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fil _enableComputable: => onSuccess = => @confirm.notify("success") - @.loadProject() + @.forceLoadProject() onError = => @confirm.notify("error") @@ -150,7 +157,7 @@ class RolesController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fil onSuccess = => response.finish() @confirm.notify("success") - @.loadProject() + @.forceLoadProject() onError = => response.finish() @confirm.notify("error") @@ -264,7 +271,7 @@ NewRoleDirective = ($tgrepo, $confirm) -> $scope.roles.splice(insertPosition, 0, role) $ctrl.setRole(role) $el.find(".add-button").show() - $ctrl.loadProject() + $ctrl.forceLoadProject() onError = -> $confirm.notify("error") @@ -474,7 +481,7 @@ RolePermissionsDirective = ($rootscope, $repo, $confirm, $compile) -> renderResume(target.parents(".category-config"), categories[categoryId]) $rootscope.$broadcast("projects:reload") $confirm.notify("success") - $ctrl.loadProject() + $ctrl.forceLoadProject() onError = -> $confirm.notify("error") diff --git a/app/coffee/modules/admin/third-parties.coffee b/app/coffee/modules/admin/third-parties.coffee index 74ea9ed7..697af026 100644 --- a/app/coffee/modules/admin/third-parties.coffee +++ b/app/coffee/modules/admin/third-parties.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -46,10 +46,11 @@ class WebhooksController extends mixOf(taiga.Controller, taiga.PageMixin, taiga. "$tgNavUrls", "tgAppMetaService", "$translate", - "tgErrorHandlingService" + "tgErrorHandlingService", + "tgProjectService" ] - constructor: (@scope, @repo, @rs, @params, @location, @navUrls, @appMetaService, @translate, @errorHandlingService) -> + constructor: (@scope, @repo, @rs, @params, @location, @navUrls, @appMetaService, @translate, @errorHandlingService, @projectService) -> bindMethods(@) @scope.sectionName = "ADMIN.WEBHOOKS.SECTION_NAME" @@ -71,21 +72,20 @@ class WebhooksController extends mixOf(taiga.Controller, taiga.PageMixin, taiga. @scope.webhooks = webhooks loadProject: -> - return @rs.projects.getBySlug(@params.pslug).then (project) => - if not project.i_am_admin - @errorHandlingService.permissionDenied() + project = @projectService.project.toJS() - @scope.projectId = project.id - @scope.project = project - @scope.$emit('project:loaded', project) - return project + if not project.i_am_admin + @errorHandlingService.permissionDenied() + + @scope.projectId = project.id + @scope.project = project + @scope.$emit('project:loaded', project) + return project loadInitialData: -> - promise = @.loadProject() - promise.then => - @.loadWebhooks() + @.loadProject() - return promise + return @.loadWebhooks() module.controller("WebhooksController", WebhooksController) @@ -309,10 +309,11 @@ class GithubController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi "$tgResources", "$routeParams", "tgAppMetaService", - "$translate" + "$translate", + "tgProjectService" ] - constructor: (@scope, @repo, @rs, @params, @appMetaService, @translate) -> + constructor: (@scope, @repo, @rs, @params, @appMetaService, @translate, @projectService) -> bindMethods(@) @scope.sectionName = @translate.instant("ADMIN.GITHUB.SECTION_NAME") @@ -332,16 +333,16 @@ class GithubController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi @scope.github = github loadProject: -> - return @rs.projects.getBySlug(@params.pslug).then (project) => - @scope.projectId = project.id - @scope.project = project - @scope.$emit('project:loaded', project) - return project + project = @projectService.project.toJS() + + @scope.projectId = project.id + @scope.project = project + @scope.$emit('project:loaded', project) + return project loadInitialData: -> promise = @.loadProject() - promise.then(=> @.loadModules()) - return promise + return @.loadModules() module.controller("GithubController", GithubController) @@ -357,10 +358,11 @@ class GitlabController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi "$tgResources", "$routeParams", "tgAppMetaService", - "$translate" + "$translate", + "tgProjectService" ] - constructor: (@scope, @repo, @rs, @params, @appMetaService, @translate) -> + constructor: (@scope, @repo, @rs, @params, @appMetaService, @translate, @projectService) -> bindMethods(@) @scope.sectionName = @translate.instant("ADMIN.GITLAB.SECTION_NAME") @@ -382,16 +384,16 @@ class GitlabController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi @scope.gitlab = gitlab loadProject: -> - return @rs.projects.getBySlug(@params.pslug).then (project) => - @scope.projectId = project.id - @scope.project = project - @scope.$emit('project:loaded', project) - return project + project = @projectService.project.toJS() + + @scope.projectId = project.id + @scope.project = project + @scope.$emit('project:loaded', project) + return project loadInitialData: -> - promise = @.loadProject() - promise.then(=> @.loadModules()) - return promise + @.loadProject() + return @.loadModules() module.controller("GitlabController", GitlabController) @@ -407,10 +409,11 @@ class BitbucketController extends mixOf(taiga.Controller, taiga.PageMixin, taiga "$tgResources", "$routeParams", "tgAppMetaService", - "$translate" + "$translate", + "tgProjectService" ] - constructor: (@scope, @repo, @rs, @params, @appMetaService, @translate) -> + constructor: (@scope, @repo, @rs, @params, @appMetaService, @translate, @projectService) -> bindMethods(@) @scope.sectionName = @translate.instant("ADMIN.BITBUCKET.SECTION_NAME") @@ -432,16 +435,16 @@ class BitbucketController extends mixOf(taiga.Controller, taiga.PageMixin, taiga @scope.bitbucket = bitbucket loadProject: -> - return @rs.projects.getBySlug(@params.pslug).then (project) => - @scope.projectId = project.id - @scope.project = project - @scope.$emit('project:loaded', project) - return project + project = @projectService.project.toJS() + + @scope.projectId = project.id + @scope.project = project + @scope.$emit('project:loaded', project) + return project loadInitialData: -> - promise = @.loadProject() - promise.then(=> @.loadModules()) - return promise + @.loadProject() + return @.loadModules() module.controller("BitbucketController", BitbucketController) @@ -598,10 +601,11 @@ class GogsController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Filt "$tgResources", "$routeParams", "tgAppMetaService", - "$translate" + "$translate", + "tgProjectService" ] - constructor: (@scope, @repo, @rs, @params, @appMetaService, @translate) -> + constructor: (@scope, @repo, @rs, @params, @appMetaService, @translate, @projectService) -> bindMethods(@) @scope.sectionName = @translate.instant("ADMIN.GOGS.SECTION_NAME") @@ -621,15 +625,15 @@ class GogsController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Filt @scope.gogs = gogs loadProject: -> - return @rs.projects.getBySlug(@params.pslug).then (project) => - @scope.projectId = project.id - @scope.project = project - @scope.$emit('project:loaded', project) - return project + project = @projectService.project.toJS() + + @scope.projectId = project.id + @scope.project = project + @scope.$emit('project:loaded', project) + return project loadInitialData: -> - promise = @.loadProject() - promise.then(=> @.loadModules()) - return promise + @.loadProject() + return @.loadModules() module.controller("GogsController", GogsController) diff --git a/app/coffee/modules/auth.coffee b/app/coffee/modules/auth.coffee index e4f4dcf0..242d4ad2 100644 --- a/app/coffee/modules/auth.coffee +++ b/app/coffee/modules/auth.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -105,6 +105,7 @@ class AuthService extends taiga.Service return @rootscope.user userData = @storage.get("userInfo") + if userData user = @model.make_model("users", userData) @rootscope.user = user @@ -205,9 +206,6 @@ class AuthService extends taiga.Service acceptInvitiationWithNewUser: (data) -> return @.register(data, "private", false) - acceptInvitiationWithExistingUser: (data) -> - return @.register(data, "private", true) - forgotPassword: (data) -> url = @urls.resolve("users-password-recovery") data = _.clone(data, false) @@ -478,7 +476,7 @@ module.directive("tgChangePasswordFromRecovery", ["$tgAuth", "$tgConfirm", "$tgL ## Invitation ############################################################################# -InvitationDirective = ($auth, $confirm, $location, $params, $navUrls, $analytics, $translate, config) -> +InvitationDirective = ($auth, $confirm, $location, $config, $params, $navUrls, $analytics, $translate, config) -> link = ($scope, $el, $attrs) -> token = $params.token @@ -515,7 +513,14 @@ InvitationDirective = ($auth, $confirm, $location, $params, $navUrls, $analytics if not loginForm.validate() return - promise = $auth.acceptInvitiationWithExistingUser($scope.dataLogin) + loginFormType = $config.get("loginFormType", "normal") + data = $scope.dataLogin + + promise = $auth.login({ + username: data.username, + password: data.password, + invitation_token: data.token + }, loginFormType) promise.then(onSuccessSubmitLogin, onErrorSubmitLogin) $el.on "submit", "form.login-form", submitLogin @@ -555,7 +560,7 @@ InvitationDirective = ($auth, $confirm, $location, $params, $navUrls, $analytics return {link:link} -module.directive("tgInvitation", ["$tgAuth", "$tgConfirm", "$tgLocation", "$routeParams", +module.directive("tgInvitation", ["$tgAuth", "$tgConfirm", "$tgLocation", "$tgConfig", "$routeParams", "$tgNavUrls", "$tgAnalytics", "$translate", "$tgConfig", InvitationDirective]) diff --git a/app/coffee/modules/backlog.coffee b/app/coffee/modules/backlog.coffee index 173df9a7..fc7b01b6 100644 --- a/app/coffee/modules/backlog.coffee +++ b/app/coffee/modules/backlog.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/backlog/lightboxes.coffee b/app/coffee/modules/backlog/lightboxes.coffee index 324ce8b1..f332fb86 100644 --- a/app/coffee/modules/backlog/lightboxes.coffee +++ b/app/coffee/modules/backlog/lightboxes.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -38,6 +38,7 @@ CreateEditSprint = ($repo, $confirm, $rs, $rootscope, lightboxService, $loading, createSprint = true form = null $scope.newSprint = {} + ussToAdd = null resetSprint = () -> form.reset() if form @@ -97,7 +98,10 @@ CreateEditSprint = ($repo, $confirm, $rs, $rootscope, lightboxService, $loading, else return it - $rootscope.$broadcast(broadcastEvent, data) + if broadcastEvent == "sprintform:create:success" && ussToAdd + $rootscope.$broadcast(broadcastEvent, data, ussToAdd) + else + $rootscope.$broadcast(broadcastEvent, data) lightboxService.close($el) @@ -135,7 +139,8 @@ CreateEditSprint = ($repo, $confirm, $rs, $rootscope, lightboxService, $loading, return sortedSprints[sortedSprints.length - 1] - $scope.$on "sprintform:create", (event, projectId) -> + $scope.$on "sprintform:create", (event, projectId, uss) -> + ussToAdd = uss resetSprint() form = $el.find("form").checksley() diff --git a/app/coffee/modules/backlog/main.coffee b/app/coffee/modules/backlog/main.coffee index b1527031..a4a93e75 100644 --- a/app/coffee/modules/backlog/main.coffee +++ b/app/coffee/modules/backlog/main.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -59,7 +59,8 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F "$tgQueueModelTransformation", "tgErrorHandlingService", "$tgStorage", - "tgFilterRemoteStorageService" + "tgFilterRemoteStorageService", + "tgProjectService" ] storeCustomFiltersName: 'backlog-custom-filters' @@ -69,7 +70,7 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, @appMetaService, @navUrls, @events, @analytics, @translate, @loading, @rs2, @modelTransform, @errorHandlingService, - @storage, @filterRemoteStorageService) -> + @storage, @filterRemoteStorageService, @projectService) -> bindMethods(@) @.backlogOrder = {} @@ -86,6 +87,7 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F @showTags = false @activeFilters = false @scope.showGraphPlaceholder = null + @displayVelocity = false @.initializeEventHandlers() @@ -120,8 +122,10 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F @confirm.notify("success") @analytics.trackEvent("userstory", "create", "bulk create userstory on backlog", 1) - @scope.$on "sprintform:create:success", => - @.loadSprints() + @scope.$on "sprintform:create:success", (e, data, ussToMove) => + @.loadSprints().then () => + @scope.$broadcast("sprintform:create:success:callback", ussToMove) + @.loadProjectStats() @confirm.notify("success") @analytics.trackEvent("sprint", "create", "create sprint on backlog", 1) @@ -181,6 +185,17 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F toggleActiveFilters: -> @activeFilters = !@activeFilters + toggleVelocityForecasting: -> + @displayVelocity = !@displayVelocity + if !@displayVelocity + @scope.visibleUserStories = _.map @scope.userstories, (it) -> + return it.ref + else + @scope.visibleUserStories = _.map @.forecastedStories, (it) -> + return it.ref + scopeDefer @scope, => + @scope.$broadcast("userstories:loaded") + loadProjectStats: -> return @rs.projects.stats(@scope.projectId).then (stats) => @scope.stats = stats @@ -192,6 +207,7 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F @scope.stats.completedPercentage = 0 @scope.showGraphPlaceholder = !(stats.total_points? && stats.total_milestones?) + @.calculateForecasting() return stats setMilestonesOrder: (sprints) -> @@ -275,6 +291,7 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F promise = @rs.userstories.listUnassigned(@scope.projectId, params, pageSize) return promise.then (result) => + userstories = result[0] header = result[1] @@ -283,6 +300,8 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F # NOTE: Fix order of USs because the filter orderBy does not work propertly in the partials files @scope.userstories = @scope.userstories.concat(_.sortBy(userstories, "backlog_order")) + @scope.visibleUserStories = _.map @scope.userstories, (it) -> + return it.ref for it in @scope.userstories @.backlogOrder[it.id] = it.backlog_order @@ -305,31 +324,47 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F @.loadProjectStats(), @.loadSprints(), @.loadUserstories() - ]) + ]).then(@.calculateForecasting) + + calculateForecasting: -> + stats = @scope.stats + total_points = stats.total_points + current_sum = stats.assigned_points + backlog_points_sum = 0 + @forecastedStories = [] + + for us in @scope.userstories + current_sum += us.total_points + backlog_points_sum += us.total_points + @forecastedStories.push(us) + + if stats.speed > 0 && backlog_points_sum > stats.speed + break loadProject: -> - return @rs.projects.getBySlug(@params.pslug).then (project) => - if not project.is_backlog_activated - @errorHandlingService.permissionDenied() + project = @projectService.project.toJS() - @scope.projectId = project.id - @scope.project = project - @scope.closedMilestones = !!project.total_closed_milestones - @scope.$emit('project:loaded', project) - @scope.points = _.sortBy(project.points, "order") - @scope.pointsById = groupBy(project.points, (x) -> x.id) - @scope.usStatusById = groupBy(project.us_statuses, (x) -> x.id) - @scope.usStatusList = _.sortBy(project.us_statuses, "id") - return project + if not project.is_backlog_activated + @errorHandlingService.permissionDenied() + + @scope.projectId = project.id + @scope.project = project + @scope.closedMilestones = !!project.total_closed_milestones + @scope.$emit('project:loaded', project) + @scope.points = _.sortBy(project.points, "order") + @scope.pointsById = groupBy(project.points, (x) -> x.id) + @scope.usStatusById = groupBy(project.us_statuses, (x) -> x.id) + @scope.usStatusList = _.sortBy(project.us_statuses, "id") + + return project loadInitialData: -> - promise = @.loadProject() - promise.then (project) => - @.fillUsersAndRoles(project.members, project.roles) - @.initializeSubscription() + project = @.loadProject() - return promise - .then(=> @.loadBacklog()) + @.fillUsersAndRoles(project.members, project.roles) + @.initializeSubscription() + + return @.loadBacklog() .then(=> @.generateFilters()) .then(=> @scope.$emit("backlog:loaded")) @@ -545,7 +580,7 @@ module.controller("BacklogController", BacklogController) ## Backlog Directive ############################################################################# -BacklogDirective = ($repo, $rootscope, $translate) -> +BacklogDirective = ($repo, $rootscope, $translate, $rs) -> ## Doom line Link doomLineTemplate = _.template("""
<%- text %>
@@ -553,11 +588,13 @@ BacklogDirective = ($repo, $rootscope, $translate) -> linkDoomLine = ($scope, $el, $attrs, $ctrl) -> reloadDoomLine = -> - if $scope.stats? and $scope.stats.total_points? and $scope.stats.total_points != 0 + if $scope.displayVelocity + removeDoomlineDom() + + if $scope.stats? and $scope.stats.total_points? and $scope.stats.total_points != 0 and !$scope.displayVelocity? removeDoomlineDom() stats = $scope.stats - total_points = stats.total_points current_sum = stats.assigned_points @@ -584,6 +621,7 @@ BacklogDirective = ($repo, $rootscope, $translate) -> return _.map(rowElements, (x) -> angular.element(x)) $scope.$on("userstories:loaded", reloadDoomLine) + $scope.$on("userstories:forecast", removeDoomlineDom) $scope.$watch("stats", reloadDoomLine) ## Move to current sprint link @@ -614,9 +652,11 @@ BacklogDirective = ($repo, $rootscope, $translate) -> # Update the total of points sprint.total_points += totalExtraPoints - $repo.saveAll(selectedUss).then -> + $rs.userstories.bulkUpdateMilestone($scope.project.id, $scope.sprints[0].id, selectedUss).then => $ctrl.loadSprints() $ctrl.loadProjectStats() + $ctrl.toggleVelocityForecasting() + $ctrl.calculateForecasting() $el.find(".move-to-sprint").hide() @@ -626,6 +666,9 @@ BacklogDirective = ($repo, $rootscope, $translate) -> moveToLatestSprint = (selectedUss) -> moveUssToSprint(selectedUss, $scope.sprints[0]) + $scope.$on "sprintform:create:success:callback", (e, ussToMove) -> + _.partial(moveToCurrentSprint, ussToMove)() + shiftPressed = false lastChecked = null @@ -640,6 +683,7 @@ BacklogDirective = ($repo, $rootscope, $translate) -> else moveToSprintDom.hide() + $(window).on "keydown.shift-pressed keyup.shift-pressed", (event) -> shiftPressed = !!event.shiftKey @@ -685,6 +729,22 @@ BacklogDirective = ($repo, $rootscope, $translate) -> showHideTags($ctrl) + $el.on "click", ".forecasting-add-sprint", (event) -> + ussToMoveList = $ctrl.forecastedStories + if $scope.currentSprint + ussToMove = _.map ussToMoveList, (us, index) -> + us.milestone = $scope.currentSprint.id + us.order = index + return us + + $scope.$apply(_.partial(moveToCurrentSprint, ussToMove)) + else + ussToMove = _.map ussToMoveList, (us, index) -> + us.order = index + return us + + $rootscope.$broadcast("sprintform:create", $scope.projectId, ussToMove) + showHideTags = ($ctrl) -> elm = angular.element("#show-tags") @@ -759,7 +819,7 @@ BacklogDirective = ($repo, $rootscope, $translate) -> return {link: link} -module.directive("tgBacklog", ["$tgRepo", "$rootScope", "$translate", BacklogDirective]) +module.directive("tgBacklog", ["$tgRepo", "$rootScope", "$translate", "$tgResources", BacklogDirective]) ############################################################################# ## User story points directive diff --git a/app/coffee/modules/backlog/sortable.coffee b/app/coffee/modules/backlog/sortable.coffee index e5905b18..69272b2d 100644 --- a/app/coffee/modules/backlog/sortable.coffee +++ b/app/coffee/modules/backlog/sortable.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/backlog/sprints.coffee b/app/coffee/modules/backlog/sprints.coffee index 41cd56c0..a1d203fc 100644 --- a/app/coffee/modules/backlog/sprints.coffee +++ b/app/coffee/modules/backlog/sprints.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/base.coffee b/app/coffee/modules/base.coffee index 5cfa7dd4..ba8a3d40 100644 --- a/app/coffee/modules/base.coffee +++ b/app/coffee/modules/base.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -62,7 +62,12 @@ urls = { "cancel-account": "/cancel-account/:token" "register": "/register" "invitation": "/invitation/:token" - "create-project": "/create-project" + "create-project": "/project/new" + "create-project-scrum": "/project/new/scrum" + "create-project-kanban": "/project/new/kanban" + "create-project-duplicate": "/project/new/duplicate" + "create-project-import": "/project/new/import" + "create-project-import-platform": "/project/new/import/:platform" "profile": "/profile" "user-profile": "/profile/:username" diff --git a/app/coffee/modules/base/bind.coffee b/app/coffee/modules/base/bind.coffee index 91e6735c..6e82b08b 100644 --- a/app/coffee/modules/base/bind.coffee +++ b/app/coffee/modules/base/bind.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/base/conf.coffee b/app/coffee/modules/base/conf.coffee index 20f56387..b90f2e9a 100644 --- a/app/coffee/modules/base/conf.coffee +++ b/app/coffee/modules/base/conf.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/base/contrib.coffee b/app/coffee/modules/base/contrib.coffee index e8607fef..e0489a60 100644 --- a/app/coffee/modules/base/contrib.coffee +++ b/app/coffee/modules/base/contrib.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -32,25 +32,24 @@ class ContribController extends taiga.Controller "$routeParams", "$tgRepo", "$tgResources", - "$tgConfirm" + "$tgConfirm", + "tgProjectService" ] - constructor: (@rootScope, @scope, @params, @repo, @rs, @confirm) -> + constructor: (@rootScope, @scope, @params, @repo, @rs, @confirm, @projectService) -> @scope.currentPlugin = _.head(_.filter(@rootScope.adminPlugins, {"slug": @params.plugin})) @scope.projectSlug = @params.pslug - promise = @.loadInitialData() - - promise.then null, => - @confirm.notify("error") + @.loadInitialData() loadProject: -> - return @rs.projects.getBySlug(@params.pslug).then (project) => - @scope.projectId = project.id - @scope.project = project - @scope.$emit('project:loaded', project) - @scope.$broadcast('project:loaded', project) - return project + project = @projectService.project.toJS() + + @scope.projectId = project.id + @scope.project = project + @scope.$emit('project:loaded', project) + @scope.$broadcast('project:loaded', project) + return project loadInitialData: -> return @.loadProject() diff --git a/app/coffee/modules/base/filters.coffee b/app/coffee/modules/base/filters.coffee index 9b9acc2c..a4ce416b 100644 --- a/app/coffee/modules/base/filters.coffee +++ b/app/coffee/modules/base/filters.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/base/http.coffee b/app/coffee/modules/base/http.coffee index 57fa8e82..5be2ae43 100644 --- a/app/coffee/modules/base/http.coffee +++ b/app/coffee/modules/base/http.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/base/location.coffee b/app/coffee/modules/base/location.coffee index 8bfd9905..0747ace2 100644 --- a/app/coffee/modules/base/location.coffee +++ b/app/coffee/modules/base/location.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/base/model.coffee b/app/coffee/modules/base/model.coffee index 36f157be..ad3b7539 100644 --- a/app/coffee/modules/base/model.coffee +++ b/app/coffee/modules/base/model.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -39,7 +39,7 @@ class Model instance._modifiedAttrs = _.cloneDeep(@._modifiedAttrs) instance._isModified = _.cloneDeep(@._isModified) - return instance + return instance clone: -> instance = new Model(@._name, @._attrs, @._dataTypes) diff --git a/app/coffee/modules/base/navurls.coffee b/app/coffee/modules/base/navurls.coffee index 28fa20de..e62eefd4 100644 --- a/app/coffee/modules/base/navurls.coffee +++ b/app/coffee/modules/base/navurls.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/base/repository.coffee b/app/coffee/modules/base/repository.coffee index 290bed50..31c81152 100644 --- a/app/coffee/modules/base/repository.coffee +++ b/app/coffee/modules/base/repository.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/base/storage.coffee b/app/coffee/modules/base/storage.coffee index c8215712..7c03eae0 100644 --- a/app/coffee/modules/base/storage.coffee +++ b/app/coffee/modules/base/storage.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/base/urls.coffee b/app/coffee/modules/base/urls.coffee index e275390a..fef32c1f 100644 --- a/app/coffee/modules/base/urls.coffee +++ b/app/coffee/modules/base/urls.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/common.coffee b/app/coffee/modules/common.coffee index 5ab2fa50..11455fa6 100644 --- a/app/coffee/modules/common.coffee +++ b/app/coffee/modules/common.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -216,6 +216,9 @@ module.directive("tgToggleComment", ToggleCommentDirective) ProjectUrl = ($navurls) -> get = (project) -> + if project.toJS + project = project.toJS() + ctx = {project: project.slug} if project.is_backlog_activated and project.my_permissions.indexOf("view_us") > -1 @@ -353,12 +356,18 @@ module.directive("tgCapslock", [Capslock]) LightboxClose = () -> template = """ - + """ + link = (scope, elm, attrs) -> + return { + scope: { + onClose: '&' + }, + link: link, template: template } @@ -369,11 +378,7 @@ Svg = () -> {{svgTitle}} - + {{svgTitleTranslate | translate: svgTitleTranslateValues}} """ @@ -390,14 +395,22 @@ Svg = () -> module.directive("tgSvg", [Svg]) -Autofocus = ($timeout) -> +Autofocus = ($timeout, $parse, animationFrame) -> return { restrict: 'A', - link : ($scope, $element) -> - $timeout -> $element[0].focus() + link : ($scope, $element, attrs) -> + if attrs.ngShow + model = $parse(attrs.ngShow) + + $scope.$watch model, (value) -> + if value == true + $timeout () -> $element[0].focus() + + else + $timeout () -> $element[0].focus() } -module.directive('tgAutofocus', ['$timeout', Autofocus]) +module.directive('tgAutofocus', ['$timeout', '$parse', "animationFrame", Autofocus]) module.directive 'tgPreloadImage', () -> spinner = "loading..." diff --git a/app/coffee/modules/common/analytics.coffee b/app/coffee/modules/common/analytics.coffee index 02950003..1511a58c 100644 --- a/app/coffee/modules/common/analytics.coffee +++ b/app/coffee/modules/common/analytics.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/common/bind-scope.coffee b/app/coffee/modules/common/bind-scope.coffee index 29f7b4af..4e20020b 100644 --- a/app/coffee/modules/common/bind-scope.coffee +++ b/app/coffee/modules/common/bind-scope.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/common/compile-html.directive.coffee b/app/coffee/modules/common/compile-html.directive.coffee index 13f66e35..e2d0e835 100644 --- a/app/coffee/modules/common/compile-html.directive.coffee +++ b/app/coffee/modules/common/compile-html.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/common/components.coffee b/app/coffee/modules/common/components.coffee index 4a020dbc..cd341457 100644 --- a/app/coffee/modules/common/components.coffee +++ b/app/coffee/modules/common/components.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -496,40 +496,37 @@ DeleteButtonDirective = ($log, $repo, $confirm, $location, $template) -> module.directive("tgDeleteButton", ["$log", "$tgRepo", "$tgConfirm", "$tgLocation", "$tgTemplate", DeleteButtonDirective]) ############################################################################# -## Editable description directive +## Editable subject directive ############################################################################# -EditableDescriptionDirective = ($rootscope, $repo, $confirm, $compile, $loading, $selectedText, $modelTransform, $template, $translate) -> - template = $template.get("common/components/editable-description.html") - noDescriptionMegEditMode = $template.get("common/components/editable-description-msg-edit-mode.html") - noDescriptionMegReadMode = $template.get("common/components/editable-description-msg-read-mode.html") +EditableSubjectDirective = ($rootscope, $repo, $confirm, $loading, $modelTransform, $template) -> + template = $template.get("common/components/editable-subject.html") link = ($scope, $el, $attrs, $model) -> - $el.find('.edit-description').hide() - $el.find('.view-description .edit').hide() $scope.$on "object:updated", () -> - $el.find('.edit-description').hide() - $el.find('.view-description').show() + $el.find('.edit-subject').hide() + $el.find('.view-subject').show() isEditable = -> return $scope.project.my_permissions.indexOf($attrs.requiredPerm) != -1 - save = (description) -> + save = (subject) -> currentLoading = $loading() .target($el.find('.save-container')) .start() transform = $modelTransform.save (item) -> - item.description = description + + item.subject = subject return item - transform.then -> + transform.then => $confirm.notify("success") $rootscope.$broadcast("object:updated") - $el.find('.edit-description').hide() - $el.find('.view-description').show() + $el.find('.edit-subject').hide() + $el.find('.view-subject').show() transform.then null, -> $confirm.notify("error") @@ -537,60 +534,43 @@ EditableDescriptionDirective = ($rootscope, $repo, $confirm, $compile, $loading, transform.finally -> currentLoading.finish() - cancelEdition = () -> - $scope.item.revert() - $el.find('.edit-description').hide() - $el.find('.view-description').show() + return transform - $el.on "mouseup", ".view-description", (event) -> - # We want to dettect the a inside the div so we use the target and - # not the currentTarget - target = angular.element(event.target) + $el.click -> return if not isEditable() - return if target.is('a') - return if $selectedText.get().length - - $el.find('.edit-description').show() - $el.find('.view-description').hide() - $el.find('textarea').focus() - - $el.on "click", "a", (event) -> - target = angular.element(event.target) - href = target.attr('href') - if href.indexOf("#") == 0 - event.preventDefault() - $('body').scrollTop($(href).offset().top) + $el.find('.edit-subject').show() + $el.find('.view-subject').hide() + $el.find('input').focus() $el.on "click", ".save", (e) -> e.preventDefault() - description = $scope.item.description - save(description) + subject = $scope.item.subject + save(subject) - $el.on "keydown", "textarea", (event) -> - return if event.keyCode != 27 + $el.on "keyup", "input", (event) -> + if event.keyCode == 13 + subject = $scope.item.subject + save(subject) + else if event.keyCode == 27 + $scope.$apply () => $model.$modelValue.revert() - $scope.$applyAsync () -> - title = $translate.instant("COMMON.CONFIRM_CLOSE_EDIT_MODE_TITLE") - message = $translate.instant("COMMON.CONFIRM_CLOSE_EDIT_MODE_MESSAGE") - $confirm.ask(title, null, message).then (askResponse) -> - cancelEdition() - askResponse.finish() + $el.find('.edit-subject').hide() + $el.find('.view-subject').show() + + $el.find('.edit-subject').hide() $scope.$watch $attrs.ngModel, (value) -> return if not value - $scope.item = value - if isEditable() - $el.find('.view-description .edit').show() - $el.find('.view-description .us-content').addClass('editable') - $scope.noDescriptionMsg = $compile(noDescriptionMegEditMode)($scope) - else - $scope.noDescriptionMsg = $compile(noDescriptionMegReadMode)($scope) + + if not isEditable() + $el.find('.view-subject .edit').remove() $scope.$on "$destroy", -> $el.off() + return { link: link restrict: "EA" @@ -598,81 +578,8 @@ EditableDescriptionDirective = ($rootscope, $repo, $confirm, $compile, $loading, template: template } -module.directive("tgEditableDescription", [ - "$rootScope", - "$tgRepo", - "$tgConfirm", - "$compile", - "$tgLoading", - "$selectedText", - "$tgQueueModelTransformation", - "$tgTemplate", - "$translate", - EditableDescriptionDirective]) - - - -EditableWysiwyg = (attachmentsService, attachmentsFullService) -> - link = ($scope, $el, $attrs, $model) -> - - isInEditMode = -> - return $el.find('textarea').is(':visible') and $model.$modelValue.id - - - uploadFile = (file, type) -> - return if !attachmentsService.validate(file) - - return attachmentsFullService.addAttachment($model.$modelValue.project, $model.$modelValue.id, type, file).then (result) -> - if taiga.isImage(result.getIn(['file', 'name'])) - return '![' + result.getIn(['file', 'name']) + '](' + result.getIn(['file', 'url']) + ')' - else - return '[' + result.getIn(['file', 'name']) + '](' + result.getIn(['file', 'url']) + ')' - - $el.on 'dragover', (e) -> - textarea = $el.find('textarea').focus() - - return false - - $el.on 'drop', (e) -> - e.stopPropagation() - e.preventDefault() - - if isInEditMode() - dataTransfer = e.dataTransfer || (e.originalEvent && e.originalEvent.dataTransfer) - - textarea = $el.find('textarea') - - textarea.addClass('in-progress') - - type = $model.$modelValue['_name'] - - if type == "userstories" - type = "us" - else if type == "tasks" - type = "task" - else if type == "issues" - type = "issue" - else if type == "wiki" - type = "wiki_page" - - promises = _.map dataTransfer.files, (file) -> - return uploadFile(file, type) - - Promise.all(promises).then (result) -> - textarea = $el.find('textarea') - - $.markItUp({ replaceWith: result.join(' ') }) - - textarea.removeClass('in-progress') - - return { - link: link - restrict: "EA" - require: "ngModel" - } - -module.directive("tgEditableWysiwyg", ["tgAttachmentsService", "tgAttachmentsFullService", EditableWysiwyg]) - +module.directive("tgEditableSubject", ["$rootScope", "$tgRepo", "$tgConfirm", "$tgLoading", "$tgQueueModelTransformation", + "$tgTemplate", EditableSubjectDirective]) ############################################################################# ## Common list directives diff --git a/app/coffee/modules/common/confirm.coffee b/app/coffee/modules/common/confirm.coffee index 04e80a62..67227343 100644 --- a/app/coffee/modules/common/confirm.coffee +++ b/app/coffee/modules/common/confirm.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -207,13 +207,16 @@ class ConfirmService extends taiga.Service return defered.promise - loader: (title, message) -> + loader: (title, message, spin=false) -> el = angular.element(".lightbox-generic-loading") # Render content el.find(".title").html(title) if title el.find(".message").html(message) if message + if spin + el.find(".spin").removeClass("hidden") + return { start: => @lightboxService.open(el) stop: => @lightboxService.close(el) diff --git a/app/coffee/modules/common/custom-field-values.coffee b/app/coffee/modules/common/custom-field-values.coffee index b9808cbb..8a64ea95 100644 --- a/app/coffee/modules/common/custom-field-values.coffee +++ b/app/coffee/modules/common/custom-field-values.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -32,6 +32,7 @@ module = angular.module("taigaCommon") # Custom attributes types (see taiga-back/taiga/projects/custom_attributes/choices.py) TEXT_TYPE = "text" +RICHTEXT_TYPE = "url" MULTILINE_TYPE = "multiline" DATE_TYPE = "date" URL_TYPE = "url" @@ -53,6 +54,10 @@ TYPE_CHOICES = [ { key: URL_TYPE, name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_URL" + }, + { + key: RICHTEXT_TYPE, + name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_RICHTEXT" } ] @@ -193,6 +198,15 @@ CustomAttributeValueDirective = ($template, $selectedText, $compile, $translate, requiredEditionPerm = $attrs.requiredEditionPerm return permissions.indexOf(requiredEditionPerm) > -1 + $scope.saveCustomRichText = (markdown, callback) => + attributeValue.value = markdown + $ctrl.updateAttributeValue(attributeValue).then -> + callback() + render(attributeValue, false) + + $scope.cancelCustomRichText= () => + render(attributeValue, false) + submit = debounce 2000, (event) => event.preventDefault() @@ -214,6 +228,9 @@ CustomAttributeValueDirective = ($template, $selectedText, $compile, $translate, # Bootstrap attributeValue = $scope.$eval($attrs.tgCustomAttributeValue) + if attributeValue.value == null or attributeValue.value == undefined + attributeValue.value = "" + $scope.customAttributeValue = attributeValue render(attributeValue) ## Actions (on view mode) diff --git a/app/coffee/modules/common/estimation.coffee b/app/coffee/modules/common/estimation.coffee index ae108527..a0da4f41 100644 --- a/app/coffee/modules/common/estimation.coffee +++ b/app/coffee/modules/common/estimation.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/common/filters.coffee b/app/coffee/modules/common/filters.coffee index c232d85d..854f1a61 100644 --- a/app/coffee/modules/common/filters.coffee +++ b/app/coffee/modules/common/filters.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -75,7 +75,6 @@ sizeFormat = => module.filter("sizeFormat", sizeFormat) - toMutableFilter = -> toMutable = (js) -> return js.toJS() @@ -127,3 +126,20 @@ darkerFilter = -> module.filter("darker", darkerFilter) + +markdownToHTML = (wysiwigService) -> + return (input) -> + if input + return wysiwigService.getHTML(input) + + return "" + +module.filter("markdownToHTML", ["tgWysiwygService", markdownToHTML]) + +inArray = ($filter) -> + return (list, arrayFilter, element) -> + if arrayFilter + filter = $filter("filter") + return filter list, (listItem) -> + return arrayFilter.indexOf(listItem[element]) != -1 +module.filter("inArray", ["$filter", inArray]) diff --git a/app/coffee/modules/common/importer.coffee b/app/coffee/modules/common/importer.coffee deleted file mode 100644 index 4ff587c1..00000000 --- a/app/coffee/modules/common/importer.coffee +++ /dev/null @@ -1,153 +0,0 @@ -### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -# File: modules/common/importer.coffee -### - -module = angular.module("taigaCommon") - - -ImportProjectButtonDirective = ($rs, $confirm, $location, $navUrls, $translate, $lightboxFactory, currentUserService, $tgAuth) -> - link = ($scope, $el, $attrs) -> - getRestrictionError = (result) -> - if result.headers - errorKey = '' - - user = currentUserService.getUser() - maxMemberships = 0 - - if result.headers.isPrivate - privateError = !currentUserService.canCreatePrivateProjects().valid - maxMemberships = null - - if user.get('max_memberships_private_projects') != null && result.headers.memberships >= user.get('max_memberships_private_projects') - membersError = true - else - membersError = false - - if privateError && membersError - errorKey = 'private-space-members' - maxMemberships = user.get('max_memberships_private_projects') - else if privateError - errorKey = 'private-space' - else if membersError - errorKey = 'private-members' - maxMemberships = user.get('max_memberships_private_projects') - - else - publicError = !currentUserService.canCreatePublicProjects().valid - - if user.get('max_memberships_public_projects') != null && result.headers.memberships >= user.get('max_memberships_public_projects') - membersError = true - else - membersError = false - - if publicError && membersError - errorKey = 'public-space-members' - maxMemberships = user.get('max_memberships_public_projects') - else if publicError - errorKey = 'public-space' - else if membersError - errorKey = 'public-members' - maxMemberships = user.get('max_memberships_public_projects') - - return { - key: errorKey, - values: { - max_memberships: maxMemberships, - members: result.headers.memberships - } - } - else - return false - - $el.on "click", ".import-project-button", (event) -> - event.preventDefault() - $el.find("input.import-file").val("") - $el.find("input.import-file").trigger("click") - - $el.on "change", "input.import-file", (event) -> - event.preventDefault() - file = event.target.files[0] - return if not file - - loader = $confirm.loader($translate.instant("PROJECT.IMPORT.UPLOADING_FILE")) - - onSuccess = (result) -> - currentUserService.loadProjects().then () -> - loader.stop() - - if result.status == 202 # Async mode - title = $translate.instant("PROJECT.IMPORT.ASYNC_IN_PROGRESS_TITLE") - message = $translate.instant("PROJECT.IMPORT.ASYNC_IN_PROGRESS_MESSAGE") - $confirm.success(title, message) - - else # result.status == 201 # Sync mode - ctx = {project: result.data.slug} - $location.path($navUrls.resolve("project-admin-project-profile-details", ctx)) - msg = $translate.instant("PROJECT.IMPORT.SYNC_SUCCESS") - $confirm.notify("success", msg) - - onError = (result) -> - $tgAuth.refresh().then () -> - restrictionError = getRestrictionError(result) - - loader.stop() - - if restrictionError - $lightboxFactory.create('tg-lb-import-error', { - class: 'lightbox lightbox-import-error' - }, restrictionError) - - else - errorMsg = $translate.instant("PROJECT.IMPORT.ERROR") - - if result.status == 429 # TOO MANY REQUESTS - errorMsg = $translate.instant("PROJECT.IMPORT.ERROR_TOO_MANY_REQUEST") - else if result.data?._error_message - errorMsg = $translate.instant("PROJECT.IMPORT.ERROR_MESSAGE", {error_message: result.data._error_message}) - $confirm.notify("error", errorMsg) - - loader.start() - $rs.projects.import(file, loader.update).then(onSuccess, onError) - - return {link: link} - -module.directive("tgImportProjectButton", -["$tgResources", "$tgConfirm", "$location", "$tgNavUrls", "$translate", "tgLightboxFactory", "tgCurrentUserService", "$tgAuth", - ImportProjectButtonDirective]) - -LbImportErrorDirective = (lightboxService) -> - link = (scope, el, attrs) -> - lightboxService.open(el) - - scope.close = () -> - lightboxService.close(el) - return - - return { - templateUrl: "common/lightbox/lightbox-import-error.html", - link: link - } - -LbImportErrorDirective.$inject = ["lightboxService"] - -module.directive("tgLbImportError", LbImportErrorDirective) diff --git a/app/coffee/modules/common/lightboxes.coffee b/app/coffee/modules/common/lightboxes.coffee index e8e6c862..17fe81bd 100644 --- a/app/coffee/modules/common/lightboxes.coffee +++ b/app/coffee/modules/common/lightboxes.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -38,7 +38,7 @@ trim = @.taiga.trim class LightboxService extends taiga.Service constructor: (@animationFrame, @q, @rootScope) -> - open: ($el, onClose) -> + open: ($el, onClose, onEsc) -> @.onClose = onClose if _.isString($el) @@ -68,7 +68,12 @@ class LightboxService extends taiga.Service docEl = angular.element(document) docEl.on "keydown.lightbox", (e) => code = if e.keyCode then e.keyCode else e.which - @.close($el) if code == 27 + if code == 27 + if onEsc + @rootScope.$applyAsync(onEsc) + else + @.close($el) + return defered.promise @@ -171,9 +176,11 @@ module.service("lightboxKeyboardNavigationService", LightboxKeyboardNavigationSe LightboxDirective = (lightboxService) -> link = ($scope, $el, $attrs) -> - $el.on "click", ".close", (event) -> - event.preventDefault() - lightboxService.close($el) + + if !$attrs.$attr.visible + $el.on "click", ".close", (event) -> + event.preventDefault() + lightboxService.close($el) return {restrict: "C", link: link} @@ -308,6 +315,9 @@ CreateEditUserstoryDirective = ($repo, $model, $rs, $rootScope, lightboxService, attachmentsToAdd = attachmentsToAdd.push(attachment) $scope.deleteAttachment = (attachment) -> + attachmentsToAdd = attachmentsToAdd.filter (it) -> + return it.get('name') != attachment.get('name') + if attachment.get("id") attachmentsToDelete = attachmentsToDelete.push(attachment) @@ -332,7 +342,7 @@ CreateEditUserstoryDirective = ($repo, $model, $rs, $rootScope, lightboxService, inserted = _.find itemtags, (it) -> it[0] == value if !inserted - itemtags.push([tag , color]) + itemtags.push([value , color]) $scope.us.tags = itemtags $scope.deleteTag = (tag) -> @@ -610,7 +620,7 @@ AssignedToLightboxDirective = (lightboxService, lightboxKeyboardNavigationServic ctx = { selected: selected users: _.slice(users, 0, 5) - showMore: visibleUsers + showMore: users.length > 5 } html = usersTemplate(ctx) diff --git a/app/coffee/modules/common/loader.coffee b/app/coffee/modules/common/loader.coffee index 80253c91..fa28eacd 100644 --- a/app/coffee/modules/common/loader.coffee +++ b/app/coffee/modules/common/loader.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -92,15 +92,16 @@ Loader = ($rootscope) -> return { pageLoaded: pageLoaded + open: () -> open start: (auto=false) -> if !open start() autoClose() if auto onStart: (fn) -> - $rootscope.$on("loader:start", fn) + return $rootscope.$on("loader:start", fn) onEnd: (fn) -> - $rootscope.$on("loader:end", fn) + return $rootscope.$on("loader:end", fn) logRequest: () -> requestCount++ diff --git a/app/coffee/modules/common/loading.coffee b/app/coffee/modules/common/loading.coffee index 5ee375e2..2e8bcb1e 100644 --- a/app/coffee/modules/common/loading.coffee +++ b/app/coffee/modules/common/loading.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/common/popovers.coffee b/app/coffee/modules/common/popovers.coffee index 1dd724e6..f8e60d3d 100644 --- a/app/coffee/modules/common/popovers.coffee +++ b/app/coffee/modules/common/popovers.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/common/raven-logger.coffee b/app/coffee/modules/common/raven-logger.coffee index c6ca9077..393a936a 100644 --- a/app/coffee/modules/common/raven-logger.coffee +++ b/app/coffee/modules/common/raven-logger.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/common/tags.coffee b/app/coffee/modules/common/tags.coffee index 377b795e..88beddeb 100644 --- a/app/coffee/modules/common/tags.coffee +++ b/app/coffee/modules/common/tags.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/common/wisiwyg.coffee b/app/coffee/modules/common/wisiwyg.coffee deleted file mode 100644 index a889042b..00000000 --- a/app/coffee/modules/common/wisiwyg.coffee +++ /dev/null @@ -1,489 +0,0 @@ -### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -# File: modules/common/wisiwyg.coffee -### - -taiga = @.taiga -bindOnce = @.taiga.bindOnce - -module = angular.module("taigaCommon") - -# How to test lists (-, *, 1.) -# test it with text after & before the list -# + is the cursor position - -# CASE 1 -# - aa+ -# --> enter -# - aa -# - + - -# CASE 1 -# - + -# --> enter - -# + - -# CASE 3 -# - bb+cc -# --> enter -# - bb -# - cc - -# CASE 3 -# +- aa -# --> enter - -# - aa - -############################################################################# -## WYSIWYG markitup editor directive -############################################################################# -MarkitupDirective = ($rootscope, $rs, $selectedText, $template, $compile, $translate, projectService) -> - previewTemplate = $template.get("common/wysiwyg/wysiwyg-markitup-preview.html", true) - - link = ($scope, $el, $attrs, $model) -> - if not $scope.project - # for backward compatibility - $scope.project = projectService.project.toJS() - - element = angular.element($el) - previewDomNode = $("
", {class: "preview"}) - - closePreviewMode = -> - element.parents(".markdown").find(".preview").remove() - element.parents(".markItUp").show() - - $scope.$on "markdown-editor:submit", -> - closePreviewMode() - - cancelablePromise = null - previewInProgress = false - - preview = -> - return if previewInProgress - - previewInProgress = true - - markdownDomNode = element.parents(".markdown") - markItUpDomNode = element.parents(".markItUp") - - $rs.mdrender.render($scope.project.id, $model.$modelValue).then (data) -> - html = previewTemplate({data: data.data}) - html = $compile(html)($scope) - - markdownDomNode.append(html) - markItUpDomNode.hide() - - previewInProgress = false - - markdown = element.closest(".markdown") - - markdown.on "mouseup.preview", ".preview", (event) -> - event.preventDefault() - target = angular.element(event.target) - - if !target.is('a') and $selectedText.get().length - return - - markdown.off(".preview") - closePreviewMode() - - setCaretPosition = (textarea, caretPosition) -> - if textarea.createTextRange - range = textarea.createTextRange() - range.move("character", caretPosition) - range.select() - - else if textarea.selectionStart - textarea.focus() - textarea.setSelectionRange(caretPosition, caretPosition) - - # Calculate the scroll position - totalLines = textarea.value.split("\n").length - line = textarea.value[0..(caretPosition - 1)].split("\n").length - scrollRelation = line / totalLines - $el.scrollTop((scrollRelation * $el[0].scrollHeight) - ($el.height() / 2)) - - addLine = (textarea, nline, replace) -> - lines = textarea.value.split("\n") - - if replace - lines[nline] = replace + lines[nline] - else - lines[nline] = "" - - cursorPosition = 0 - - for line, key in lines - cursorPosition += line.length + 1 || 1 - - break if key == nline - - textarea.value = lines.join("\n") - - #return the new position - if replace - return cursorPosition - lines[nline].length + replace.length - 1 - else - return cursorPosition - - prepareUrlFormatting = (markItUp) -> - regex = /(<<<|>>>)/gi - result = 0 - indices = [] - (indices.push(result.index)) while ( (result = regex.exec(markItUp.textarea.value)) ) - markItUp.donotparse = indices - - urlFormatting = (markItUp) -> - regex = /<<>>/gi - endIndex = 0 - loop - result = regex.exec(markItUp.textarea.value) - break if !result - if result.index not in markItUp.donotparse - endIndex = result.index - break - - value = markItUp.textarea.value - url = value.substring(startIndex, endIndex).replace('<<<', '').replace('>>>', '') - url = url.replace('(', '%28').replace(')', '%29') - url = url.replace('[', '%5B').replace(']', '%5D') - value = value.substring(0, startIndex) + url + value.substring(endIndex+3, value.length) - markItUp.textarea.value = value - markItUp.donotparse = undefined - - markdownTitle = (markItUp, char) -> - heading = "" - n = $.trim(markItUp.selection or markItUp.placeHolder).length - - for i in [0..n-1] - heading += char - - return "\n"+heading+"\n" - - renderMarkItUp = () -> - markdownSettings = - nameSpace: "markdown" - onShiftEnter: {keepDefault:false, openWith:"\n\n"} - onEnter: - keepDefault: false, - replaceWith: () -> - # Allow textcomplete to intercept the enter key if the options list is displayed - # @todo There doesn't seem to be a more graceful way to do this with the textcomplete API. - if not $('.textcomplete-dropdown').is(':visible') - "\n" - afterInsert: (data) -> - lines = data.textarea.value.split("\n") - # Detect if we are in this situation +- aa at the beginning if the textarea - if data.caretPosition > 0 - cursorLine = data.textarea.value[0..(data.caretPosition - 1)].split("\n").length - else - cursorLine = 1 - - newLineContent = data.textarea.value[data.caretPosition..].split("\n")[0] - lastLine = lines[cursorLine - 1] - - # unordered list - - match = lastLine.match /^(\s*- ).*/ - - if match - emptyListItem = lastLine.match /^(\s*)\-\s$/ - - if emptyListItem - nline = cursorLine - 1 - replace = null - else - nline = cursorLine - replace = "#{match[1]}" - - markdownCaretPositon = addLine(data.textarea, nline, replace) - - # unordered list * - match = lastLine.match /^(\s*\* ).*/ - - if match - emptyListItem = lastLine.match /^(\s*\* )$/ - - if emptyListItem - nline = cursorLine - 1 - replace = null - else - nline = cursorLine - replace = "#{match[1]}" - - markdownCaretPositon = addLine(data.textarea, nline, replace) - - # ordered list - match = lastLine.match /^(\s*)(\d+)\.\s/ - - if match - emptyListItem = lastLine.match /^(\s*)(\d+)\.\s$/ - - if emptyListItem - nline = cursorLine - 1 - replace = null - else - nline = cursorLine - replace = "#{match[1] + (parseInt(match[2], 10) + 1)}. " - - markdownCaretPositon = addLine(data.textarea, nline, replace) - - setCaretPosition(data.textarea, markdownCaretPositon) if markdownCaretPositon - - markupSet: [ - { - name: $translate.instant("COMMON.WYSIWYG.H1_BUTTON") - key: "1" - placeHolder: $translate.instant("COMMON.WYSIWYG.H1_SAMPLE_TEXT") - closeWith: (markItUp) -> markdownTitle(markItUp, "=") - }, - { - name: $translate.instant("COMMON.WYSIWYG.H2_BUTTON") - key: "2" - placeHolder: $translate.instant("COMMON.WYSIWYG.H2_SAMPLE_TEXT") - closeWith: (markItUp) -> markdownTitle(markItUp, "-") - }, - { - name: $translate.instant("COMMON.WYSIWYG.H3_BUTTON") - key: "3" - openWith: "### " - placeHolder: $translate.instant("COMMON.WYSIWYG.H3_SAMPLE_TEXT") - }, - { - separator: "---------------" - }, - { - name: $translate.instant("COMMON.WYSIWYG.BOLD_BUTTON") - key: "B" - openWith: "**" - closeWith: "**" - placeHolder: $translate.instant("COMMON.WYSIWYG.BOLD_BUTTON_SAMPLE_TEXT") - }, - { - name: $translate.instant("COMMON.WYSIWYG.ITALIC_SAMPLE_TEXT") - key: "I" - openWith: "_" - closeWith: "_" - placeHolder: $translate.instant("COMMON.WYSIWYG.ITALIC_SAMPLE_TEXT") - }, - { - name: $translate.instant("COMMON.WYSIWYG.STRIKE_BUTTON") - key: "S" - openWith: "~~" - closeWith: "~~" - placeHolder: $translate.instant("COMMON.WYSIWYG.STRIKE_SAMPLE_TEXT") - }, - { - separator: "---------------" - }, - { - name: $translate.instant("COMMON.WYSIWYG.BULLETED_LIST_BUTTON") - openWith: "- " - placeHolder: $translate.instant("COMMON.WYSIWYG.BULLETED_LIST_SAMPLE_TEXT") - }, - { - name: $translate.instant("COMMON.WYSIWYG.NUMERIC_LIST_BUTTON") - openWith: (markItUp) -> markItUp.line+". " - placeHolder: $translate.instant("COMMON.WYSIWYG.NUMERIC_LIST_SAMPLE_TEXT") - }, - { - separator: "---------------" - }, - { - name: $translate.instant("COMMON.WYSIWYG.PICTURE_BUTTON") - key: "P" - openWith: "![" - closeWith: '](<<<[![Url:!:http://]!]>>> "[![Title]!]")' - placeHolder: $translate.instant("COMMON.WYSIWYG.PICTURE_SAMPLE_TEXT") - beforeInsert:(markItUp) -> prepareUrlFormatting(markItUp) - afterInsert:(markItUp) -> urlFormatting(markItUp) - }, - { - name: $translate.instant("COMMON.WYSIWYG.LINK_BUTTON") - key: "L" - openWith: "[" - closeWith: '](<<<[![Url:!:http://]!]>>> "[![Title]!]")' - placeHolder: $translate.instant("COMMON.WYSIWYG.LINK_SAMPLE_TEXT") - beforeInsert:(markItUp) -> prepareUrlFormatting(markItUp) - afterInsert:(markItUp) -> urlFormatting(markItUp) - }, - { - separator: "---------------" - }, - { - name: $translate.instant("COMMON.WYSIWYG.QUOTE_BLOCK_BUTTON") - openWith: "> " - placeHolder: $translate.instant("COMMON.WYSIWYG.QUOTE_BLOCK_SAMPLE_TEXT") - }, - { - name: $translate.instant("COMMON.WYSIWYG.CODE_BLOCK_BUTTON") - openWith: "```\n" - placeHolder: $translate.instant("COMMON.WYSIWYG.CODE_BLOCK_SAMPLE_TEXT") - closeWith: "\n```" - }, - { - separator: "---------------" - }, - { - name: $translate.instant("COMMON.WYSIWYG.PREVIEW_BUTTON") - call: preview - className: "preview-icon" - }, - ] - afterInsert: (event) -> - target = angular.element(event.textarea) - $model.$setViewValue(target.val()) - - element - .markItUpRemove() - .markItUp(markdownSettings) - .textcomplete([ - # us, task, and issue autocomplete: #id or # - { - cache: true - match: /(^|\s)#([a-z0-9]+)$/i, - search: (term, callback) -> - term = taiga.slugify(term) - - searchTypes = ['issues', 'tasks', 'userstories', 'epics'] - searchProps = ['ref', 'subject'] - - filter = (item) => - for prop in searchProps - if taiga.slugify(item[prop]).indexOf(term) >= 0 - return true - return false - - cancelablePromise.abort() if cancelablePromise - cancelablePromise = $rs.search.do($scope.project.id, term) - - cancelablePromise.then (res) => - # ignore wikipages if they're the only results. can't exclude them in search - if res.count < 1 or res.count == res.wikipages.length - callback([]) - - else - for type in searchTypes - if res[type] and res[type].length > 0 - callback(res[type].filter(filter), true) - - # must signal end of lists - callback([]) - - replace: (res) -> - return "$1\##{res.ref} " - - template: (res, term) -> - return "\##{res.ref} - #{res.subject}" - } - - # username autocomplete: @username or @ - { - cache: true - match: /(^|\s)@([a-z0-9\-\._]{2,})$/i - search: (term, callback) -> - username = taiga.slugify(term) - searchProps = ['username', 'full_name', 'full_name_display'] - - if $scope.project.members.length < 1 - callback([]) - - else - callback $scope.project.members.filter (user) => - for prop in searchProps - if taiga.slugify(user[prop]).indexOf(username) >= 0 - return true - return false - - replace: (user) -> - return "$1@#{user.username} " - - template: (user) -> - return "#{user.username} - #{user.full_name_display}" - } - - # wiki pages autocomplete: [[slug or [[ - # if the search function was called with the 3rd param the regex - # like the docs claim, we could combine this with the #123 search - { - cache: true - match: /(^|\s)\[\[([a-z0-9\-]+)$/i - search: (term, callback) -> - term = taiga.slugify(term) - - $rs.search.do($scope.project.id, term).then (res) => - if res.count < 1 - callback([]) - - if res.count < 1 or not res.wikipages or res.wikipages.length <= 0 - callback([]) - - else - callback res.wikipages.filter((page) => - return taiga.slugify(page['slug']).indexOf(term) >= 0 - ), true - - # must signal end of lists - callback([]) - - - replace: (res) -> - return "$1[[#{res.slug}]]" - - template: (res, term) -> - return res.slug - } - ], - { - debounce: 200 - } - ) - - renderMarkItUp() - - unbind = $rootscope.$on "$translateChangeEnd", renderMarkItUp - - element.on "keypress", (event) -> - $scope.$apply() - - $scope.$on "$destroy", -> - $el.off() - unbind() - - return {link:link, require:"ngModel"} - -module.directive("tgMarkitup", ["$rootScope", "$tgResources", "$selectedText", "$tgTemplate", "$compile", - "$translate", "tgProjectService", MarkitupDirective]) diff --git a/app/coffee/modules/controllerMixins.coffee b/app/coffee/modules/controllerMixins.coffee index e383f20d..5c128845 100644 --- a/app/coffee/modules/controllerMixins.coffee +++ b/app/coffee/modules/controllerMixins.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/epics.coffee b/app/coffee/modules/epics.coffee index 743e70d4..1cc3a6f1 100644 --- a/app/coffee/modules/epics.coffee +++ b/app/coffee/modules/epics.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/epics/detail.coffee b/app/coffee/modules/epics/detail.coffee index f5a35849..616c1aa8 100644 --- a/app/coffee/modules/epics/detail.coffee +++ b/app/coffee/modules/epics/detail.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -54,11 +54,12 @@ class EpicDetailController extends mixOf(taiga.Controller, taiga.PageMixin) "$tgNavUrls", "$translate", "$tgQueueModelTransformation", - "tgErrorHandlingService" + "tgErrorHandlingService", + "tgProjectService" ] constructor: (@scope, @rootscope, @repo, @confirm, @rs, @rs2, @params, @q, @location, - @log, @appMetaService, @analytics, @navUrls, @translate, @modelTransform, @errorHandlingService) -> + @log, @appMetaService, @analytics, @navUrls, @translate, @modelTransform, @errorHandlingService, @projectService) -> bindMethods(@) @scope.epicRef = @params.epicref @@ -102,14 +103,15 @@ class EpicDetailController extends mixOf(taiga.Controller, taiga.PageMixin) @scope.onDeleteGoToUrl = @navUrls.resolve("project-epics", ctx) loadProject: -> - return @rs.projects.getBySlug(@params.pslug).then (project) => - @scope.projectId = project.id - @scope.project = project - @scope.immutableProject = Immutable.fromJS(project._attrs) - @scope.$emit('project:loaded', project) - @scope.statusList = project.epic_statuses - @scope.statusById = groupBy(project.epic_statuses, (x) -> x.id) - return project + project = @projectService.project.toJS() + + @scope.projectId = project.id + @scope.project = project + @scope.immutableProject = @projectService.project + @scope.$emit('project:loaded', project) + @scope.statusList = project.epic_statuses + @scope.statusById = groupBy(project.epic_statuses, (x) -> x.id) + return project loadEpic: -> return @rs.epics.getByRef(@scope.projectId, @params.epicref).then (epic) => @@ -139,10 +141,10 @@ class EpicDetailController extends mixOf(taiga.Controller, taiga.PageMixin) @scope.userstories = data loadInitialData: -> - promise = @.loadProject() - return promise.then (project) => - @.fillUsersAndRoles(project.members, project.roles) - @.loadEpic().then(=> @.loadUserstories()) + project = @.loadProject() + + @.fillUsersAndRoles(project.members, project.roles) + @.loadEpic().then(=> @.loadUserstories()) ### # Note: This methods (onUpvote() and onDownvote()) are related to tg-vote-button. diff --git a/app/coffee/modules/events.coffee b/app/coffee/modules/events.coffee index e492fb36..1d5bd943 100644 --- a/app/coffee/modules/events.coffee +++ b/app/coffee/modules/events.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/feedback.coffee b/app/coffee/modules/feedback.coffee index 7cfabd75..b7adfb21 100644 --- a/app/coffee/modules/feedback.coffee +++ b/app/coffee/modules/feedback.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/integrations.coffee b/app/coffee/modules/integrations.coffee index 7392054e..214d30e7 100644 --- a/app/coffee/modules/integrations.coffee +++ b/app/coffee/modules/integrations.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/issues.coffee b/app/coffee/modules/issues.coffee index 9399ca8e..0792a136 100644 --- a/app/coffee/modules/issues.coffee +++ b/app/coffee/modules/issues.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/issues/detail.coffee b/app/coffee/modules/issues/detail.coffee index bb65f413..f74333e0 100644 --- a/app/coffee/modules/issues/detail.coffee +++ b/app/coffee/modules/issues/detail.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -53,11 +53,12 @@ class IssueDetailController extends mixOf(taiga.Controller, taiga.PageMixin) "$tgNavUrls", "$translate", "$tgQueueModelTransformation", - "tgErrorHandlingService" + "tgErrorHandlingService", + "tgProjectService" ] constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, - @log, @appMetaService, @analytics, @navUrls, @translate, @modelTransform, @errorHandlingService) -> + @log, @appMetaService, @analytics, @navUrls, @translate, @modelTransform, @errorHandlingService, @projectService) -> bindMethods(@) @scope.issueRef = @params.issueref @@ -112,19 +113,20 @@ class IssueDetailController extends mixOf(taiga.Controller, taiga.PageMixin) @scope.onDeleteGoToUrl = @navUrls.resolve("project", ctx) loadProject: -> - return @rs.projects.getBySlug(@params.pslug).then (project) => - @scope.projectId = project.id - @scope.project = project - @scope.$emit('project:loaded', project) - @scope.statusList = project.issue_statuses - @scope.statusById = groupBy(project.issue_statuses, (x) -> x.id) - @scope.typeById = groupBy(project.issue_types, (x) -> x.id) - @scope.typeList = _.sortBy(project.issue_types, "order") - @scope.severityList = project.severities - @scope.severityById = groupBy(project.severities, (x) -> x.id) - @scope.priorityList = project.priorities - @scope.priorityById = groupBy(project.priorities, (x) -> x.id) - return project + project = @projectService.project.toJS() + + @scope.projectId = project.id + @scope.project = project + @scope.$emit('project:loaded', project) + @scope.statusList = project.issue_statuses + @scope.statusById = groupBy(project.issue_statuses, (x) -> x.id) + @scope.typeById = groupBy(project.issue_types, (x) -> x.id) + @scope.typeList = _.sortBy(project.issue_types, "order") + @scope.severityList = project.severities + @scope.severityById = groupBy(project.severities, (x) -> x.id) + @scope.priorityList = project.priorities + @scope.priorityById = groupBy(project.priorities, (x) -> x.id) + return project loadIssue: -> return @rs.issues.getByRef(@scope.projectId, @params.issueref).then (issue) => @@ -149,10 +151,11 @@ class IssueDetailController extends mixOf(taiga.Controller, taiga.PageMixin) @scope.nextUrl = @navUrls.resolve("project-issues-detail", ctx) loadInitialData: -> - promise = @.loadProject() - return promise.then (project) => - @.fillUsersAndRoles(project.members, project.roles) - @.loadIssue() + project = @.loadProject() + + @.fillUsersAndRoles(project.members, project.roles) + + return @.loadIssue() ### # Note: This methods (onUpvote() and onDownvote()) are related to tg-vote-button. diff --git a/app/coffee/modules/issues/lightboxes.coffee b/app/coffee/modules/issues/lightboxes.coffee index 312c3add..b8d57df3 100644 --- a/app/coffee/modules/issues/lightboxes.coffee +++ b/app/coffee/modules/issues/lightboxes.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -78,6 +78,10 @@ CreateIssueDirective = ($repo, $confirm, $rootscope, lightboxService, $loading, $scope.addAttachment = (attachment) -> attachmentsToAdd = attachmentsToAdd.push(attachment) + $scope.deleteAttachment = (attachment) -> + attachmentsToAdd = attachmentsToAdd.filter (it) -> + return it.get('name') != attachment.get('name') + $scope.addTag = (tag, color) -> value = trim(tag.toLowerCase()) diff --git a/app/coffee/modules/issues/list.coffee b/app/coffee/modules/issues/list.coffee index 433c8543..f4c1c565 100644 --- a/app/coffee/modules/issues/list.coffee +++ b/app/coffee/modules/issues/list.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -58,14 +58,16 @@ class IssuesController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi "$translate", "tgErrorHandlingService", "$tgStorage", - "tgFilterRemoteStorageService" + "tgFilterRemoteStorageService", + "tgProjectService", + "tgUserActivityService" ] filtersHashSuffix: "issues-filters" myFiltersHashSuffix: "issues-my-filters" constructor: (@scope, @rootscope, @repo, @confirm, @rs, @urls, @params, @q, @location, @appMetaService, - @navUrls, @events, @analytics, @translate, @errorHandlingService, @storage, @filterRemoteStorageService) -> + @navUrls, @events, @analytics, @translate, @errorHandlingService, @storage, @filterRemoteStorageService, @projectService) -> bindMethods(@) @scope.sectionName = "Issues" @@ -286,24 +288,25 @@ class IssuesController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi loadProject: -> - return @rs.projects.getBySlug(@params.pslug).then (project) => - if not project.is_issues_activated - @errorHandlingService.permissionDenied() + project = @projectService.project.toJS() - @scope.projectId = project.id - @scope.project = project - @scope.$emit('project:loaded', project) + if not project.is_issues_activated + @errorHandlingService.permissionDenied() - @scope.issueStatusById = groupBy(project.issue_statuses, (x) -> x.id) - @scope.issueStatusList = _.sortBy(project.issue_statuses, "order") - @scope.severityById = groupBy(project.severities, (x) -> x.id) - @scope.severityList = _.sortBy(project.severities, "order") - @scope.priorityById = groupBy(project.priorities, (x) -> x.id) - @scope.priorityList = _.sortBy(project.priorities, "order") - @scope.issueTypes = _.sortBy(project.issue_types, "order") - @scope.issueTypeById = groupBy(project.issue_types, (x) -> x.id) + @scope.projectId = project.id + @scope.project = project + @scope.$emit('project:loaded', project) - return project + @scope.issueStatusById = groupBy(project.issue_statuses, (x) -> x.id) + @scope.issueStatusList = _.sortBy(project.issue_statuses, "order") + @scope.severityById = groupBy(project.severities, (x) -> x.id) + @scope.severityList = _.sortBy(project.severities, "order") + @scope.priorityById = groupBy(project.priorities, (x) -> x.id) + @scope.priorityList = _.sortBy(project.priorities, "order") + @scope.issueTypes = _.sortBy(project.issue_types, "order") + @scope.issueTypeById = groupBy(project.issue_types, (x) -> x.id) + + return project # We need to guarantee that the last petition done here is the finally used # When searching by text loadIssues can be called fastly with different parameters and @@ -328,13 +331,13 @@ class IssuesController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi return promise loadInitialData: -> - promise = @.loadProject() - return promise.then (project) => - @.fillUsersAndRoles(project.members, project.roles) - @.initializeSubscription() - @.generateFilters() + project = @.loadProject() - return @.loadIssues() + @.fillUsersAndRoles(project.members, project.roles) + @.initializeSubscription() + @.generateFilters() + + return @.loadIssues() # Functions used from templates addNewIssue: -> @@ -482,7 +485,10 @@ IssuesDirective = ($log, $location, $template, $compile) -> currentOrder = $ctrl.getOrderBy() newOrder = target.data("fieldname") - finalOrder = if currentOrder == newOrder then "-#{newOrder}" else newOrder + if newOrder == 'total_voters' + finalOrder = if currentOrder == newOrder then newOrder else "-#{newOrder}" + else + finalOrder = if currentOrder == newOrder then "-#{newOrder}" else newOrder $scope.$apply -> $ctrl.replaceFilter("order_by", finalOrder) diff --git a/app/coffee/modules/kanban.coffee b/app/coffee/modules/kanban.coffee index 0f0f48f3..c18606a5 100644 --- a/app/coffee/modules/kanban.coffee +++ b/app/coffee/modules/kanban.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/kanban/kanban-usertories.coffee b/app/coffee/modules/kanban/kanban-usertories.coffee index dc1faf82..dc699c43 100644 --- a/app/coffee/modules/kanban/kanban-usertories.coffee +++ b/app/coffee/modules/kanban/kanban-usertories.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -170,9 +170,14 @@ class KanbanUserstoriesService extends taiga.Service userstories = @.userstoriesRaw userstories = _.map userstories, (usModel) => us = {} + + model = usModel.getAttrs() + us.foldStatusChanged = @.foldStatusChanged[usModel.id] - us.model = usModel.getAttrs() - us.images = _.filter usModel.attachments, (it) -> return !!it.thumbnail_card_url + + us.model = model + us.images = _.filter model.attachments, (it) -> return !!it.thumbnail_card_url + us.id = usModel.id us.assigned_to = @.usersById[usModel.assigned_to] us.colorized_tags = _.map us.model.tags, (tag) => diff --git a/app/coffee/modules/kanban/main.coffee b/app/coffee/modules/kanban/main.coffee index 643472f5..b7ad0597 100644 --- a/app/coffee/modules/kanban/main.coffee +++ b/app/coffee/modules/kanban/main.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -58,7 +58,8 @@ class KanbanController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi "$tgModel", "tgKanbanUserstories", "$tgStorage", - "tgFilterRemoteStorageService" + "tgFilterRemoteStorageService", + "tgProjectService" ] storeCustomFiltersName: 'kanban-custom-filters' @@ -66,7 +67,7 @@ class KanbanController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi constructor: (@scope, @rootscope, @repo, @confirm, @rs, @rs2, @params, @q, @location, @appMetaService, @navUrls, @events, @analytics, @translate, @errorHandlingService, - @model, @kanbanUserstoriesService, @storage, @filterRemoteStorageService) -> + @model, @kanbanUserstoriesService, @storage, @filterRemoteStorageService, @projectService) -> bindMethods(@) @kanbanUserstoriesService.reset() @.openFilter = false @@ -76,6 +77,10 @@ class KanbanController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi @scope.sectionName = @translate.instant("KANBAN.SECTION_NAME") @.initializeEventHandlers() + taiga.defineImmutableProperty @.scope, "usByStatus", () => + return @kanbanUserstoriesService.usByStatus + + firstLoad: () -> promise = @.loadInitialData() # On Success @@ -90,16 +95,29 @@ class KanbanController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi # On Error promise.then null, @.onInitialDataError.bind(@) - taiga.defineImmutableProperty @.scope, "usByStatus", () => - return @kanbanUserstoriesService.usByStatus - setZoom: (zoomLevel, zoom) -> - if @.zoomLevel != zoomLevel - @kanbanUserstoriesService.resetFolds() + if @.zoomLevel == zoomLevel + return null + + @.isFirstLoad = !@.zoomLevel + + previousZoomLevel = @.zoomLevel @.zoomLevel = zoomLevel @.zoom = zoom + if @.isFirstLoad + @.firstLoad().then () => + @.isFirstLoad = false + @kanbanUserstoriesService.resetFolds() + + else if @.zoomLevel > 1 && previousZoomLevel <= 1 + @.zoomLoading = true + + @.loadUserstories().then () => + @.zoomLoading = false + @kanbanUserstoriesService.resetFolds() + filtersReloadContent: () -> @.loadUserstories().then () => openArchived = _.difference(@kanbanUserstoriesService.archivedStatus, @@ -181,13 +199,15 @@ class KanbanController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi return @rs.projects.tagsColors(@scope.projectId).then (tags_colors) => @scope.project.tags_colors = tags_colors._attrs - loadUserstories: -> + loadUserstories: () -> params = { - status__is_archived: false, - include_attachments: true, - include_tasks: true + status__is_archived: false } + if @.zoomLevel > 1 + params.include_attachments = 1 + params.include_tasks = 1 + params = _.merge params, @location.search() promise = @rs.userstories.listAll(@scope.projectId, params).then (userstories) => @@ -237,20 +257,21 @@ class KanbanController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi ]) loadProject: -> - return @rs.projects.getBySlug(@params.pslug).then (project) => - if not project.is_kanban_activated - @errorHandlingService.permissionDenied() + project = @projectService.project.toJS() - @scope.projectId = project.id - @scope.project = project - @scope.projectId = project.id - @scope.points = _.sortBy(project.points, "order") - @scope.pointsById = groupBy(project.points, (x) -> x.id) - @scope.usStatusById = groupBy(project.us_statuses, (x) -> x.id) - @scope.usStatusList = _.sortBy(project.us_statuses, "order") + if not project.is_kanban_activated + @errorHandlingService.permissionDenied() - @scope.$emit("project:loaded", project) - return project + @scope.projectId = project.id + @scope.project = project + @scope.projectId = project.id + @scope.points = _.sortBy(project.points, "order") + @scope.pointsById = groupBy(project.points, (x) -> x.id) + @scope.usStatusById = groupBy(project.us_statuses, (x) -> x.id) + @scope.usStatusList = _.sortBy(project.us_statuses, "order") + + @scope.$emit("project:loaded", project) + return project initializeSubscription: -> routingKey1 = "changes.project.#{@scope.projectId}.userstories" @@ -258,12 +279,12 @@ class KanbanController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi @.loadUserstories() loadInitialData: -> - promise = @.loadProject() - return promise.then (project) => - @.fillUsersAndRoles(project.members, project.roles) - @.initializeSubscription() - @.loadKanban() - @.generateFilters() + project = @.loadProject() + + @.fillUsersAndRoles(project.members, project.roles) + @.initializeSubscription() + @.loadKanban() + @.generateFilters() # Utils methods @@ -407,12 +428,8 @@ module.directive("tgKanbanArchivedStatusIntro", ["$translate", "tgKanbanUserstor ## Kanban Squish Column Directive ############################################################################# -KanbanSquishColumnDirective = (rs) -> +KanbanSquishColumnDirective = (rs, projectService) -> link = ($scope, $el, $attrs) -> - $scope.$on "project:loaded", (event, project) -> - $scope.folds = rs.kanban.getStatusColumnModes(project.id) - updateTableWidth() - $scope.foldStatus = (status) -> $scope.folds[status.id] = !!!$scope.folds[status.id] rs.kanban.storeStatusColumnModes($scope.projectId, $scope.folds) @@ -425,14 +442,22 @@ KanbanSquishColumnDirective = (rs) -> return 40 else return 310 + totalWidth = _.reduce columnWidths, (total, width) -> return total + width $el.find('.kanban-table-inner').css("width", totalWidth) + unwatch = $scope.$watch 'usByStatus', (usByStatus) -> + if usByStatus.size + $scope.folds = rs.kanban.getStatusColumnModes(projectService.project.get('id')) + updateTableWidth() + + unwatch() + return {link: link} -module.directive("tgKanbanSquishColumn", ["$tgResources", KanbanSquishColumnDirective]) +module.directive("tgKanbanSquishColumn", ["$tgResources", "tgProjectService", KanbanSquishColumnDirective]) ############################################################################# ## Kanban WIP Limit Directive diff --git a/app/coffee/modules/kanban/sortable.coffee b/app/coffee/modules/kanban/sortable.coffee index e3e72876..8df444ed 100644 --- a/app/coffee/modules/kanban/sortable.coffee +++ b/app/coffee/modules/kanban/sortable.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/plugins.coffee b/app/coffee/modules/plugins.coffee index b826c25c..b83a5569 100644 --- a/app/coffee/modules/plugins.coffee +++ b/app/coffee/modules/plugins.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/projects.coffee b/app/coffee/modules/projects.coffee index 95f3641c..ecc4f8f6 100644 --- a/app/coffee/modules/projects.coffee +++ b/app/coffee/modules/projects.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/projects/create-project-restriction.directive.coffee b/app/coffee/modules/projects/create-project-restriction.directive.coffee deleted file mode 100644 index 66564563..00000000 --- a/app/coffee/modules/projects/create-project-restriction.directive.coffee +++ /dev/null @@ -1,8 +0,0 @@ -module = angular.module("taigaProject") - -createProjectRestrictionDirective = () -> - return { - templateUrl: "project/wizard-restrictions.html" - } - -module.directive('tgCreateProjectRestriction', [createProjectRestrictionDirective]) diff --git a/app/coffee/modules/projects/lightboxes.coffee b/app/coffee/modules/projects/lightboxes.coffee index eca7121f..528bbc4e 100644 --- a/app/coffee/modules/projects/lightboxes.coffee +++ b/app/coffee/modules/projects/lightboxes.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -29,94 +29,6 @@ debounce = @.taiga.debounce module = angular.module("taigaProject") -CreateProject = ($rootscope, $repo, $confirm, $location, $navurls, $rs, $projectUrl, $loading, lightboxService, $cacheFactory, $translate, currentUserService, $auth) -> - link = ($scope, $el, attrs) -> - $scope.data = {} - $scope.templates = [] - currentLoading = null - - form = $el.find("form").checksley({"onlyOneErrorElement": true}) - - onSuccessSubmit = (response) -> - # remove all $http cache - # This is necessary when a project is created with the same name - # than another deleted in the same session - $cacheFactory.get('$http').removeAll() - - currentLoading.finish() - $rootscope.$broadcast("projects:reload") - - $confirm.notify("success", $translate.instant("COMMON.SAVE")) - - $location.url($projectUrl.get(response)) - lightboxService.close($el) - currentUserService.loadProjects() - - onErrorSubmit = (response) -> - currentLoading.finish() - form.setErrors(response) - selectors = [] - for error_field in _.keys(response) - selectors.push("[name=#{error_field}]") - - submit = (event) => - event.preventDefault() - - if not form.validate() - return - - currentLoading = $loading() - .target(submitButton) - .start() - - promise = $repo.create("projects", $scope.data) - promise.then(onSuccessSubmit, onErrorSubmit) - - openLightbox = -> - $scope.data = { - is_private: false - } - - if !$scope.templates.length - $rs.projects.templates().then (result) => - $scope.templates = result - $scope.data.creation_template = _.head(_.filter($scope.templates, (x) -> x.slug == "scrum")).id - else - $scope.data.creation_template = _.head(_.filter($scope.templates, (x) -> x.slug == "scrum")).id - - $scope.canCreatePrivateProjects = currentUserService.canCreatePrivateProjects() - $scope.canCreatePublicProjects = currentUserService.canCreatePublicProjects() - - lightboxService.open($el) - - submitButton = $el.find(".submit-button") - - $el.on "submit", "form", submit - - $el.on "click", ".close", (event) -> - event.preventDefault() - lightboxService.close($el) - - $scope.$on "$destroy", -> - $el.off() - - $auth.refresh().then () -> - openLightbox() - - directive = { - link: link, - templateUrl: "project/wizard-create-project.html" - scope: {} - } - - return directive - - -module.directive("tgLbCreateProject", ["$rootScope", "$tgRepo", "$tgConfirm", - "$location", "$tgNavUrls", "$tgResources", "$projectUrl", "$tgLoading", - "lightboxService", "$cacheFactory", "$translate", "tgCurrentUserService", "$tgAuth", CreateProject]) - - ############################################################################# ## Delete Project Lightbox Directive ############################################################################# diff --git a/app/coffee/modules/related-tasks.coffee b/app/coffee/modules/related-tasks.coffee index d8eede4e..9d42ae32 100644 --- a/app/coffee/modules/related-tasks.coffee +++ b/app/coffee/modules/related-tasks.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -34,6 +34,8 @@ RelatedTaskRowDirective = ($repo, $compile, $confirm, $rootscope, $loading, $tem templateEdit = $template.get("task/related-task-row-edit.html", true) link = ($scope, $el, $attrs, $model) -> + @childScope = $scope.$new() + saveTask = debounce 2000, (task) -> task.subject = $el.find('input').val() @@ -53,7 +55,10 @@ RelatedTaskRowDirective = ($repo, $compile, $confirm, $rootscope, $loading, $tem return promise renderEdit = (task) -> - $el.html($compile(templateEdit({task: task}))($scope)) + @childScope.$destroy() + @childScope = $scope.$new() + $el.off() + $el.html($compile(templateEdit({task: task}))(childScope)) $el.find(".task-name input").val(task.subject) @@ -72,6 +77,8 @@ RelatedTaskRowDirective = ($repo, $compile, $confirm, $rootscope, $loading, $tem renderView($model.$modelValue) renderView = (task) -> + @childScope.$destroy() + @childScope = $scope.$new() $el.off() perms = { @@ -79,7 +86,7 @@ RelatedTaskRowDirective = ($repo, $compile, $confirm, $rootscope, $loading, $tem delete_task: $scope.project.my_permissions.indexOf("delete_task") != -1 } - $el.html($compile(templateView({task: task, perms: perms}))($scope)) + $el.html($compile(templateView({task: task, perms: perms}))(childScope)) $el.on "click", ".edit-task", -> renderEdit($model.$modelValue) diff --git a/app/coffee/modules/resources.coffee b/app/coffee/modules/resources.coffee index 20b9fa9a..64d8a299 100644 --- a/app/coffee/modules/resources.coffee +++ b/app/coffee/modules/resources.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -74,6 +74,7 @@ urls = { "project-unlike": "/projects/%s/unlike" "project-watch": "/projects/%s/watch" "project-unwatch": "/projects/%s/unwatch" + "project-contact": "contact" "project-transfer-validate-token": "/projects/%s/transfer_validate_token" "project-transfer-accept": "/projects/%s/transfer_accept" "project-transfer-reject": "/projects/%s/transfer_reject" @@ -109,6 +110,7 @@ urls = { "bulk-update-us-milestone": "/userstories/bulk_update_milestone" "bulk-update-us-miles-order": "/userstories/bulk_update_sprint_order" "bulk-update-us-kanban-order": "/userstories/bulk_update_kanban_order" + "bulk-update-us-milestone": "/userstories/bulk_update_milestone" "userstories-filters": "/userstories/filters_data" "userstory-upvote": "/userstories/%s/upvote" "userstory-downvote": "/userstories/%s/downvote" @@ -201,6 +203,31 @@ urls = { # Stats "stats-discover": "/stats/discover" + + # Importers + "importers-trello-auth-url": "/importers/trello/auth_url" + "importers-trello-authorize": "/importers/trello/authorize" + "importers-trello-list-projects": "/importers/trello/list_projects" + "importers-trello-list-users": "/importers/trello/list_users" + "importers-trello-import-project": "/importers/trello/import_project" + + "importers-jira-auth-url": "/importers/jira/auth_url" + "importers-jira-authorize": "/importers/jira/authorize" + "importers-jira-list-projects": "/importers/jira/list_projects" + "importers-jira-list-users": "/importers/jira/list_users" + "importers-jira-import-project": "/importers/jira/import_project" + + "importers-github-auth-url": "/importers/github/auth_url" + "importers-github-authorize": "/importers/github/authorize" + "importers-github-list-projects": "/importers/github/list_projects" + "importers-github-list-users": "/importers/github/list_users" + "importers-github-import-project": "/importers/github/import_project" + + "importers-asana-auth-url": "/importers/asana/auth_url" + "importers-asana-authorize": "/importers/asana/authorize" + "importers-asana-list-projects": "/importers/asana/list_projects" + "importers-asana-list-users": "/importers/asana/list_users" + "importers-asana-import-project": "/importers/asana/import_project" } # Initialize api urls service diff --git a/app/coffee/modules/resources/custom-attributes-values.coffee b/app/coffee/modules/resources/custom-attributes-values.coffee index 904d506e..a63ca55b 100644 --- a/app/coffee/modules/resources/custom-attributes-values.coffee +++ b/app/coffee/modules/resources/custom-attributes-values.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/resources/custom-attributes.coffee b/app/coffee/modules/resources/custom-attributes.coffee index 88ae4872..3b7f363b 100644 --- a/app/coffee/modules/resources/custom-attributes.coffee +++ b/app/coffee/modules/resources/custom-attributes.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/resources/epics.coffee b/app/coffee/modules/resources/epics.coffee index 480395ce..9873fb08 100644 --- a/app/coffee/modules/resources/epics.coffee +++ b/app/coffee/modules/resources/epics.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/resources/history.coffee b/app/coffee/modules/resources/history.coffee index 6e0942b1..690ccf47 100644 --- a/app/coffee/modules/resources/history.coffee +++ b/app/coffee/modules/resources/history.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/resources/invitations.coffee b/app/coffee/modules/resources/invitations.coffee index 50058426..99347e84 100644 --- a/app/coffee/modules/resources/invitations.coffee +++ b/app/coffee/modules/resources/invitations.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/resources/issues.coffee b/app/coffee/modules/resources/issues.coffee index 60ea24b6..b487c822 100644 --- a/app/coffee/modules/resources/issues.coffee +++ b/app/coffee/modules/resources/issues.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/resources/kanban.coffee b/app/coffee/modules/resources/kanban.coffee index 48bd2074..6b86e050 100644 --- a/app/coffee/modules/resources/kanban.coffee +++ b/app/coffee/modules/resources/kanban.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/resources/locales.coffee b/app/coffee/modules/resources/locales.coffee index a53090f5..db5a6e31 100644 --- a/app/coffee/modules/resources/locales.coffee +++ b/app/coffee/modules/resources/locales.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/resources/mdrender.coffee b/app/coffee/modules/resources/mdrender.coffee index 98017b49..2e53047c 100644 --- a/app/coffee/modules/resources/mdrender.coffee +++ b/app/coffee/modules/resources/mdrender.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/resources/memberships.coffee b/app/coffee/modules/resources/memberships.coffee index ab7891e5..cae8ed79 100644 --- a/app/coffee/modules/resources/memberships.coffee +++ b/app/coffee/modules/resources/memberships.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/resources/modules.coffee b/app/coffee/modules/resources/modules.coffee index b1f342f7..ce4d4b77 100644 --- a/app/coffee/modules/resources/modules.coffee +++ b/app/coffee/modules/resources/modules.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/resources/notify-policies.coffee b/app/coffee/modules/resources/notify-policies.coffee index 34abf634..d67ad90a 100644 --- a/app/coffee/modules/resources/notify-policies.coffee +++ b/app/coffee/modules/resources/notify-policies.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/resources/projects.coffee b/app/coffee/modules/resources/projects.coffee index dcb48a72..1ca6716e 100644 --- a/app/coffee/modules/resources/projects.coffee +++ b/app/coffee/modules/resources/projects.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/resources/roles.coffee b/app/coffee/modules/resources/roles.coffee index f878eda8..3ee12f20 100644 --- a/app/coffee/modules/resources/roles.coffee +++ b/app/coffee/modules/resources/roles.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/resources/search.coffee b/app/coffee/modules/resources/search.coffee index c46bbe33..b521f038 100644 --- a/app/coffee/modules/resources/search.coffee +++ b/app/coffee/modules/resources/search.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/resources/sprints.coffee b/app/coffee/modules/resources/sprints.coffee index 06fadbe1..c0a45676 100644 --- a/app/coffee/modules/resources/sprints.coffee +++ b/app/coffee/modules/resources/sprints.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/resources/tasks.coffee b/app/coffee/modules/resources/tasks.coffee index 4c47ad6e..62ce3e07 100644 --- a/app/coffee/modules/resources/tasks.coffee +++ b/app/coffee/modules/resources/tasks.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -33,9 +33,12 @@ resourceProvider = ($repo, $http, $urls, $storage) -> hashSuffixStatusColumnModes = "tasks-statuscolumnmodels" hashSuffixUsRowModes = "tasks-usrowmodels" - service.get = (projectId, taskId) -> + service.get = (projectId, taskId, extraParams) -> params = service.getQueryParams(projectId) params.project = projectId + + params = _.extend({}, params, extraParams) + return $repo.queryOne("tasks", taskId, params) service.getByRef = (projectId, ref, extraParams) -> diff --git a/app/coffee/modules/resources/user-settings.coffee b/app/coffee/modules/resources/user-settings.coffee index ee53c6ef..24a59f23 100644 --- a/app/coffee/modules/resources/user-settings.coffee +++ b/app/coffee/modules/resources/user-settings.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/resources/users.coffee b/app/coffee/modules/resources/users.coffee index 6d139693..968f4122 100644 --- a/app/coffee/modules/resources/users.coffee +++ b/app/coffee/modules/resources/users.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/resources/userstories.coffee b/app/coffee/modules/resources/userstories.coffee index f4c5cca4..f3aeb5f4 100644 --- a/app/coffee/modules/resources/userstories.coffee +++ b/app/coffee/modules/resources/userstories.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -30,9 +30,12 @@ resourceProvider = ($repo, $http, $urls, $storage, $q) -> service = {} hashSuffix = "userstories-queryparams" - service.get = (projectId, usId) -> + service.get = (projectId, usId, extraParams) -> params = service.getQueryParams(projectId) params.project = projectId + + params = _.extend({}, params, extraParams) + return $repo.queryOne("userstories", usId, params) service.getByRef = (projectId, ref, extraParams = {}) -> @@ -64,6 +67,7 @@ resourceProvider = ($repo, $http, $urls, $storage, $q) -> params = {"project": projectId} params = _.extend({}, params, filters or {}) service.storeQueryParams(projectId, params) + return $repo.queryMany("userstories", params) service.bulkCreate = (projectId, status, bulk) -> @@ -108,6 +112,17 @@ resourceProvider = ($repo, $http, $urls, $storage, $q) -> params = {project_id: projectId, bulk_stories: data} return $http.post(url, params) + service.bulkUpdateMilestone = (projectId, milestoneId, data) -> + url = $urls.resolve("bulk-update-us-milestone") + data = _.map data, (us) -> + return { + us_id: us.id + order: us.order + } + + params = {project_id: projectId, milestone_id: milestoneId, bulk_stories: data} + return $http.post(url, params) + service.listValues = (projectId, type) -> params = {"project": projectId} service.storeQueryParams(projectId, params) diff --git a/app/coffee/modules/resources/webhooklogs.coffee b/app/coffee/modules/resources/webhooklogs.coffee index d33cfecc..3f0511c5 100644 --- a/app/coffee/modules/resources/webhooklogs.coffee +++ b/app/coffee/modules/resources/webhooklogs.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/resources/webhooks.coffee b/app/coffee/modules/resources/webhooks.coffee index 2f51e540..dae59b37 100644 --- a/app/coffee/modules/resources/webhooks.coffee +++ b/app/coffee/modules/resources/webhooks.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/resources/wiki.coffee b/app/coffee/modules/resources/wiki.coffee index 8c7beee4..5ef41b24 100644 --- a/app/coffee/modules/resources/wiki.coffee +++ b/app/coffee/modules/resources/wiki.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/search.coffee b/app/coffee/modules/search.coffee index 37cf51bc..760ea40b 100644 --- a/app/coffee/modules/search.coffee +++ b/app/coffee/modules/search.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -49,23 +49,22 @@ class SearchController extends mixOf(taiga.Controller, taiga.PageMixin) "tgAppMetaService", "$tgNavUrls", "$translate", - "tgErrorHandlingService" + "tgErrorHandlingService", + "tgProjectService" ] - constructor: (@scope, @repo, @rs, @params, @q, @location, @appMetaService, @navUrls, @translate, @errorHandlingService) -> + constructor: (@scope, @repo, @rs, @params, @q, @location, @appMetaService, @navUrls, @translate, @errorHandlingService, @projectService) -> @scope.sectionName = "Search" - promise = @.loadInitialData() + @.loadInitialData() - promise.then () => - title = @translate.instant("SEARCH.PAGE_TITLE", {projectName: @scope.project.name}) - description = @translate.instant("SEARCH.PAGE_DESCRIPTION", { - projectName: @scope.project.name, - projectDescription: @scope.project.description - }) - @appMetaService.setAll(title, description) + title = @translate.instant("SEARCH.PAGE_TITLE", {projectName: @scope.project.name}) + description = @translate.instant("SEARCH.PAGE_DESCRIPTION", { + projectName: @scope.project.name, + projectDescription: @scope.project.description + }) - promise.then null, @.onInitialDataError.bind(@) + @appMetaService.setAll(title, description) # Search input watcher @scope.searchTerm = null @@ -85,17 +84,18 @@ class SearchController extends mixOf(taiga.Controller, taiga.PageMixin) return defered.promise loadProject: -> - return @rs.projects.getBySlug(@params.pslug).then (project) => - @scope.project = project - @scope.$emit('project:loaded', project) + project = @projectService.project.toJS() - @scope.epicStatusById = groupBy(project.epic_statuses, (x) -> x.id) - @scope.issueStatusById = groupBy(project.issue_statuses, (x) -> x.id) - @scope.taskStatusById = groupBy(project.task_statuses, (x) -> x.id) - @scope.severityById = groupBy(project.severities, (x) -> x.id) - @scope.priorityById = groupBy(project.priorities, (x) -> x.id) - @scope.usStatusById = groupBy(project.us_statuses, (x) -> x.id) - return project + @scope.project = project + @scope.$emit('project:loaded', project) + + @scope.epicStatusById = groupBy(project.epic_statuses, (x) -> x.id) + @scope.issueStatusById = groupBy(project.issue_statuses, (x) -> x.id) + @scope.taskStatusById = groupBy(project.task_statuses, (x) -> x.id) + @scope.severityById = groupBy(project.severities, (x) -> x.id) + @scope.priorityById = groupBy(project.priorities, (x) -> x.id) + @scope.usStatusById = groupBy(project.us_statuses, (x) -> x.id) + return project loadSearchData: (term = "") -> @scope.loading = true @@ -112,9 +112,10 @@ class SearchController extends mixOf(taiga.Controller, taiga.PageMixin) return @._promise loadInitialData: -> - return @.loadProject().then (project) => - @scope.projectId = project.id - @.fillUsersAndRoles(project.members, project.roles) + project = @.loadProject() + + @scope.projectId = project.id + @.fillUsersAndRoles(project.members, project.roles) module.controller("SearchController", SearchController) diff --git a/app/coffee/modules/taskboard.coffee b/app/coffee/modules/taskboard.coffee index ac09372a..8047a54c 100644 --- a/app/coffee/modules/taskboard.coffee +++ b/app/coffee/modules/taskboard.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/taskboard/charts.coffee b/app/coffee/modules/taskboard/charts.coffee index 9e6af226..d482f87b 100644 --- a/app/coffee/modules/taskboard/charts.coffee +++ b/app/coffee/modules/taskboard/charts.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/taskboard/lightboxes.coffee b/app/coffee/modules/taskboard/lightboxes.coffee index f162b8fe..19ecb708 100644 --- a/app/coffee/modules/taskboard/lightboxes.coffee +++ b/app/coffee/modules/taskboard/lightboxes.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -42,6 +42,9 @@ CreateEditTaskDirective = ($repo, $model, $rs, $rootscope, $loading, lightboxSer attachmentsToAdd = attachmentsToAdd.push(attachment) $scope.deleteAttachment = (attachment) -> + attachmentsToAdd = attachmentsToAdd.filter (it) -> + return it.get('name') != attachment.get('name') + if attachment.get("id") attachmentsToDelete = attachmentsToDelete.push(attachment) diff --git a/app/coffee/modules/taskboard/main.coffee b/app/coffee/modules/taskboard/main.coffee index 74f95d84..10e7be65 100644 --- a/app/coffee/modules/taskboard/main.coffee +++ b/app/coffee/modules/taskboard/main.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -72,6 +72,10 @@ class TaskboardController extends mixOf(taiga.Controller, taiga.PageMixin, taiga @scope.sectionName = @translate.instant("TASKBOARD.SECTION_NAME") @.initializeEventHandlers() + taiga.defineImmutableProperty @.scope, "usTasks", () => + return @taskboardTasksService.usTasks + + firstLoad: () -> promise = @.loadInitialData() # On Success @@ -79,16 +83,28 @@ class TaskboardController extends mixOf(taiga.Controller, taiga.PageMixin, taiga # On Error promise.then null, @.onInitialDataError.bind(@) - taiga.defineImmutableProperty @.scope, "usTasks", () => - return @taskboardTasksService.usTasks - setZoom: (zoomLevel, zoom) -> - if @.zoomLevel != zoomLevel - @taskboardTasksService.resetFolds() + if @.zoomLevel == zoomLevel + return null + + @.isFirstLoad = !@.zoomLevel + + previousZoomLevel = @.zoomLevel @.zoomLevel = zoomLevel @.zoom = zoom + if @.isFirstLoad + @.firstLoad().then () => + @.isFirstLoad = false + @taskboardTasksService.resetFolds() + + else if @.zoomLevel > 1 && previousZoomLevel <= 1 + @.zoomLoading = true + @.loadTasks().then () => + @.zoomLoading = false + @taskboardTasksService.resetFolds() + if @.zoomLevel == '0' @rootscope.$broadcast("sprint:zoom0") @@ -342,9 +358,10 @@ class TaskboardController extends mixOf(taiga.Controller, taiga.PageMixin, taiga return sprint loadTasks: -> - params = { - include_attachments: true, - } + params = {} + + if @.zoomLevel > 1 + params.include_attachments = 1 params = _.merge params, @location.search() diff --git a/app/coffee/modules/taskboard/sortable.coffee b/app/coffee/modules/taskboard/sortable.coffee index 119fcae0..2e5a291f 100644 --- a/app/coffee/modules/taskboard/sortable.coffee +++ b/app/coffee/modules/taskboard/sortable.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/taskboard/taskboard-tasks.coffee b/app/coffee/modules/taskboard/taskboard-tasks.coffee index 013238fb..276f338d 100644 --- a/app/coffee/modules/taskboard/taskboard-tasks.coffee +++ b/app/coffee/modules/taskboard/taskboard-tasks.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -157,12 +157,15 @@ class TaskboardTasksService extends taiga.Service for taskModel in tasks if usTasks[taskModel.user_story]? and usTasks[taskModel.user_story][taskModel.status]? task = {} + + model = taskModel.getAttrs() + task.foldStatusChanged = @.foldStatusChanged[taskModel.id] - task.model = taskModel.getAttrs() - task.images = _.filter taskModel.attachments, (it) -> return !!it.thumbnail_card_url + task.model = model + task.images = _.filter model.attachments, (it) -> return !!it.thumbnail_card_url task.id = taskModel.id task.assigned_to = @.usersById[taskModel.assigned_to] - task.colorized_tags = _.map task.model.tags, (tag) => + task.colorized_tags = _.map task.model.tags, (tag) => return {name: tag[0], color: tag[1]} usTasks[taskModel.user_story][taskModel.status].push(task) diff --git a/app/coffee/modules/tasks.coffee b/app/coffee/modules/tasks.coffee index 2062317d..79d17350 100644 --- a/app/coffee/modules/tasks.coffee +++ b/app/coffee/modules/tasks.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/tasks/detail.coffee b/app/coffee/modules/tasks/detail.coffee index 2e9ae523..6ed9af5c 100644 --- a/app/coffee/modules/tasks/detail.coffee +++ b/app/coffee/modules/tasks/detail.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -51,11 +51,12 @@ class TaskDetailController extends mixOf(taiga.Controller, taiga.PageMixin) "$tgAnalytics", "$translate", "$tgQueueModelTransformation", - "tgErrorHandlingService" + "tgErrorHandlingService", + "tgProjectService" ] constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, - @log, @appMetaService, @navUrls, @analytics, @translate, @modelTransform, @errorHandlingService) -> + @log, @appMetaService, @navUrls, @analytics, @translate, @modelTransform, @errorHandlingService, @projectService) -> bindMethods(@) @scope.taskRef = @params.taskref @@ -106,13 +107,14 @@ class TaskDetailController extends mixOf(taiga.Controller, taiga.PageMixin) @scope.onDeleteGoToUrl = @navUrls.resolve("project-userstories-detail", ctx) loadProject: -> - return @rs.projects.getBySlug(@params.pslug).then (project) => - @scope.projectId = project.id - @scope.project = project - @scope.$emit('project:loaded', project) - @scope.statusList = project.task_statuses - @scope.statusById = groupBy(project.task_statuses, (x) -> x.id) - return project + project = @projectService.project.toJS() + + @scope.projectId = project.id + @scope.project = project + @scope.$emit('project:loaded', project) + @scope.statusList = project.task_statuses + @scope.statusById = groupBy(project.task_statuses, (x) -> x.id) + return project loadTask: -> return @rs.tasks.getByRef(@scope.projectId, @params.taskref).then (task) => @@ -150,10 +152,10 @@ class TaskDetailController extends mixOf(taiga.Controller, taiga.PageMixin) return us loadInitialData: -> - promise = @.loadProject() - return promise.then (project) => - @.fillUsersAndRoles(project.members, project.roles) - @.loadTask().then(=> @q.all([@.loadSprint(), @.loadUserStory()])) + project = @.loadProject() + + @.fillUsersAndRoles(project.members, project.roles) + return @.loadTask().then(=> @q.all([@.loadSprint(), @.loadUserStory()])) ### # Note: This methods (onUpvote() and onDownvote()) are related to tg-vote-button. diff --git a/app/coffee/modules/team.coffee b/app/coffee/modules/team.coffee index 8e36614a..1975d76c 100644 --- a/app/coffee/modules/team.coffee +++ b/app/coffee/modules/team.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/team/main.coffee b/app/coffee/modules/team/main.coffee index e11a4769..fef22c05 100644 --- a/app/coffee/modules/team/main.coffee +++ b/app/coffee/modules/team/main.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -88,17 +88,18 @@ class TeamController extends mixOf(taiga.Controller, taiga.PageMixin) @scope.memberships = _.reject(@scope.activeUsers, {id: user?.id}) loadProject: -> - return @rs.projects.getBySlug(@params.pslug).then (project) => - @scope.projectId = project.id - @scope.project = project - @scope.$emit('project:loaded', project) + project = @projectService.project.toJS() - @scope.issuesEnabled = project.is_issues_activated - @scope.tasksEnabled = project.is_kanban_activated or project.is_backlog_activated - @scope.wikiEnabled = project.is_wiki_activated - @scope.owner = project.owner.id + @scope.projectId = project.id + @scope.project = project + @scope.$emit('project:loaded', project) - return project + @scope.issuesEnabled = project.is_issues_activated + @scope.tasksEnabled = project.is_kanban_activated or project.is_backlog_activated + @scope.wikiEnabled = project.is_wiki_activated + @scope.owner = project.owner.id + + return project loadMemberStats: -> return @rs.projects.memberStats(@scope.projectId).then (stats) => @@ -132,16 +133,16 @@ class TeamController extends mixOf(taiga.Controller, taiga.PageMixin) return stats loadInitialData: -> - promise = @.loadProject() - return promise.then (project) => - @.fillUsersAndRoles(project.members, project.roles) - @.loadMembers() + project = @.loadProject() - userRoles = _.map @scope.users, (user) -> user.role + @.fillUsersAndRoles(project.members, project.roles) + @.loadMembers() - @scope.roles = _.filter @scope.roles, (role) -> userRoles.indexOf(role.id) != -1 + userRoles = _.map @scope.users, (user) -> user.role - return @.loadMemberStats() + @scope.roles = _.filter @scope.roles, (role) -> userRoles.indexOf(role.id) != -1 + + return @.loadMemberStats() module.controller("TeamController", TeamController) diff --git a/app/coffee/modules/user-settings.coffee b/app/coffee/modules/user-settings.coffee index 1a581ed3..d0e542db 100644 --- a/app/coffee/modules/user-settings.coffee +++ b/app/coffee/modules/user-settings.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/user-settings/change-password.coffee b/app/coffee/modules/user-settings/change-password.coffee index a08acb8c..dcb2b9fd 100644 --- a/app/coffee/modules/user-settings/change-password.coffee +++ b/app/coffee/modules/user-settings/change-password.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/user-settings/lightboxes.coffee b/app/coffee/modules/user-settings/lightboxes.coffee index 32f32bce..97791ef6 100644 --- a/app/coffee/modules/user-settings/lightboxes.coffee +++ b/app/coffee/modules/user-settings/lightboxes.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/user-settings/main.coffee b/app/coffee/modules/user-settings/main.coffee index e1ac9139..7057eaaf 100644 --- a/app/coffee/modules/user-settings/main.coffee +++ b/app/coffee/modules/user-settings/main.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/user-settings/nav.coffee b/app/coffee/modules/user-settings/nav.coffee index f9762b4a..86f8f2ae 100644 --- a/app/coffee/modules/user-settings/nav.coffee +++ b/app/coffee/modules/user-settings/nav.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/user-settings/notifications.coffee b/app/coffee/modules/user-settings/notifications.coffee index 0cb25f4c..4bc19754 100644 --- a/app/coffee/modules/user-settings/notifications.coffee +++ b/app/coffee/modules/user-settings/notifications.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/userstories.coffee b/app/coffee/modules/userstories.coffee index ae0df58f..8cf5e2db 100644 --- a/app/coffee/modules/userstories.coffee +++ b/app/coffee/modules/userstories.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/userstories/detail.coffee b/app/coffee/modules/userstories/detail.coffee index 950185df..56866510 100644 --- a/app/coffee/modules/userstories/detail.coffee +++ b/app/coffee/modules/userstories/detail.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -52,11 +52,14 @@ class UserStoryDetailController extends mixOf(taiga.Controller, taiga.PageMixin) "$translate", "$tgQueueModelTransformation", "tgErrorHandlingService", - "$tgConfig" + "$tgConfig", + "tgProjectService", + "tgWysiwygService" ] constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, - @log, @appMetaService, @navUrls, @analytics, @translate, @modelTransform, @errorHandlingService, @configService) -> + @log, @appMetaService, @navUrls, @analytics, @translate, @modelTransform, + @errorHandlingService, @configService, @projectService, @wysiwigService) -> bindMethods(@) @scope.usRef = @params.usref @@ -88,7 +91,7 @@ class UserStoryDetailController extends mixOf(taiga.Controller, taiga.PageMixin) description = @translate.instant("US.PAGE_DESCRIPTION", { userStoryStatus: @scope.statusById[@scope.us.status]?.name or "--" userStoryPoints: @scope.us.total_points - userStoryDescription: angular.element(@scope.us.description_html or "").text() + userStoryDescription: angular.element(@wysiwigService.getHTML(@scope.us.description) or "").text() userStoryClosedTasks: closedTasks userStoryTotalTasks: totalTasks userStoryProgressPercentage: progressPercentage @@ -123,16 +126,17 @@ class UserStoryDetailController extends mixOf(taiga.Controller, taiga.PageMixin) @scope.onDeleteGoToUrl = @navUrls.resolve("project-kanban", ctx) loadProject: -> - return @rs.projects.getBySlug(@params.pslug).then (project) => - @scope.projectId = project.id - @scope.project = project - @scope.$emit('project:loaded', project) - @scope.statusList = project.us_statuses - @scope.statusById = groupBy(project.us_statuses, (x) -> x.id) - @scope.taskStatusById = groupBy(project.task_statuses, (x) -> x.id) - @scope.pointsList = _.sortBy(project.points, "order") - @scope.pointsById = groupBy(@scope.pointsList, (e) -> e.id) - return project + project = @projectService.project.toJS() + + @scope.projectId = project.id + @scope.project = project + @scope.$emit('project:loaded', project) + @scope.statusList = project.us_statuses + @scope.statusById = groupBy(project.us_statuses, (x) -> x.id) + @scope.taskStatusById = groupBy(project.task_statuses, (x) -> x.id) + @scope.pointsList = _.sortBy(project.points, "order") + @scope.pointsById = groupBy(@scope.pointsList, (e) -> e.id) + return project loadUs: -> httpParams = _.pick(@location.search(), "milestone", "no-milestone", "kanban-status") @@ -180,10 +184,9 @@ class UserStoryDetailController extends mixOf(taiga.Controller, taiga.PageMixin) return tasks loadInitialData: -> - promise = @.loadProject() - return promise.then (project) => - @.fillUsersAndRoles(project.members, project.roles) - @.loadUs().then(=> @q.all([@.loadSprint(), @.loadTasks()])) + project = @.loadProject() + @.fillUsersAndRoles(project.members, project.roles) + @.loadUs().then(=> @q.all([@.loadSprint(), @.loadTasks()])) ### # Note: This methods (onUpvote() and onDownvote()) are related to tg-vote-button. diff --git a/app/coffee/modules/wiki.coffee b/app/coffee/modules/wiki.coffee index cf963020..4cdfb10c 100644 --- a/app/coffee/modules/wiki.coffee +++ b/app/coffee/modules/wiki.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/coffee/modules/wiki/main.coffee b/app/coffee/modules/wiki/main.coffee index b192b09a..88fdcf02 100644 --- a/app/coffee/modules/wiki/main.coffee +++ b/app/coffee/modules/wiki/main.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -52,11 +52,12 @@ class WikiDetailController extends mixOf(taiga.Controller, taiga.PageMixin) "$tgNavUrls", "$tgAnalytics", "$translate", - "tgErrorHandlingService" + "tgErrorHandlingService", + "tgProjectService" ] constructor: (@scope, @rootscope, @repo, @model, @confirm, @rs, @params, @q, @location, - @filter, @log, @appMetaService, @navUrls, @analytics, @translate, @errorHandlingService) -> + @filter, @log, @appMetaService, @navUrls, @analytics, @translate, @errorHandlingService, @projectService) -> @scope.$on("wiki:links:move", @.moveLink) @scope.projectSlug = @params.pslug @scope.wikiSlug = @params.slug @@ -86,14 +87,15 @@ class WikiDetailController extends mixOf(taiga.Controller, taiga.PageMixin) @appMetaService.setAll(title, description) loadProject: -> - return @rs.projects.getBySlug(@params.pslug).then (project) => - if not project.is_wiki_activated - @errorHandlingService.permissionDenied() + project = @projectService.project.toJS() - @scope.projectId = project.id - @scope.project = project - @scope.$emit('project:loaded', project) - return project + if not project.is_wiki_activated + @errorHandlingService.permissionDenied() + + @scope.projectId = project.id + @scope.project = project + @scope.$emit('project:loaded', project) + return project loadWiki: -> promise = @rs.wiki.getBySlug(@scope.projectId, @params.slug) @@ -130,10 +132,10 @@ class WikiDetailController extends mixOf(taiga.Controller, taiga.PageMixin) @scope.wikiTitle = selectedWikiLink.title if selectedWikiLink? loadInitialData: -> - promise = @.loadProject() - return promise.then (project) => - @.fillUsersAndRoles(project.members, project.roles) - @q.all([@.loadWikiLinks(), @.loadWiki()]).then @.checkLinksPerms.bind(this) + project = @.loadProject() + + @.fillUsersAndRoles(project.members, project.roles) + @q.all([@.loadWikiLinks(), @.loadWiki()]).then @.checkLinksPerms.bind(this) checkLinksPerms: -> if @scope.project.my_permissions.indexOf("add_wiki_link") != -1 || @@ -150,6 +152,7 @@ class WikiDetailController extends mixOf(taiga.Controller, taiga.PageMixin) ctx = {project: @scope.projectSlug} @location.path(@navUrls.resolve("project-wiki", ctx)) @confirm.notify("success") + @.loadWiki() onError = => askResponse.finish(false) @@ -215,126 +218,82 @@ WikiSummaryDirective = ($log, $template, $compile, $translate, avatarService) -> module.directive("tgWikiSummary", ["$log", "$tgTemplate", "$compile", "$translate", "tgAvatarService", WikiSummaryDirective]) +WikiWysiwyg = ($modelTransform, $rootscope, $confirm, attachmentsFullService, +$qqueue, $repo, $analytics, wikiHistoryService) -> + link = ($scope, $el, $attrs) -> + $scope.editableDescription = false -############################################################################# -## Editable Wiki Content Directive -############################################################################# - -EditableWikiContentDirective = ($window, $document, $repo, $confirm, $loading, $analytics, $qqueue, $translate, - $wikiHistoryService) -> - link = ($scope, $el, $attrs, $model) -> - isEditable = -> - return $scope.project.my_permissions.indexOf("modify_wiki_page") != -1 - - switchToEditMode = -> - $el.find('.edit-wiki-content').show() - $el.find('.view-wiki-content').hide() - $el.find('textarea').focus() - - switchToReadMode = -> - $el.find('.edit-wiki-content').hide() - $el.find('.view-wiki-content').show() - - disableEdition = -> - $el.find(".view-wiki-content .edit").remove() - $el.find(".edit-wiki-content").remove() - - cancelEdition = -> - return if not $model.$modelValue.id - - $model.$modelValue.revert() - switchToReadMode() - - getSelectedText = -> - if $window.getSelection - return $window.getSelection().toString() - else if $document.selection - return $document.selection.createRange().text - return null - - save = $qqueue.bindAdd (wiki) -> + $scope.saveDescription = $qqueue.bindAdd (description, cb) -> onSuccess = (wikiPage) -> - if not wiki.id? + if not $scope.item.id? $analytics.trackEvent("wikipage", "create", "create wiki page", 1) - $model.$setViewValue wikiPage.clone() - - $wikiHistoryService.loadHistoryEntries() + wikiHistoryService.loadHistoryEntries() $confirm.notify("success") - switchToReadMode() onError = -> $confirm.notify("error") - currentLoading = $loading() - .target($el.find('.save')) - .start() + $scope.item.content = description - if wiki.id? - promise = $repo.save(wiki).then(onSuccess, onError) + if $scope.item.id? + promise = $repo.save($scope.item).then(onSuccess, onError) else - promise = $repo.create("wiki", wiki).then(onSuccess, onError) + promise = $repo.create("wiki", $scope.item).then(onSuccess, onError) - promise.finally -> - currentLoading.finish() + promise.finally(cb) - $el.on "click", "a", (event) -> - target = angular.element(event.currentTarget) - href = target.attr('href') + uploadFile = (file, cb) -> + return attachmentsFullService.addAttachment($scope.project.id, $scope.item.id, 'wiki_page', file).then (result) -> + cb(result.getIn(['file', 'name']), result.getIn(['file', 'url'])) - if href.indexOf("#") == 0 - event.preventDefault() - $('body').scrollTop($(href).offset().top) + $scope.uploadFiles = (files, cb) -> + for file in files + uploadFile(file, cb) - $el.on "mousedown", ".view-wiki-content", (event) -> - target = angular.element(event.target) - return if not isEditable() - return if event.button == 2 + $scope.$watch $attrs.model, (value) -> + return if not value + $scope.item = value + $scope.version = value.version + $scope.storageKey = $scope.project.id + "-" + value.id + "-" + $attrs.type - $el.on "mouseup", ".view-wiki-content", (event) -> - target = angular.element(event.target) - return if getSelectedText() - return if not isEditable() - return if target.is('a') - return if target.is('pre') + $scope.$watch 'project', (project) -> + return if !project - switchToEditMode() - - $el.on "click", ".save", debounce 2000, -> - save($scope.wiki) - - $el.on "click", ".cancel", -> - $scope.$apply(cancelEdition) - - $el.on "keydown", "textarea", (event) -> - return if event.keyCode != 27 - $scope.$applyAsync () -> - title = $translate.instant("COMMON.CONFIRM_CLOSE_EDIT_MODE_TITLE") - message = $translate.instant("COMMON.CONFIRM_CLOSE_EDIT_MODE_MESSAGE") - $confirm.ask(title, null, message).then (askResponse) -> - cancelEdition() - askResponse.finish() - - $scope.$watch $attrs.ngModel, (wikiPage) -> - return if not wikiPage - - if isEditable() - $el.addClass('editable') - if not wikiPage.id? or $.trim(wikiPage.content).length == 0 - switchToEditMode() - else - disableEdition() - - $scope.$on "$destroy", -> - $el.off() + $scope.editableDescription = project.my_permissions.indexOf("modify_wiki_page") != -1 return { - link: link - restrict: "EA" - require: "ngModel" - templateUrl: "wiki/editable-wiki-content.html" + scope: true, + link: link, + template: """ +
+ + + +
+ +
+ {{'COMMON.DESCRIPTION.NO_DESCRIPTION' | translate}} +
+
+ """ } -module.directive("tgEditableWikiContent", ["$window", "$document", "$tgRepo", "$tgConfirm", "$tgLoading", - "$tgAnalytics", "$tgQqueue", "$translate", "tgWikiHistoryService", - EditableWikiContentDirective]) +module.directive("tgWikiWysiwyg", [ + "$tgQueueModelTransformation", + "$rootScope", + "$tgConfirm", + "tgAttachmentsFullService", + "$tgQqueue", "$tgRepo", "$tgAnalytics", "tgWikiHistoryService" + WikiWysiwyg]) diff --git a/app/coffee/modules/wiki/nav.coffee b/app/coffee/modules/wiki/nav.coffee index 5b6bb01b..4193b0f1 100644 --- a/app/coffee/modules/wiki/nav.coffee +++ b/app/coffee/modules/wiki/nav.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -105,7 +105,7 @@ WikiNavDirective = ($tgrepo, $log, $location, $confirm, $analytics, $loading, $t target = angular.element(event.currentTarget) linkId = target.parents('.wiki-link').data('id') - title = $translate.instant("WIKI.DELETE_LIGHTBOX_TITLE") + title = $translate.instant("WIKI.DELETE_LINK_TITLE") message = $scope.wikiLinks[linkId].title $confirm.askOnDelete(title, message).then (askResponse) => diff --git a/app/coffee/modules/wiki/pages-list.coffee b/app/coffee/modules/wiki/pages-list.coffee index 5aaddb8c..a26603c9 100644 --- a/app/coffee/modules/wiki/pages-list.coffee +++ b/app/coffee/modules/wiki/pages-list.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -43,11 +43,12 @@ class WikiPagesListController extends mixOf(taiga.Controller, taiga.PageMixin) "$routeParams", "$q", "$tgNavUrls", - "tgErrorHandlingService" + "tgErrorHandlingService", + "tgProjectService" ] constructor: (@scope, @rootscope, @repo, @model, @confirm, @rs, @params, @q, - @navUrls, @errorHandlingService) -> + @navUrls, @errorHandlingService, @projectService) -> @scope.projectSlug = @params.pslug @scope.wikiSlug = @params.slug @scope.wikiTitle = @scope.wikiSlug @@ -60,14 +61,16 @@ class WikiPagesListController extends mixOf(taiga.Controller, taiga.PageMixin) promise.then null, @.onInitialDataError.bind(@) loadProject: -> - return @rs.projects.getBySlug(@params.pslug).then (project) => - if not project.is_wiki_activated - @errorHandlingService.permissionDenied() + project = @projectService.project.toJS() - @scope.projectId = project.id - @scope.project = project - @scope.$emit('project:loaded', project) - return project + if not project.is_wiki_activated + @errorHandlingService.permissionDenied() + + @scope.projectId = project.id + @scope.project = project + @scope.$emit('project:loaded', project) + + return project loadWikiPages: -> promise = @rs.wiki.list(@scope.projectId).then (wikipages) => @@ -87,10 +90,11 @@ class WikiPagesListController extends mixOf(taiga.Controller, taiga.PageMixin) @scope.wikiTitle = selectedWikiLink.title if selectedWikiLink? loadInitialData: -> - promise = @.loadProject() - return promise.then (project) => - @.fillUsersAndRoles(project.members, project.roles) - @q.all([@.loadWikiLinks(), @.loadWikiPages()]).then @.checkLinksPerms.bind(this) + project = @.loadProject() + + @.fillUsersAndRoles(project.members, project.roles) + + @q.all([@.loadWikiLinks(), @.loadWikiPages()]).then(@.checkLinksPerms.bind(this)) checkLinksPerms: -> if @scope.project.my_permissions.indexOf("add_wiki_link") != -1 || diff --git a/app/coffee/utils.coffee b/app/coffee/utils.coffee index a2d02c99..f9ec5c14 100644 --- a/app/coffee/utils.coffee +++ b/app/coffee/utils.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -220,8 +220,10 @@ _.mixin isImage = (name) -> - return name.match(/\.(jpe?g|png|gif|gifv|webm)/i) != null + return name.match(/\.(jpe?g|png|gif|gifv|webm|svg|psd)/i) != null +isEmail = (name) -> + return name? and name.match(/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/) != null isPdf = (name) -> return name.match(/\.(pdf)/i) != null @@ -251,6 +253,16 @@ getRandomDefaultColor = () -> getDefaulColorList = () -> return _.clone(DEFAULT_COLOR_LIST) +getMatches = (string, regex, index) -> + index || (index = 1) + matches = [] + match = null + + while match = regex.exec(string) + matches.push(match[index]) + + return matches + taiga = @.taiga taiga.addClass = addClass taiga.nl2br = nl2br @@ -276,7 +288,9 @@ taiga.stripTags = stripTags taiga.replaceTags = replaceTags taiga.defineImmutableProperty = defineImmutableProperty taiga.isImage = isImage +taiga.isEmail = isEmail taiga.isPdf = isPdf taiga.patch = patch taiga.getRandomDefaultColor = getRandomDefaultColor taiga.getDefaulColorList = getDefaulColorList +taiga.getMatches = getMatches diff --git a/app/images/import-logos/asana.png b/app/images/import-logos/asana.png new file mode 100644 index 00000000..1de82ae5 Binary files /dev/null and b/app/images/import-logos/asana.png differ diff --git a/app/images/import-logos/github.png b/app/images/import-logos/github.png new file mode 100644 index 00000000..77aaf337 Binary files /dev/null and b/app/images/import-logos/github.png differ diff --git a/app/images/import-logos/jira.png b/app/images/import-logos/jira.png new file mode 100644 index 00000000..5e917863 Binary files /dev/null and b/app/images/import-logos/jira.png differ diff --git a/app/images/import-logos/trello.png b/app/images/import-logos/trello.png new file mode 100644 index 00000000..4660b575 Binary files /dev/null and b/app/images/import-logos/trello.png differ diff --git a/app/images/looking-for-people.png b/app/images/looking-for-people.png index 89800164..01b4e4ed 100644 Binary files a/app/images/looking-for-people.png and b/app/images/looking-for-people.png differ diff --git a/app/index.jade b/app/index.jade index 7ba7bb63..ae7d1734 100644 --- a/app/index.jade +++ b/app/index.jade @@ -51,3 +51,4 @@ html(lang="en") script(src="/#{v}/js/templates.js") script(src="/#{v}/js/app-loader.js") include svg/sprite.svg + include svg/editor.svg diff --git a/app/js/medium-mention.js b/app/js/medium-mention.js new file mode 100644 index 00000000..936874be --- /dev/null +++ b/app/js/medium-mention.js @@ -0,0 +1,270 @@ +var MentionExtension = MediumEditor.Extension.extend({ + name: 'mediumMention', + init: function() { + this.subscribe('editableKeyup', this.handleKeyup.bind(this)); + this.subscribe('editableKeydown', this.handleKeydown.bind(this)); + this.subscribe('blur', this.cancel.bind(this)); + }, + isEditMode: function() { + return !this.base.origElements.parentNode.classList.contains('read-mode'); + }, + cancel: function() { + if (this.isEditMode()) { + this.hidePanel(); + this.reset(); + } + }, + handleKeydown: function(e) { + var code = e.keyCode ? e.keyCode : e.which; + + if (this.mentionPanel && code === MediumEditor.util.keyCode.ENTER) { + e.preventDefault(); + } + }, + handleKeyup: function(e) { + var code = e.keyCode ? e.keyCode : e.which; + var isSpace = code === MediumEditor.util.keyCode.SPACE; + var isBackspace = code === MediumEditor.util.keyCode.BACKSPACE; + + if (this.mentionPanel) { + this.keyDownMentionPanel(e); + } + + var moveKeys = [37, 38, 39, 40]; + + if (moveKeys.indexOf(code) !== -1) { + return; + } + + this.selection = this.document.getSelection(); + + if (isBackspace && this.selection.focusNode.nodeName.toLowerCase() === 'p') { + return; + } + + if (!isSpace && this.selection.rangeCount === 1) { + var endChar = this.selection.getRangeAt(0).startOffset; + var textContent = this.selection.focusNode.textContent; + + this.word = this.getLastWord(textContent); + textContent = textContent.substring(0, endChar); + + if (this.word.length > 1 && ['@', '#', ':'].indexOf(this.word[0]) != -1) { + this.wrap(); + this.showPanel(); + + MediumEditor.selection.select( + this.document, + this.wordNode.firstChild, + this.word.length + ); + + return; + } + } else if (isSpace) { + this.cancelMentionSpace(); + } + + this.hidePanel(); + }, + reset: function() { + this.wordNode = null; + this.word = null; + this.selection = null; + }, + cancelMentionSpace: function() { + if (this.wordNode && this.wordNode.nextSibling) { + var textNode = this.document.createTextNode(''); + textNode.textContent = this.word + '\u00A0'; + + this.wordNode.parentNode.replaceChild(textNode, this.wordNode); + + MediumEditor.selection.select(this.document, textNode, this.word.length + 1); + } + + this.reset(); + }, + wrap: function() { + var range = this.selection.getRangeAt(0).cloneRange(); + + if (range.startContainer.parentNode.nodeName.toLowerCase() === 'a') { + var parentLink = range.startContainer.parentNode.parentNode; + var textNode = this.document.createTextNode(range.startContainer.parentNode.innerText); + + parentLink.replaceChild(textNode, range.startContainer.parentNode); + + this.selection.removeAllRanges(); + + range = document.createRange(); + + range.setStart(textNode, textNode.length); + range.setEnd(textNode, textNode.length); + + this.selection.addRange(range); + } + + if (!range.startContainer.parentNode.classList.contains('mention')) { + this.wordNode = this.document.createElement('span'); + this.wordNode.classList.add('mention'); + + range.setStart(range.startContainer, this.selection.getRangeAt(0).startOffset - this.word.length); + range.surroundContents(this.wordNode); + + this.selection.removeAllRanges(); + this.selection.addRange(range); + + //move cursor to old position + range.setStart(range.startContainer, range.endOffset); + range.setStart(range.endContainer, range.endOffset); + this.selection.removeAllRanges(); + this.selection.addRange(range); + } else { + this.wordNode = range.startContainer.parentNode; + } + }, + refreshPositionPanel: function() { + var bound = this.wordNode.getBoundingClientRect(); + + this.mentionPanel.style.top = this.window.pageYOffset + bound.bottom + 'px'; + this.mentionPanel.style.left = this.window.pageXOffset + bound.left + 'px'; + }, + selectMention: function(item) { + if (item.image) { + var img = document.createElement('img'); + img.src = item.image; + + this.wordNode.parentNode.replaceChild(img, this.wordNode); + this.wordNode = img; + } else { + var link = document.createElement('a'); + + link.setAttribute('href', item.url); + + if (item.ref) { + link.innerText = '#' + item.ref + '-' + item.subject; + } else { + link.innerText = '@' + item.username; + } + + this.wordNode.parentNode.replaceChild(link, this.wordNode); + this.wordNode = link; + } + + var textNode = this.document.createTextNode(''); + textNode.textContent = '\u00A0'; + + this.wordNode.parentNode.insertBefore(textNode, this.wordNode.nextSibling); + MediumEditor.selection.select(this.document, textNode, 1); + + var target = this.base.getFocusedElement(); + + this.base.events.updateInput(target, { + target: target, + currentTarget: target + }); + + this.hidePanel(); + this.reset(); + }, + showPanel: function() { + if(document.querySelectorAll('.medium-editor-mention-panel').length) { + this.refreshPositionPanel(); + this.getItems(this.word, this.renderPanel.bind(this)); + return; + } + + var el = this.document.createElement('div'); + el.classList.add('medium-editor-mention-panel'); + this.mentionPanel = el; + this.getEditorOption('elementsContainer').appendChild(el); + + this.refreshPositionPanel(); + this.getItems(this.word, this.renderPanel.bind(this)); + }, + keyDownMentionPanel: function(e) { + var code = e.keyCode ? e.keyCode : e.which; + var active = this.mentionPanel.querySelector('.active'); + + this.wordNode = document.querySelector('span.mention'); + + if(!active) { + return; + } + + if (code === MediumEditor.util.keyCode.ENTER) { + e.preventDefault(); + e.stopPropagation(); + + var event = document.createEvent('HTMLEvents'); + event.initEvent('click', true, false); + + active.dispatchEvent(event); + + return; + } + + active.classList.remove('active'); + + if (code === 38) { + if(active.previousSibling) { + active.previousSibling.classList.add('active'); + } else { + active.parentNode.lastChild.classList.add('active'); + } + } else if (code === 40) { + if(active.nextSibling) { + active.nextSibling.classList.add('active'); + } else { + active.parentNode.firstChild.classList.add('active'); + } + } + }, + renderPanel: function(items) { + this.mentionPanel.innerHTML = ''; + + if (!items.length) return; + + var ul = this.document.createElement('ul'); + + ul.classList.add('medium-mention'); + + items.forEach(function(it) { + var li = this.document.createElement('li'); + + if (it.image) { + var img = this.document.createElement('img'); + + img.src = it.image; + li.appendChild(img); + + var textNode = document.createTextNode(''); + textNode.textContent = ' ' + it.name; + + li.appendChild(textNode); + + } else if (it.ref) { + li.innerText = '#' + it.ref + ' - ' + it.subject; + } else { + li.innerText = '@' + it.username; + } + + li.addEventListener('mousedown', this.selectMention.bind(this, it)); + + ul.appendChild(li); + }.bind(this)); + + ul.firstChild.classList.add('active'); + + this.mentionPanel.appendChild(ul); + }, + hidePanel: function() { + if (this.mentionPanel) { + this.mentionPanel.parentNode.removeChild(this.mentionPanel); + this.mentionPanel = null; + } + }, + getLastWord: function(text) { + var n = text.split(' '); + return n[n.length - 1].trim(); + } +}); diff --git a/app/locales/taiga/locale-ca.json b/app/locales/taiga/locale-ca.json index 029d9984..5bf8f9f7 100644 --- a/app/locales/taiga/locale-ca.json +++ b/app/locales/taiga/locale-ca.json @@ -4,7 +4,6 @@ "NO": "No", "OR": "o", "LOADING": "Carregant...", - "LOADING_PROJECT": "Carregant projecte...", "DATE": "DD MMM YYYY", "DATETIME": "DD MMM YYYY HH:mm", "SAVE": "Desa", @@ -27,12 +26,9 @@ "BLOCKED_NOTE": "Per qué està bloquejat?", "BLOCKED_REASON": "Per favor, explica la raó", "CREATED_BY": "Creat per {{fullDisplayName}}", - "FROM": "de", - "TO": "a", "CLOSE": "Tancar", "GO_HOME": "Porta'm a l'inici ", "PLUGINS": "Plugins", - "BETA": "Estem en beta!", "ONE_ITEM_LINE": "In item per línia", "NEW_BULK": "Nova inserció en grup", "RELATED_TASKS": "Tasques relacionades", @@ -41,7 +37,7 @@ "LOGOUT": "Surt", "EXTERNAL_USER": "un usuari extern", "GENERIC_ERROR": "Un Oompa Loompas diu {{error}}.", - "IOCAINE_TEXT": "Un poc saturat per una tasca? Fes-ho saber als teus companys clicant a Iocaina quan edites la tasca. Es possible ser inmune a aquesta (fictícia) poció mortal consumint xicotetes dòsis poc a poc, així com es possible millorar amb xicotets nous desafiaments!", + "IOCAINE_TEXT": "This member is feeling a bit overwhelmed by this task. Will become immune to the iocaine poison over time with your help. For now, may need a hug.", "CLIENT_REQUIREMENT": "Client requirement is new requirement that was not previously expected and it is required to be part of the project", "TEAM_REQUIREMENT": "Team requirement is a requirement that must exist in the project but should have no cost for the client", "OWNER": "Project Owner", @@ -148,7 +144,6 @@ "PRIORITY": "Prioritat", "ASSIGNED_TO": "Assignat a", "POINTS": "Punts", - "BLOCKED_NOTE": "Nota de bloqueig", "IS_BLOCKED": "està bloquejat", "REF": "Ref", "VOTES": "Vots", @@ -187,10 +182,6 @@ "COUNTER_TITLE": "{total, plural, one{un seguidor} other{# seguidors}}" }, "VOTE_BUTTON": { - "UPVOTE": "Upvote", - "UPVOTED": "Upvoted", - "DOWNVOTE": "Downvote", - "VOTERS": "Voters", "BUTTON_TITLE": "Upvote/Downvote this item", "COUNTER_TITLE": "{total, plural, one{one vote} other{# votes}}" }, @@ -202,10 +193,9 @@ "CONFIRM_DELETE": "Remeber that all values in this custom field will be deleted.\n Are you sure you want to continue?" }, "FILTERS": { - "TITLE": "Filtres", "INPUT_PLACEHOLDER": "Descripció o referència", "TITLE_ACTION_FILTER_BUTTON": "cerca", - "INPUT_SEARCH_PLACEHOLDER": "Descripció o ref", + "TITLE": "Filtres", "TITLE_ACTION_SEARCH": "Cerca", "ACTION_SAVE_CUSTOM_FILTER": "Guarda com a filtre", "PLACEHOLDER_FILTER_NAME": "Escriu el filtre i pressiona Intro", @@ -220,41 +210,10 @@ "CREATED_BY": "Creat per", "CUSTOM_FILTERS": "Filtres personalitzats", "EPIC": "Epic" - }, - "CONFIRM_DELETE": { - "TITLE": "Esborrar filtre", - "MESSAGE": "el filtre '{{customFilterName}}'" } }, "WYSIWYG": { - "H1_BUTTON": "Capçcalera de primer nivel", - "H1_SAMPLE_TEXT": "El títul ací...", - "H2_BUTTON": "Capçalera de segon nivel", - "H2_SAMPLE_TEXT": "El títul ací...", - "H3_BUTTON": "Tercer nivell de capçalera", - "H3_SAMPLE_TEXT": "El títul ací...", - "BOLD_BUTTON": "Gros", - "BOLD_BUTTON_SAMPLE_TEXT": "El teu text ací...", - "ITALIC_BUTTON": "Itàlica", - "ITALIC_SAMPLE_TEXT": "El teu text ací...", - "STRIKE_BUTTON": "Tatxar", - "STRIKE_SAMPLE_TEXT": "El teu text ací...", - "BULLETED_LIST_BUTTON": "Llista ordenada", - "BULLETED_LIST_SAMPLE_TEXT": "El teu text ací...", - "NUMERIC_LIST_BUTTON": "Llista numèrica", - "NUMERIC_LIST_SAMPLE_TEXT": "El teu text ací...", - "PICTURE_BUTTON": "Foto", - "PICTURE_SAMPLE_TEXT": "El text alternatiu a la foto ací", - "LINK_BUTTON": "Enllaç", - "LINK_SAMPLE_TEXT": "El teu text per al link ací...", - "QUOTE_BLOCK_BUTTON": "Bloc de cita", - "QUOTE_BLOCK_SAMPLE_TEXT": "El teu text ací...", - "CODE_BLOCK_BUTTON": "Bolc de codi", - "CODE_BLOCK_SAMPLE_TEXT": "El teu text ací...", - "PREVIEW_BUTTON": "Previsualitzar", - "EDIT_BUTTON": "Editar", - "ATTACH_FILE_HELP": "Attach files by dragging & dropping on the textarea above.", - "ATTACH_FILE_HELP_SAVE_FIRST": "Save first before if you want to attach files by dragging & dropping on the textarea above.", + "OUTDATED": "Another person has made changes while you were editing. Check the new version on the activiy tab before you save your changes.", "MARKDOWN_HELP": "Ajuda de Markdown" }, "PERMISIONS_CATEGORIES": { @@ -307,10 +266,6 @@ "ADD_WIKI_LINKS": "Afegir link de wiki", "DELETE_WIKI_LINKS": "Esborrar enllaços de wiki" } - }, - "META": { - "PAGE_TITLE": "Taiga", - "PAGE_DESCRIPTION": "Taiga is a project management platform for startups and agile developers & designers who want a simple, beautiful tool that makes work truly enjoyable." } }, "LOGIN": { @@ -366,7 +321,6 @@ }, "CHANGE_PASSWORD": { "PAGE_TITLE": "Canvi de contrasenya - Taiga", - "PAGE_DESCRIPTION": "Estableix una contrasenya nova per al teu compte de Taiga i per cer cert! Potser voleu menjar més aliments rics en ferro, és bo per al cervell :P", "SECTION_NAME": "Canvi de contrasenya", "FIELD_CURRENT_PASSWORD": "Contrasenya actual", "PLACEHOLDER_CURRENT_PASSWORD": "La teua contrasenya actua (buit si no tens contrasenya encara)", @@ -391,8 +345,7 @@ }, "INVITATION_LOGIN_FORM": { "NOT_FOUND": "Els Oompa Loompas no troben la teua invitació.", - "SUCCESS": "T'has incorporat a este projecte. Vos donem la benvinguda a {{project_name}}", - "ERROR": "Segons els nostres OOmpa Loompas, no estàs registrat encara o has escrit una contrasenya invàlida." + "SUCCESS": "T'has incorporat a este projecte. Vos donem la benvinguda a {{project_name}}" }, "HOME": { "PAGE_TITLE": "Home - Taiga", @@ -463,10 +416,7 @@ "TITLE_LIGHTBOX_DELETE_ATTACHMENT": "Esborrar adjunt...", "MSG_LIGHTBOX_DELETE_ATTACHMENT": "l'adjunt '{{fileName}}'", "ERROR_DELETE_ATTACHMENT": "No hem pogut esborrar: {{errorMessage}}", - "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) es massa gran per als nostres Oompa Loompas, prova amb algun inferior a ({{maxFileSize}})", - "FIELDS": { - "IS_DEPRECATED": "es obsolet" - } + "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) es massa gran per als nostres Oompa Loompas, prova amb algun inferior a ({{maxFileSize}})" }, "PAGINATION": { "PREVIOUS": "Abans", @@ -502,13 +452,10 @@ "ASYNC_MESSAGE": "T'enviarem un correu quan estiga llest.", "SYNC_MESSAGE": "Si la descàrrega no baixa directament clica ací.", "ERROR": "Els Oompa Loompas tenen problemes generant el teu arxiu de dades. Per favor intenta-ho de nou.", - "ERROR_BUSY": "Ho sentim, els Oompa Loompas estàn molt ocupats ara mateix. Intenta-ho de nou en uns moments.", - "ERROR_MESSAGE": "Els Oompa Loompas tenen problemes generant el teu arxiu de dades: {{message}}" + "ERROR_BUSY": "Ho sentim, els Oompa Loompas estàn molt ocupats ara mateix. Intenta-ho de nou en uns moments." }, "MODULES": { "TITLE": "Mòdules", - "ENABLE": "Activa", - "DISABLE": "Desactiva", "EPICS": "Epics", "EPICS_DESCRIPTION": "Visualize and manage the most strategic part of your project", "BACKLOG": "Backlog", @@ -537,17 +484,16 @@ "PAGE_TITLE": "{{sectionName}} - Perfil de projecte - {{projectName}}", "PROJECT_DETAILS": "Detalls de projecte", "PROJECT_NAME": "Nom del projecte", - "PROJECT_SLUG": "Slug de projecte", "TAGS": "Etiquetes", "DESCRIPTION": "Descripció", "RECRUITING": "Este projecte busca col·laboracions?", "RECRUITING_MESSAGE": "A qui estàs buscant?", "RECRUITING_PLACEHOLDER": "Defineix els perfils que estàs buscant", + "FEEDBACK": "Receive feedback from Taiga users?", "PUBLIC_PROJECT": "Projecte públic", "PRIVATE_PROJECT": "Projecte privat", "PRIVATE_OR_PUBLIC": "What's the difference between public and private projects?", "DELETE": "Esborra aquest projecte", - "LOGO_HELP": "S'escalarà la imatge a 80x80px.", "CHANGE_LOGO": "Change logo", "ACTION_USE_DEFAULT_LOGO": "Utilitza la imatge per defecte", "MAX_PRIVATE_PROJECTS": "You've reached the maximum number of private projects allowed by your current plan", @@ -595,6 +541,7 @@ "ISSUE_DESCRIPTION": "Camps personalitzats d'incidències", "ISSUE_ADD": "Afegix camps personalitzats en incidències", "FIELD_TYPE_TEXT": "Text", + "FIELD_TYPE_RICHTEXT": "Rich text", "FIELD_TYPE_MULTI": "Múltiples línies", "FIELD_TYPE_DATE": "Data", "FIELD_TYPE_URL": "Url" @@ -623,7 +570,7 @@ "ACTION_ADD": "Afegir nova severitat" }, "PROJECT_VALUES_STATUS": { - "TITLE": "Estat", + "TITLE": "Statuses", "SUBTITLE": "Especifica els estats de les vostres històries d'usuari, tasques i incidències", "EPIC_TITLE": "Epic Statuses", "US_TITLE": "User Story Statuses", @@ -676,8 +623,8 @@ "INFO_VERIFYING_IP": "Les peticions a Bitbuket no estan signades. El millor mode de verificar l'oritge es per IP. Si el camp està buit no hi haurà verificació per IP." }, "GITHUB": { - "SECTION_NAME": "Github", - "PAGE_TITLE": "Github - {{projectName}}" + "SECTION_NAME": "GitHub", + "PAGE_TITLE": "GitHub - {{projectName}}" }, "GOGS": { "SECTION_NAME": "Gogs", @@ -686,7 +633,6 @@ "WEBHOOKS": { "PAGE_TITLE": "Webhooks - {{projectName}}", "SECTION_NAME": "Webhooks", - "SUBTITLE": "Els Webhooks notifiquen serveis extens de events en taiga com comentaris, històries d'usuari...", "ADD_NEW": "Afegir un nou Webhook", "TYPE_NAME": "Escriu el nom del servei", "TYPE_PAYLOAD_URL": "Escriu el service payload url", @@ -732,7 +678,6 @@ "DELETE_MEMBER": "Esborrar membre", "RESEND": "Resend", "SUCCESS_SEND_INVITATION": "Hem tornat a enviar la invitació a '{{email}}'.", - "ERROR_SEND_INVITATION": "No s'ha enviat la invitació", "SUCCESS_DELETE": "Hem esborrat {{message}}.", "ERROR_DELETE": "No hem pogut esborrar ", "DEFAULT_DELETE_MESSAGE": "la invitació a '{{email}}'." @@ -761,16 +706,11 @@ "PLACEHOLDER_WRITE_NAME": "Escriviu un nom per al nou estat" }, "MENU": { - "TITLE": "Admin", "PROJECT": "Projecte", "ATTRIBUTES": "Atributs", "MEMBERS": "Membres", "PERMISSIONS": "Permisos", - "INTEGRATIONS": "Integracions", - "PLUGINS": "Plugins" - }, - "SUBMENU_PROJECT_ATTRIBUTES": { - "TITLE": "Atributs" + "INTEGRATIONS": "Integracions" }, "SUBMENU_PROJECT_VALUES": { "STATUS": "Estats", @@ -781,17 +721,11 @@ "CUSTOM_FIELDS": "Camps personalitzats", "TAGS": "Etiquetes" }, - "SUBMENU_PROJECT_PROFILE": { - "TITLE": "Perfil de projecte" - }, "SUBMENU_ROLES": { "TITLE": "Rols", "ACTION_NEW_ROLE": "+ Nou rol", "TITLE_ACTION_NEW_ROLE": "Afegir nou rol" }, - "SUBMENU_THIDPARTIES": { - "TITLE": "Serveis" - }, "PROJECT_TRANSFER": { "DO_YOU_ACCEPT_PROJECT_OWNERNSHIP": "Would you like to become the new project owner?", "PRIVATE": "Private", @@ -806,15 +740,13 @@ "PRIVATE": "Please remember that you can own up to {{maxProjects}} private projects. You currently own {{currentProjects}} private projects", "PUBLIC": "Please remember that you can own up to {{maxProjects}} public projects. You currently own {{currentProjects}} public projects" }, - "CANT_BE_OWNED": "At the moment you cannot become an owner of a project of this type. If you would like to become the owner of this project, please contact the administrator so they change your account settings to enable project ownership.", - "CHANGE_MY_PLAN": "Change my plan" + "CANT_BE_OWNED": "At the moment you cannot become an owner of a project of this type. If you would like to become the owner of this project, please contact the administrator so they change your account settings to enable project ownership." } }, "USER": { "PROFILE": { "PAGE_TITLE": "{{userFullName}} (@{{userUsername}})", "EDIT": "Edita el perfil", - "FOLLOW": "Seguir", "CLOSED_US": "HU tancada", "PROJECTS": "Projectes", "PROJECTS_EMPTY": "{{username}} encara no te cap projecte", @@ -822,7 +754,6 @@ "CONTACTS_EMPTY": "{{Usuari}} no té contactes encara", "CURRENT_USER_CONTACTS_EMPTY": "No tens contactes encara", "CURRENT_USER_CONTACTS_EMPTY_EXPLAIN": "Les persones amb les que treballa a Taiga seran els seus contactes de forma automàtica", - "REPORT": "Informar d'un abús", "TABS": { "ACTIVITY_TAB": "Timeline", "ACTIVITY_TAB_TITLE": "Mostra tota la activitat d'aquest usuari", @@ -848,13 +779,13 @@ "FILTER_TYPE_ALL": "Tot", "FILTER_TYPE_ALL_TITLE": "Mostrar tot", "FILTER_TYPE_PROJECTS": "Projectes", - "FILTER_TYPE_PROJECT_TITLES": "Mostra només projectes", + "FILTER_TYPE_PROJECTS_TITLE": "Mostra només projectes", "FILTER_TYPE_EPICS": "Epics", - "FILTER_TYPE_EPIC_TITLES": "Show only epics", + "FILTER_TYPE_EPICS_TITLE": "Show only epics", "FILTER_TYPE_USER_STORIES": "Históries", - "FILTER_TYPE_USER_STORIES_TITLES": "Veure només històries d'usuari", + "FILTER_TYPE_USER_STORIES_TITLE": "Veure només històries d'usuari", "FILTER_TYPE_TASKS": "Tasques", - "FILTER_TYPE_TASK_TITLES": "Mostra només tasquest", + "FILTER_TYPE_TASKS_TITLE": "Mostra només tasquest", "FILTER_TYPE_ISSUES": "Incidències", "FILTER_TYPE_ISSUES_TITLE": "Mostra només incidències", "EMPTY_TITLE": "Sembla que no hi ha res que mostrar" @@ -862,8 +793,6 @@ }, "PROJECT": { "PAGE_TITLE": "{{projectName}}", - "WELCOME": "Benvinguts", - "SECTION_PROJECTS": "Projectes", "HELP": "Reordena els teus projectes per a establir els més utilitzats en les primeres posicions.
Els 10 millors projectes apareixeran en la llista de projectes de la barra de navegació superior", "PRIVATE": "Projecte privat", "LOOKING_FOR_PEOPLE": "Este projecte busca col·laboracions", @@ -875,12 +804,6 @@ "THIS_PROJECT_IS_BLOCKED": "This project is temporarily blocked", "TO_UNBLOCK_CONTACT_THE_ADMIN_STAFF": "In order to unblock your projects, contact the administrator." }, - "STATS": { - "PROJECT": "punts
projecte", - "DEFINED": "punts
definits", - "ASSIGNED": "punts
assignats", - "CLOSED": "punts
tancats" - }, "SECTION": { "SEARCH": "Cerca", "TIMELINE": "Timeline", @@ -893,15 +816,9 @@ "ADMIN": "Admin" }, "NAVIGATION": { - "SECTION_TITLE": "Els teus projectes", - "PLACEHOLDER_SEARCH": "Cerca en...", "ACTION_CREATE_PROJECT": "Crear projecte", - "ACTION_IMPORT_PROJECT": "Importar projecte", "MANAGE_PROJECTS": "Gestiona els projectes", "TITLE_CREATE_PROJECT": "Crear projecte", - "TITLE_IMPORT_PROJECT": "Importar projecte", - "TITLE_PRVIOUS_PROJECT": "Mostra projectes previs", - "TITLE_NEXT_PROJECT": "Mostrar próxims projectes", "HELP_TITLE": "Pàgina d'ajuda de Taiga", "HELP": "Ajuda", "HOMEPAGE": "Homepage", @@ -909,10 +826,6 @@ "FEEDBACK": "Suggerències", "NOTIFICATIONS_TITLE": "Edita la configuració de les teves notificacions", "NOTIFICATIONS": "Notificacions", - "ORGANIZATIONS_TITLE": "Edit your organizations", - "ORGANIZATIONS": "Editar organitzacions", - "SETTINGS_TITLE": "Editeu les vostres preferències", - "SETTINGS": "Preferències", "VIEW_PROFILE_TITLE": "Visualitza el perfil", "VIEW_PROFILE": "Visualitza el perfil", "EDIT_PROFILE_TITLE": "Editeu el vostre perfil", @@ -921,14 +834,68 @@ "CHANGE_PASSWORD": "Canvi de contrasenya", "DASHBOARD_TITLE": "Tauler", "DISCOVER_TITLE": "Discover trending projects", - "NEW_ITEM": "Nova", - "DISCOVER": "Descobreix", - "ACTION_REORDER": "Arrossega els elements per endreçar" + "DISCOVER": "Descobreix" + }, + "LIKE_BUTTON": { + "LIKE": "M'agrada", + "LIKED": "T'agrada", + "UNLIKE": "No t'agrada", + "BUTTON_TITLE": "Favoriteja o desfavoriteja aquest projecte", + "COUNTER_TITLE": "{total, plural, un{un fan} altres{# fans}}" + }, + "WATCH_BUTTON": { + "BUTTON_TITLE": "Segueix este projecte i edita les notificacions", + "WATCH": "Segueix", + "WATCHING": "Observant", + "COUNTER_TITLE": "{total, plural, one{un seguidor} other{# seguidors}}", + "OPTIONS": { + "NOTIFY_ALL": "Receive all notifications", + "NOTIFY_ALL_TITLE": "Receive all notifications for this project", + "NOTIFY_INVOLVED": "Only involved", + "NOTIFY_INVOLVED_TITLE": "Recive notificacions only when you are involved", + "UNWATCH": "Unwatch", + "UNWATCH_TITLE": "Unwatch this project" + } + }, + "CONTACT_BUTTON": { + "CONTACT_TITLE": "Contact the project team", + "CONTACT_BUTTON": "Contact the project" + }, + "CREATE": { + "TITLE": "Crear projecte", + "CHOOSE_TEMPLATE": "Which template fits your project better?", + "TEMPLATE_SCRUM": "Scrum", + "TEMPLATE_SCRUM_DESC": "Prioritize and solve your tasks in short time cycles.", + "TEMPLATE_SCRUM_LONGDESC": "Scrum is an iterative and incremental agile software development methodology for managing product development.\nThe product backlog is what will ultimately be delivered, ordered into the sequence in which it should be delivered. Product Backlogs are broken into manageable, executable chunks named sprints. Every certain amount of time the team initiates a new sprint and commits to deliver a certain number of user stories from the backlog, in accordance with their skills, abilities and resources. The project advances as the backlog becomes depleted.", + "TEMPLATE_KANBAN": "Kanban", + "TEMPLATE_KANBAN_DESC": "Keep a constant workflow on independent tasks", + "TEMPLATE_KANBAN_LONGDESC": "The Kanban methodology is used to divide project development (any sort of project) into stages.\nA kanban card is like an index card or post-it note that details every task (or user story) in a project that needs to be completed. The Kanban board is used to move each card from one state of completion to the next and in so doing, helps track progress.", + "DUPLICATE": "Duplicate project", + "DUPLICATE_DESC": "Start clean and keep your configuration", + "IMPORT": "Importar projecte", + "IMPORT_DESC": "Import your project from multiple platforms into Taiga", + "INVITE": "Invite to the project", + "SOLO_PROJECT": "You'll be alone in this project", + "INVITE_LATER": "(You'll be able to invite more members later)", + "BACK": "Back", + "MAX_PRIVATE_PROJECTS": "Unfortunately, You've reached the maximum number of private projects.\nIf you would like to increase the current limit please contact the administrator.", + "MAX_PUBLIC_PROJECTS": "Unfortunately, You've reached the maximum number of public projects.\nIf you would like to increase the current limit please contact the administrator.", + "PUBLIC_PROJECT": "Public Project", + "PRIVATE_PROJECT": "Private Project" + }, + "COMMON": { + "DETAILS": "New project details", + "PROJECT_TITLE": "Project Name", + "PROJECT_DESCRIPTION": "Project Description" + }, + "DUPLICATE": { + "TITLE": "Duplicate Project", + "DESCRIPTION": "Start clean and keep your configuration", + "SELECT_PLACEHOLDER": "Choose an existing project to duplicate" }, "IMPORT": { - "TITLE": "Important Projecte", - "UPLOADING_FILE": "Pujant arxiu de dades", - "DESCRIPTION": "Aquest procés pot durar una mica, pero favor mantinga la finestra oberta", + "TITLE": "Import Project", + "DESCRIPTION": "Import your project from multiple platforms into Taiga", "ASYNC_IN_PROGRESS_TITLE": "Els Oompa Loompas estàn important el teu projecte", "ASYNC_IN_PROGRESS_MESSAGE": "Aquest procés pot durar uns moments
T'enviarem un correo quan estiga llest.", "UPLOAD_IN_PROGRESS_MESSAGE": "Pujat {{uploadedSize}} de {{totalSize}}", @@ -937,8 +904,29 @@ "ERROR_MESSAGE": "Els Oompa Loompas tenen problemes important les teues dades: {{error_message}}", "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) es massa gran per als nostres Oompa Loompas, prova amb algun inferior a ({{maxFileSize}})", "SYNC_SUCCESS": "El teu projecte s'ha importat correctament", + "IMPORT": "Import", + "WHO_IS": "Their tasks will be assigned to ...", + "WRITE_EMAIL": "Or if you want, write the email that this user uses in Taiga", + "SEARCH_CONTACT": "Or if you want, search in your contacts", + "WRITE_EMAIL_LABEL": "Write the email that this user uses in Taiga", + "ACCEEDE": "Acceede", + "PROJECT_MEMBERS": "Project Members", + "PROCESS_DESCRIPTION": "Tell us who from Taiga you want to assign the tasks of {{platform}}", + "MATCH": "Is {{user_external}} the same person as {{user_internal}}?", + "CHOOSE": "Select user", + "LINKS": "Links with {{platform}}", + "LINKS_DESCRIPTION": "Do you want to keep the link of each item with the original {{platform}} card?", + "WARNING_MAIL_USER": "Note that if the user does not have a Taiga account we will not be able to assign the tasks to him.", + "ASSIGN": "Assign", + "PROJECT_SELECTOR": { + "NO_RESULTS": "It looks like nothing was found with your search criteria", + "ACTION_SEARCH": "cerca", + "ACTION_BACK": "Back" + }, "PROJECT_RESTRICTIONS": { - "PROJECT_MEMBERS_DESC": "The project you are trying to import has {{members}} members, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per project. If you would like to increase that limit please contact the administrator.", + "PROJECT_MEMBERS_DESC_PRIVATE": "The project you are trying to import has {{members}} members including you, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per private project. If you would like to increase that limit please contact the administrator.", + "PROJECT_MEMBERS_DESC_PUBLIC": "The project you are trying to import has {{members}} members including you, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per public project. If you would like to increase that limit please contact the administrator.", + "ACCOUNT_ALLOW_MEMBERS": "Your account only allows {{members}} members", "PRIVATE_PROJECTS_SPACE": { "TITLE": "Unfortunately, your current plan does not allow for additional private projects", "DESC": "The project you are trying to import is private. Unfortunately, your current plan does not allow for additional private projects." @@ -961,39 +949,67 @@ "TITLE": "Unfortunately your current plan doesn't allow additional public projects or an increase of more than {{max_memberships}} members per public project", "DESC": "The project that you are trying to import is public and has more than {{members}} members." } - } - }, - "LIKE_BUTTON": { - "LIKE": "M'agrada", - "LIKED": "T'agrada", - "UNLIKE": "No t'agrada", - "BUTTON_TITLE": "Favoriteja o desfavoriteja aquest projecte", - "COUNTER_TITLE": "{total, plural, un{un fan} altres{# fans}}" - }, - "WATCH_BUTTON": { - "BUTTON_TITLE": "Segueix este projecte i edita les notificacions", - "WATCH": "Segueix", - "WATCHING": "Observant", - "COUNTER_TITLE": "{total, plural, one{un seguidor} other{# seguidors}}", - "OPTIONS": { - "NOTIFY_ALL": "Receive all notifications", - "NOTIFY_ALL_TITLE": "Receive all notifications for this project", - "NOTIFY_INVOLVED": "Only involved", - "NOTIFY_INVOLVED_TITLE": "Recive notificacions only when you are involved", - "UNWATCH": "Unwatch", - "UNWATCH_TITLE": "Unwatch this project" + }, + "IN_PROGRESS": { + "TITLE": "Important Projecte", + "DESCRIPTION": "Aquest procés pot durar una mica, pero favor mantinga la finestra oberta" + }, + "WARNING": { + "TITLE": "Some taks will be unassigned", + "DESCRIPTION": "There are still unidentified people. The cards assigned to these people will remain unassigned. Check all the contacts to not lose that information.", + "CHECK": "Check contacts" + }, + "TAIGA": { + "SELECTOR": "Import your Taiga project" + }, + "TRELLO": { + "SELECTOR": "Import your Trello boards into Taiga", + "CHOOSE_PROJECT": "Choose board that you want to import", + "NO_PROJECTS": "It seems you have no boards in Trello" + }, + "GITHUB": { + "SELECTOR": "Import your GitHub project issues", + "CHOOSE_PROJECT": "Find the project you want to import", + "NO_PROJECTS": "It seems you have no porjects in GitHub", + "HOW_DO_YOU_WANT_TO_IMPORT": "How do you want to import your issues into Taiga?", + "KANBAN_PROJECT": "As user stories in a kanban project", + "KANBAN_PROJECT_DESCRIPTION": "After that you can enable scrum with backlog.", + "SCRUM_PROJECT": "As user stories in a scrum project", + "SCRUM_PROJECT_DESCRIPTION": "After that you can enable kanban mode.", + "ISSUES_PROJECT": "As issues", + "ISSUES_PROJECT_DESCRIPTION": "You will not be able to use your issues in kanban or scrum mode. You will be able to enable kanban or scrum for new user stories" + }, + "ASANA": { + "SELECTOR": "Import your Asana project and choose how to manage it", + "CHOOSE_PROJECT": "Choose project that you want to import", + "NO_PROJECTS": "It seems you have no porjects in Asana", + "KANBAN_PROJECT": "Kanban", + "SCRUM_PROJECT": "Scrum", + "CREATE_AS_SCRUM_DESCRIPTION": "The tasks and sub-tasks of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_KANBAN_DESCRIPTION": "The tasks and sub-tasks of your project will be created as Taiga user stories and tasks." + }, + "JIRA": { + "SELECTOR": "Import your Jira project and choose how to manage it", + "CHOOSE_PROJECT": "Choose project or board that you want to import", + "NO_PROJECTS": "It seems you have no porjects or boards in Jira", + "URL": "Your Jira URL", + "KANBAN_PROJECT": "Kanban", + "SCRUM_PROJECT": "Scrum", + "ISSUES_PROJECT": "Incidències", + "CREATE_AS_SCRUM_DESCRIPTION": "The issues and sub-issues of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_KANBAN_DESCRIPTION": "The issues and sub-issues of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_ISSUES_DESCRIPTION": "What do you want to do with sub-issues from the Jira project? (Taiga doesn't allow sub-issues)", + "CREATE_NEW_ISSUES": "Convert sub-issues to new Taiga issues", + "NOT_CREATE_NEW_ISSUES": "Do not import sub-issues" } } }, "LIGHTBOX": { "DELETE_ACCOUNT": { - "SECTION_NAME": "Esborrar compte de Taiga", "CONFIRM": "Segur que vols borrar el teu compte de Taiga? ", - "NEWSLETTER_LABEL_TEXT": "No vull rebre més el vostre butlletí de notícies", "CANCEL": "Back to settings", "ACCEPT": "Delete account", - "BLOCK_PROJECT": "Note that all the projects you own projects will be blocked after you delete your account. If you do want a project blocked, transfer ownership to another member of each project prior to deleting your account.", - "SUBTITLE": "Sorry to see you go. We'll be here if you should ever consider us again! :(" + "BLOCK_PROJECT": "Note that all the projects you own projects will be blocked after you delete your account. If you do want a project blocked, transfer ownership to another member of each project prior to deleting your account." }, "DELETE_PROJECT": { "TITLE": "Esborrar projecte", @@ -1007,6 +1023,12 @@ }, "ADD_MEMBER": { "TITLE": "Nou membre", + "PLACEHOLDER": "Filter users or write an email to invite", + "ADD_EMAIL": "Add email", + "REMOVE": "Remove", + "INVITE": "Invite", + "CHOOSE_ROLE": "Choose a role", + "PLACEHOLDER_INVITATION_TEXT": "(Opcional) Afegix un text personalizat a la invitació. Dis-li algo divertit als nous membres. ;-)", "HELP_TEXT": "Si els usuaris ja estàn registrats en Taiga seràn afegits automàticament. Si no, rebran una invitació." }, "CREATE_ISSUE": { @@ -1068,6 +1090,12 @@ "TITLE": "Who do you want to be the new project owner?", "ADD_COMMENT": "Add comment", "BUTTON": "Ask this project member to become the new project owner" + }, + "CONTACT_PROJECT": { + "TITLE": "Send an email to", + "WARNING": "The email will be received by the project admins", + "PLACEHOLDER": "Write your message", + "SEND": "Send" } }, "EPIC": { @@ -1101,15 +1129,9 @@ "ADD_BULK": "Afegeix noves històries d'usuari en grup", "PROMOTED": "Aquesta US ha sigut promocionada desde:", "TITLE_LINK_GO_TO_ISSUE": "Anar a la incidència", - "EXTERNAL_REFERENCE": "Aquesta US ha sigut creada desde", - "GO_TO_EXTERNAL_REFERENCE": "Anar a l'orige", - "BLOCKED": "Aquest història d'usuari està bloquejada", "TITLE_DELETE_ACTION": "Esborra història d'usuari", "LIGHTBOX_TITLE_BLOKING_US": "Bloquejant US", - "TASK_COMPLETED": "{{totalClosedTasks}}/{{totalTasks}} tasques completades", - "ASSIGN": "Assigna història d'usuari", "NOT_ESTIMATED": "Sense estimar", - "TOTAL_US_POINTS": "Punts totals d'US", "TRIBE": { "PUBLISH": "Publish as Gig in Taiga Tribe", "PUBLISH_INFO": "More info", @@ -1119,23 +1141,19 @@ "CLOSE": "Close", "SYNCHRONIZE_LINK": "synchronize with Taiga Tribe", "PUBLISH_MORE_INFO_TITLE": "Do you need somebody for this task?", - "PUBLISH_MORE_INFO_TEXT": "

If you need help with a particular piece of work you can easily create gigs on Taiga Tribe and receive help from all over the world. You will be able to control and manage the gig enjoying a great community eager to contribute.

TaigaTribe was born as a Taiga sibling. Both platforms can live separately but we believe that there is much power in using them combined so we are making sure the integration works like a charm.

" + "PUBLISH_MORE_INFO_TEXT": "

If you need help with a particular piece of work you can easily create gigs on Taiga Tribe and receive help from all over the world. You will be able to control and manage the gig enjoying a great community eager to contribute.

TaigaTribe was born as a Taiga sibling. Both platforms can live separately but we believe that there is much power in using them combined so we are making sure the integration works like a charm.

" }, "FIELDS": { "TEAM_REQUIREMENT": "Requeriment d'equip", - "CLIENT_REQUIREMENT": "Requeriment de client", - "FINISH_DATE": "Data de finalització" + "CLIENT_REQUIREMENT": "Requeriment de client" } }, "COMMENTS": { "DELETED_INFO": "Comment deleted by {{user}}", - "TITLE": "Comentaris", "COMMENTS_COUNT": "{{comments}} Comments", - "ORDER": "Order", "OLDER_FIRST": "Older first", "RECENT_FIRST": "Recent first", "COMMENT": "Comentar", - "EDIT_COMMENT": "Edit comment", "EDITED_COMMENT": "Edited:", "SHOW_HISTORY": "View historic", "TYPE_NEW_COMMENT": "Escriu un nou comentari ací", @@ -1148,13 +1166,8 @@ } }, "ACTIVITY": { - "SHOW_ACTIVITY": "Mostrar activitat", - "DATETIME": "DD MMM YYYY HH:mm", - "SHOW_MORE": "+ Mostrar activitat anterior ({{showMore}} més)", "TITLE": "Activitat", "ACTIVITIES_COUNT": "{{activities}} Activities", - "REMOVED": "Borrat", - "ADDED": "Afegit", "TAGS_ADDED": "tags added:", "TAGS_REMOVED": "tags removed:", "US_POINTS": "{{role}} points", @@ -1163,50 +1176,21 @@ "UPDATED_ATTACHMENT": "updated attachment ({{filename}}):", "CREATED_CUSTOM_ATTRIBUTE": "created custom attribute", "UPDATED_CUSTOM_ATTRIBUTE": "updated custom attribute", - "SIZE_CHANGE": "Fet {size, plural, one{un canvi} other{# changes}}", "BECAME_DEPRECATED": "became deprecated", "BECAME_UNDEPRECATED": "became undeprecated", "TEAM_REQUIREMENT": "Requeriment d'equip", "CLIENT_REQUIREMENT": "Requeriment de client", "BLOCKED": "Bloquejat", "VALUES": { - "YES": "si", - "NO": "no", - "EMPTY": "buit", "UNASSIGNED": "Sense assignar" }, "FIELDS": { "SUBJECT": "descripció", - "NAME": "nom", "DESCRIPTION": "descripció", - "CONTENT": "Contingut", "STATUS": "Estats", - "IS_CLOSED": "tancat", - "FINISH_DATE": "Data de finalització", "TYPE": "tipus", - "PRIORITY": "prioritat", - "SEVERITY": "severitat", "ASSIGNED_TO": "Assignat a", - "WATCHERS": "Seguidors", "MILESTONE": "sprint", - "USER_STORY": "història d'usuari", - "PROJECT": "projecte", - "IS_BLOCKED": "Està bloquejat", - "BLOCKED_NOTE": "Nota de bloqueig", - "POINTS": "punts", - "CLIENT_REQUIREMENT": "requeriment de client", - "TEAM_REQUIREMENT": "requeriment d'equip", - "IS_IOCAINE": "Es iocaina", - "TAGS": "Etiquetes", - "ATTACHMENTS": "adjunts", - "IS_DEPRECATED": "és obsolet", - "IS_NOT_DEPRECATED": "is not deprecated", - "ORDER": "ordre", - "BACKLOG_ORDER": "ordre de backlog", - "SPRINT_ORDER": "ordre d'sprint", - "KANBAN_ORDER": "ordre de kanban", - "TASKBOARD_ORDER": "ordre de panell de tasques", - "US_ORDER": "ordre d'US", "COLOR": "color" } }, @@ -1220,8 +1204,6 @@ "CUSTOMIZE_GRAPH_TITLE": "Estableix els punts i els sprints al Admin", "MOVE_US_TO_CURRENT_SPRINT": "Envia al Sprint", "MOVE_US_TO_LATEST_SPRINT": "Posar a l'ultim sprint", - "SHOW_FILTERS": "Mostra filtres", - "SHOW_TAGS": "Mostra etiquetes", "EMPTY": "El backlog està buit!", "CREATE_NEW_US": "Crea una nova US", "CREATE_NEW_US_EMPTY_HELP": "Potser vols crear una nova història d'usuari", @@ -1248,6 +1230,12 @@ "SHOW": "Mostra etiquetes", "HIDE": "Amaga etiquetes" }, + "FORECASTING": { + "TITLE": "Velocity forecasting", + "BACKLOG": "Display backlog", + "NEW_SPRINT": "Candidate User Stories for your next sprint based on your velocity. Click to create a new sprint.", + "CURRENT_SPRINT": "Candidate User Stories for your sprint based on your velocity. Click to add to current sprint." + }, "TABLE": { "COLUMN_US": "Històries d'usuari", "TITLE_COLUMN_POINTS": "Selecciona vista per rol" @@ -1270,8 +1258,6 @@ }, "FILTERS": { "TOGGLE": "Alterna la visibilitat dels filtres", - "TITLE": "Filtres", - "REMOVE": "Esborra filtres", "HIDE": "Amaga filtres", "SHOW": "Mostra filtres" }, @@ -1280,7 +1266,6 @@ "DATE": "DD MMM YYYY", "LINK_TASKBOARD": "Anar al panell de sprint", "TITLE_LINK_TASKBOARD": "Anar al panell de {{::name}}", - "NUMBER_SPRINTS": "
sprints", "EMPTY": "There are no sprints yet", "WARNING_EMPTY_SPRINT_ANONYMOUS": "This sprint has no User Stories", "WARNING_EMPTY_SPRINT": "Drop here Stories from your backlog to start a new sprint", @@ -1305,7 +1290,6 @@ "TITLE_ACTION_ADD": "Afegir nova tasca", "TITLE_ACTION_ADD_BULK": "Afegeix noves històries d'usuari en grup", "TITLE_ACTION_ASSIGN": "Assignar tasca", - "TITLE_ACTION_EDIT": "Editar tasca", "PLACEHOLDER_CARD_TITLE": "Açó podría ser una tasca", "PLACEHOLDER_CARD_TEXT": "Divideix les históries per a poder gertionar-les separadament", "TABLE": { @@ -1335,17 +1319,11 @@ "TITLE_SELECT_STATUS": "Nom de l'estat", "OWNER_US": "Aquesta tasca pertany a", "TITLE_LINK_GO_OWNER": "Anar a història d'usuari", - "ORIGIN_US": "Aquesta tasca ha sigut creada desde", - "TITLE_LINK_GO_ORIGIN": "Anar a història d'usuari", - "BLOCKED": "Aquesta tasca està bloquejada", "TITLE_DELETE_ACTION": "Esborrar tasca", "LIGHTBOX_TITLE_BLOKING_TASK": "Bloquejant tasca", "FIELDS": { - "MILESTONE": "Sprint", - "USER_STORY": "Història d'usuari", "IS_IOCAINE": "Es iocaina" }, - "ACTION_IOCAINE": "Iocaína", "TITLE_ACTION_IOCAINE": "Un poc saturat per una tasca? Fes-ho saber als teus companys clicant a Iocaina quan edites la tasca. Es possible ser inmune a aquesta (fictícia) poció mortal consumint xicotetes dòsis poc a poc, així com es possible millorar amb xicotets nous desafiaments!" }, "NOTIFICATION": { @@ -1374,14 +1352,12 @@ "ISSUES": { "PAGE_TITLE": "Incidències - {{projectName}}", "PAGE_DESCRIPTION": "El panell d'incidències de {{projectName}}: {{projectDescription}}", - "LIST_SECTION_NAME": "Incidències", "SECTION_NAME": "incidència", "ACTION_NEW_ISSUE": "+ NOVA INCIDÈNCIA", "ACTION_PROMOTE_TO_US": "Promocionar història d'usuari", "PROMOTED": "Esta incidència ha sigut promcionada a US:", "EXTERNAL_REFERENCE": "Esta incidència ha sigut creada desde", "GO_TO_EXTERNAL_REFERENCE": "Anar a l'orige", - "BLOCKED": "Aquesta incidència està bloquejada", "ACTION_DELETE": "Esborrar incidència", "LIGHTBOX_TITLE_BLOKING_ISSUE": "Bloquejant incidència", "FIELDS": { @@ -1423,15 +1399,11 @@ "SECTION_NAME": "Kanban", "TITLE_ACTION_FOLD": "Plegar columna", "TITLE_ACTION_UNFOLD": "Desplegar columna", - "TITLE_ACTION_FOLD_CARDS": "Plegar targeta", - "TITLE_ACTION_UNFOLD_CARDS": "Desplegar targetes", "TITLE_ACTION_ADD_US": "Afegeix una nova història d'usuari", "TITLE_ACTION_ADD_BULK": "Afegir en grup", "ACTION_SHOW_ARCHIVED": "Mostrar arxivats", "ACTION_HIDE_ARCHIVED": "Amagar arxivats", "HIDDEN_USER_STORIES": "Les històries d'usuari en aquest estats estan amagades", - "ARCHIVED": "Has arxivat", - "UNDO_ARCHIVED": "Arrastra de nou per desfer", "PLACEHOLDER_CARD_TITLE": "These are your User Stories", "PLACEHOLDER_CARD_TEXT": "Stories might also have subtasks to separate requirements" }, @@ -1452,7 +1424,6 @@ "PAGE_TITLE": "Equip - {{projectName}}", "PAGE_DESCRIPTION": "El panell d'equip mostra tots els membres del projecte {{projectName}}: {{projectDescription}}", "SECTION_NAME": "Equip", - "APP_TITLE": "EQUIP - {{projectName}}", "PLACEHOLDER_INPUT_SEARCH": "Busca per nom complet...", "COLUMN_MR_WOLF": "Mr. Wolf", "EXPLANATION_COLUMN_MR_WOLF": "Incidències tancades", @@ -1488,18 +1459,9 @@ "OPTION_ALL": "Tot", "OPTION_INVOLVED": "Implicat", "OPTION_NONE": "Sense notificacions" - }, - "POPOVER": { - "USER_PROFILE": "Perfil d'usuari", - "CHANGE_PASSWORD": "Canvi de contrasenya", - "NOTIFICATIONS": "Notificacions", - "FEEDBACK": "Suggerències", - "TITLE_AVATAR": "Preferències d'usuari" } }, "USER_PROFILE": { - "IMAGE_HELP": "S'escalarà la imatge a 80x80px.", - "ACTION_CHANGE_IMAGE": "Canviar", "ACTION_USE_GRAVATAR": "Utilitza la imatge per defecte", "ACTION_DELETE_ACCOUNT": "Esborrar compte de Taiga", "CHANGE_EMAIL_SUCCESS": "Mira el teu correu!
Hem enviat un correu al teu conter
amb les instrucciones per a escriure una nova adreça de correu", @@ -1517,25 +1479,10 @@ "THEME_DEFAULT": "-- utilitza el tema per defecte --" } }, - "WIZARD": { - "SECTION_TITLE_CREATE_PROJECT": "Crear projecte", - "CREATE_PROJECT_TEXT": "Nou projecte. Qué il·lusió!", - "CHOOSE_TEMPLATE": "Which template fits your project best?", - "CHOOSE_TEMPLATE_TITLE": "More info about project templates", - "CHOOSE_TEMPLATE_INFO": "More info", - "PROJECT_DETAILS": "Project Details", - "PUBLIC_PROJECT": "Public Project", - "PRIVATE_PROJECT": "Private Project", - "CREATE_PROJECT": "Crear projecte", - "MAX_PRIVATE_PROJECTS": "You've reached the maximum number of private projects", - "MAX_PUBLIC_PROJECTS": "Unfortunately, you've reached the maximum number of public projects", - "CHANGE_PLANS": "change plans" - }, "WIKI": { "PAGE_TITLE": "{{wikiPageName}} - Wiki - {{projectName}}", "PAGE_DESCRIPTION": "Last edition on {{lastModifiedDate}} ({{totalEditions}} editions in total) Content: {{ wikiPageContent }}", "DATETIME": "DD MMM YYYY HH:mm", - "PLACEHOLDER_PAGE": "Esciu pàgina del Wiki", "REMOVE": "Esborrar pàgina de Wiki", "DELETE_LIGHTBOX_TITLE": "Esborrar pàgina de Wiki", "DELETE_LINK_TITLE": "Delete Wiki link", @@ -1693,7 +1640,6 @@ "MOST_LIKED": "Most liked", "MOST_LIKED_EMPTY": "There are no LIKED projects yet", "VIEW_MORE": "View more", - "RECRUITING": "Este projecte busca col·laborados", "FEATURED": "Featured Projects", "EMPTY": "There are no projects to show with this search criteria.
Try again!", "FILTERS": { diff --git a/app/locales/taiga/locale-de.json b/app/locales/taiga/locale-de.json index 00606711..b709615c 100644 --- a/app/locales/taiga/locale-de.json +++ b/app/locales/taiga/locale-de.json @@ -4,14 +4,13 @@ "NO": "Nein", "OR": "oder", "LOADING": "Wird geladen...", - "LOADING_PROJECT": "Projekt wird geladen...", "DATE": "DD. MMM YYYY", "DATETIME": "DD. MMM YYYY HH:mm", "SAVE": "Speichern", "CANCEL": "Abbrechen", "ACCEPT": "Akzeptieren", "DELETE": "Löschen", - "UNLINK": "Unlink", + "UNLINK": "Verknüpfung auflösen", "CREATE": "Erzeugen", "ADD": "Hinzufügen", "COPY_TO_CLIPBOARD": "Ins Clipboard übernehmen: Strg+C", @@ -27,21 +26,18 @@ "BLOCKED_NOTE": "Why is this blocked?", "BLOCKED_REASON": "Bitte erklären Sie den Grund", "CREATED_BY": "Erstellt durch {{fullDisplayName}}", - "FROM": "von", - "TO": "zu", "CLOSE": "schließen", "GO_HOME": "Führe mich heim", "PLUGINS": "Plugins", - "BETA": "Wir sind auf beta!", "ONE_ITEM_LINE": "Ein Eintrag pro Zeile...", "NEW_BULK": "Neue Massenerstellung", "RELATED_TASKS": "Verbundene Aufgaben", - "PREVIOUS": "Previous", + "PREVIOUS": "Zurück", "NEXT": "Weiter", "LOGOUT": "Ausloggen", "EXTERNAL_USER": "ein externer Benutzer", "GENERIC_ERROR": "Eins unserer Helferlein sagt {{error}}.", - "IOCAINE_TEXT": "Fühlen Sie sich von einer Aufgabe etwas erdrückt? Stellen Sie sicher, dass andere davon erfahren, indem Sie auf Locaine klicken, wenn Sie eine Aufgabe ändern. Es ist möglich, gegen dieses (fiktive) tödliche Gift immun zu werden, indem man kleine Mengen über einen Zeitraum hinweg einnimmt. Genauso, wie es möglich ist, besser in dem zu werden, was man tut, indem man gelegentlich zusätzliche Herausforderungen annimmt!", + "IOCAINE_TEXT": "This member is feeling a bit overwhelmed by this task. Will become immune to the iocaine poison over time with your help. For now, may need a hug.", "CLIENT_REQUIREMENT": "Client requirement is new requirement that was not previously expected and it is required to be part of the project", "TEAM_REQUIREMENT": "Team requirement is a requirement that must exist in the project but should have no cost for the client", "OWNER": "Projekteigentümer", @@ -50,8 +46,8 @@ "CONFIRM_CLOSE_EDIT_MODE_MESSAGE": "Beachten Sie, dass alle Änderungen verloren gehen, wenn Sie den Bearbeitungsmodus schließen, ohne vorher zu speichern.", "RELATED_USERSTORIES": "Related user stories", "CARD": { - "ASSIGN_TO": "Assign To", - "EDIT": "Edit card" + "ASSIGN_TO": "Zuweisen an", + "EDIT": "Karte bearbeiten" }, "FORM_ERRORS": { "DEFAULT_MESSAGE": "Dieser Wert scheint ungültig zu sein.", @@ -125,7 +121,7 @@ "ISSUE": "Ticket", "EPIC": "Epic", "TAGS": { - "PLACEHOLDER": "Enter tag", + "PLACEHOLDER": "Gib einen Tag ein", "DELETE": "Schlagwort löschen", "ADD": "Schlagwort hinzufügen" }, @@ -148,7 +144,6 @@ "PRIORITY": "Priorität", "ASSIGNED_TO": "Zugewiesen an", "POINTS": "Punkte", - "BLOCKED_NOTE": "Blockierungsgrund", "IS_BLOCKED": "wird blockiert", "REF": "Ref", "VOTES": "Stimmen", @@ -187,10 +182,6 @@ "COUNTER_TITLE": "{total, plural, one{ein Beobachter} other{# Beobachter}}" }, "VOTE_BUTTON": { - "UPVOTE": "Upvote", - "UPVOTED": "Hochgevotet", - "DOWNVOTE": "Runtergevotet", - "VOTERS": "Voter", "BUTTON_TITLE": "Upvote/Downvote diesen Eintrag", "COUNTER_TITLE": "{total, plural, one{eine Stimme} other{# Stimmen}}" }, @@ -198,18 +189,17 @@ "CUSTOM_FIELDS": "Benutzerdefinierte Felder", "SAVE": "Benutzerdefiniertes Feld speichern", "EDIT": "Benutzerdefiniertes Feld bearbeiten", - "DELETE": "Benutzerattribut löschen", + "DELETE": "benutzerdefiniertes Attribut löschen", "CONFIRM_DELETE": "Alle Werte in benutzerdefinierten Feldern werden gelöscht.\n Sind Sie sicher, dass Sie fortfahren wollen?" }, "FILTERS": { - "TITLE": "Filter", "INPUT_PLACEHOLDER": "Betreff oder Verweis", "TITLE_ACTION_FILTER_BUTTON": "suche", - "INPUT_SEARCH_PLACEHOLDER": "Thema oder ref", + "TITLE": "Filter", "TITLE_ACTION_SEARCH": "Suche", "ACTION_SAVE_CUSTOM_FILTER": "Als Benutzerfilter speichern", "PLACEHOLDER_FILTER_NAME": "Benennen Sie den Filter und drücken Sie die Eingabetaste", - "APPLIED_FILTERS_NUM": "filters applied", + "APPLIED_FILTERS_NUM": "Filter wurden angewandt", "CATEGORIES": { "TYPE": "Arten", "STATUS": "Status", @@ -220,51 +210,20 @@ "CREATED_BY": "Erstellt durch", "CUSTOM_FILTERS": "Benutzerfilter", "EPIC": "Epic" - }, - "CONFIRM_DELETE": { - "TITLE": "Benutzerfilter löschen", - "MESSAGE": "der Benutzerfilter '{{customFilterName}}'" } }, "WYSIWYG": { - "H1_BUTTON": "Überschrift 1", - "H1_SAMPLE_TEXT": "Titel...", - "H2_BUTTON": "Überschrift 2", - "H2_SAMPLE_TEXT": "Titel...", - "H3_BUTTON": "Überschrift 3", - "H3_SAMPLE_TEXT": "Titel...", - "BOLD_BUTTON": "Fettschrift", - "BOLD_BUTTON_SAMPLE_TEXT": "Text...", - "ITALIC_BUTTON": "Kursivschrift", - "ITALIC_SAMPLE_TEXT": "Text...", - "STRIKE_BUTTON": "Treffer", - "STRIKE_SAMPLE_TEXT": "Text...", - "BULLETED_LIST_BUTTON": "Aufzählung", - "BULLETED_LIST_SAMPLE_TEXT": "Text...", - "NUMERIC_LIST_BUTTON": "Numerische Liste", - "NUMERIC_LIST_SAMPLE_TEXT": "Text...", - "PICTURE_BUTTON": "Bild", - "PICTURE_SAMPLE_TEXT": "Alternativtext zum Bild...", - "LINK_BUTTON": "Link", - "LINK_SAMPLE_TEXT": "Linktext...", - "QUOTE_BLOCK_BUTTON": "Blockzitat", - "QUOTE_BLOCK_SAMPLE_TEXT": "Text...", - "CODE_BLOCK_BUTTON": "Kodeblock", - "CODE_BLOCK_SAMPLE_TEXT": "Text...", - "PREVIEW_BUTTON": "Vorschau", - "EDIT_BUTTON": "Bearbeiten", - "ATTACH_FILE_HELP": "Dateien per Drag & Drop auf das obere Textfeld anhängen.", - "ATTACH_FILE_HELP_SAVE_FIRST": "Save first before if you want to attach files by dragging & dropping on the textarea above.", + "OUTDATED": "Another person has made changes while you were editing. Check the new version on the activiy tab before you save your changes.", "MARKDOWN_HELP": "Markdown syntax Hilfe" }, "PERMISIONS_CATEGORIES": { "EPICS": { "NAME": "Epics", - "VIEW_EPICS": "View epics", - "ADD_EPICS": "Add epics", - "MODIFY_EPICS": "Modify epics", - "COMMENT_EPICS": "Comment epics", - "DELETE_EPICS": "Delete epics" + "VIEW_EPICS": "Epics anzeigen", + "ADD_EPICS": "Epics hinzufügen", + "MODIFY_EPICS": "Epics verändern", + "COMMENT_EPICS": "Epics kommentieren", + "DELETE_EPICS": "Epics löschen" }, "SPRINTS": { "NAME": "Sprints", @@ -278,7 +237,7 @@ "VIEW_USER_STORIES": "User-Stories ansehen", "ADD_USER_STORIES": "User-Stories hinzufügen", "MODIFY_USER_STORIES": "User-Stories modifizieren", - "COMMENT_USER_STORIES": "Comment user stories", + "COMMENT_USER_STORIES": "User-Stories kommentieren", "DELETE_USER_STORIES": "User-Stories löschen" }, "TASKS": { @@ -286,7 +245,7 @@ "VIEW_TASKS": "Aufgaben ansehen", "ADD_TASKS": "Aufgaben hinzufügen", "MODIFY_TASKS": "Aufgaben ändern", - "COMMENT_TASKS": "Comment tasks", + "COMMENT_TASKS": "Aufgaben kommentieren", "DELETE_TASKS": "Aufgaben löschen" }, "ISSUES": { @@ -294,7 +253,7 @@ "VIEW_ISSUES": "Tickets ansehen", "ADD_ISSUES": "Tickets hinzufügen", "MODIFY_ISSUES": "Tickets ändern", - "COMMENT_ISSUES": "Comment issues", + "COMMENT_ISSUES": "Tickets kommentieren", "DELETE_ISSUES": "Tickets löschen" }, "WIKI": { @@ -307,10 +266,6 @@ "ADD_WIKI_LINKS": "Wiki Links hinzufügen", "DELETE_WIKI_LINKS": "Wiki Links löschen" } - }, - "META": { - "PAGE_TITLE": "Taiga", - "PAGE_DESCRIPTION": "Taiga ist ein Projekt-Management Plattform für Neugründer und agile Entwickler und Designer, die ein unkompliziertes und ansprechendes Tool möchten, das die Arbeit wirklich angenehm macht." } }, "LOGIN": { @@ -333,7 +288,7 @@ "PLACEHOLDER_AUTH_PASSWORD": "Passwort" }, "LOGIN_FORM": { - "ERROR_AUTH_INCORRECT": "Laut unseren Helferlein ist Dein Benutzername/Deine E-Mail-Adresse oder Dein Passwort nicht korrekt. (Bitte achte auf die Groß- und Kleinschreibung.)", + "ERROR_AUTH_INCORRECT": "Laut unserem Helferlein ist Dein Benutzername/Deine E-Mail-Adresse oder Dein Passwort nicht korrekt. (Bitte achte auf die Groß- und Kleinschreibung.)", "SUCCESS": "Herzlich willkommen bei Taiga, unsere Helferlein freuen sich." }, "REGISTER": { @@ -366,7 +321,6 @@ }, "CHANGE_PASSWORD": { "PAGE_TITLE": "Ändere Dein Passwort - Taiga", - "PAGE_DESCRIPTION": "Setzen Sie ein neues Passwort für Ihr Taiga Benutzerkonto.", "SECTION_NAME": "Passwort ändern", "FIELD_CURRENT_PASSWORD": "Aktuelles Passwort", "PLACEHOLDER_CURRENT_PASSWORD": "Dein aktuelles Passwort (oder leer, wenn Du noch kein Passwort hast)", @@ -383,7 +337,7 @@ "PLACEHOLDER_RE_TYPE_NEW_PASSWORD": "Wiederholen Sie die Eingabe des neuen Passworts", "ACTION_RESET_PASSWORD": "Passwort zurücksetzen", "ERROR": "Unsere Helferelein haben Probleme deine Anfrage zum Zurücksetzen des Passworts zu finden. Probiere es einfach nochmal.", - "SUCCESS": "Unsere Oompa Loompas haben das neue Passwort gespeichert.
Hier gehts zum login." + "SUCCESS": "Unsere Helferlein haben das neue Passwort gespeichert.
Hier gehts zum login." }, "INVITATION": { "PAGE_TITLE": "Einladung Annahme - Taiga", @@ -391,8 +345,7 @@ }, "INVITATION_LOGIN_FORM": { "NOT_FOUND": "Unsere Helferlein können deine Einladung nicht finden.", - "SUCCESS": "Sie sind diesem Projekt erfolgreich beigetreten. Herzlich willkommen bei {{project_name}}", - "ERROR": "Laut unseren Helferlein sind Sie noch nicht registriert, oder Sie haben ein ungültiges Passwort eingegeben." + "SUCCESS": "Sie sind diesem Projekt erfolgreich beigetreten. Herzlich willkommen bei {{project_name}}" }, "HOME": { "PAGE_TITLE": "Home - Taiga", @@ -409,14 +362,14 @@ "SECTION_NAME": "Epics", "EPIC": "EPIC", "PAGE_TITLE": "Epics - {{projectName}}", - "PAGE_DESCRIPTION": "The epics list of the project {{projectName}}: {{projectDescription}}", + "PAGE_DESCRIPTION": "Die Liste der Epics dieses Projekts {{projectName}}: {{projectDescription}}", "DASHBOARD": { "ADD": "+ EPIC HINZUFÜGEN", "UNASSIGNED": "Nicht zugeordnet" }, "EMPTY": { - "TITLE": "It looks like there aren't any epics yet", - "EXPLANATION": "Epics are items at a higher level that encompass user stories.
Epics are at the top of the hierarchy and can be used to group user stories together.", + "TITLE": "Es sind noch keine Epics vorhanden", + "EXPLANATION": "Epics sind Elemente, die User-Stories umfassen.
Sie stehen dabei an oberster Stelle in der Hierarchie und können dazu verwendet werden, User-Stories zu gruppieren.", "HELP": "Erfahren Sie mehr über Epics" }, "TABLE": { @@ -427,11 +380,11 @@ "ASSIGNED_TO": "Zugewiesen", "STATUS": "Status", "PROGRESS": "Fortschritt", - "VIEW_OPTIONS": "View options" + "VIEW_OPTIONS": "Zeige Optionen" }, "CREATE": { "TITLE": "Neues Epic", - "PLACEHOLDER_DESCRIPTION": "Please add descriptive text to help others better understand this epic", + "PLACEHOLDER_DESCRIPTION": "Bitte beschreiben Sie dieses Epic zum leichteren Verständnis", "TEAM_REQUIREMENT": "Team-Anforderung", "CLIENT_REQUIREMENT": "Kunden-Anforderung", "BLOCKED": "Blockiert", @@ -463,10 +416,7 @@ "TITLE_LIGHTBOX_DELETE_ATTACHMENT": "Anhang löschen...", "MSG_LIGHTBOX_DELETE_ATTACHMENT": "der Anhang '{{fileName}}'", "ERROR_DELETE_ATTACHMENT": "Es war uns nicht möglich, zu löschen: {{errorMessage}}", - "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) ist zu schwierig für unsere Helferlein, versuchen Sie es bitte mit einer kleineren Datei als ({{maxFileSize}})", - "FIELDS": { - "IS_DEPRECATED": "ist verworfen" - } + "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) ist zu schwierig für unsere Helferlein, versuchen Sie es bitte mit einer kleineren Datei als ({{maxFileSize}})" }, "PAGINATION": { "PREVIOUS": "Zurück", @@ -502,16 +452,13 @@ "ASYNC_MESSAGE": "Wir werden nach Fertigstellung eine E-Mail senden.", "SYNC_MESSAGE": "Wenn der Download nicht automatisch startet, klicken Sie hier.", "ERROR": "Unsere Helferlein haben Probleme, Ihre Export-Datei zu erzeugen. Bitte versuchen Sie es erneut.", - "ERROR_BUSY": "Entschuldigung, unsere Helferlein sind zur Zeit sehr beschäftigt. Bitte versuchen Sie es in ein paar Minuten erneut.", - "ERROR_MESSAGE": "Unsere Helferlein haben Probleme, Ihre Export-Datei zu erstellen: {{message}}" + "ERROR_BUSY": "Entschuldigung, unsere Helferlein sind zur Zeit sehr beschäftigt. Bitte versuchen Sie es in ein paar Minuten erneut." }, "MODULES": { "TITLE": "Module", - "ENABLE": "Aktivieren", - "DISABLE": "Deaktivieren", "EPICS": "Epics", "EPICS_DESCRIPTION": "Visualisieren und verwalten Sie den strategischsten Teil Ihres Projektes", - "BACKLOG": "Auftragsliste", + "BACKLOG": "Backlog", "BACKLOG_DESCRIPTION": "Verwalten Sie Ihre User-Stories, um einen organisierten Überblick der anstehenden und priorisierten Aufgaben zu erhalten.", "NUMBER_SPRINTS": "Erwartete Anzahl an Sprints", "NUMBER_SPRINTS_HELP": "0 für eine unbestimmte Anzahl", @@ -537,17 +484,16 @@ "PAGE_TITLE": "{{sectionName}} - Projekt Profil - {{projectName}}", "PROJECT_DETAILS": "Projekt Details", "PROJECT_NAME": "Projektname", - "PROJECT_SLUG": "Projekt Slug", "TAGS": "Schlagwörter", "DESCRIPTION": "Beschreibung", "RECRUITING": "Is this project looking for people?", - "RECRUITING_MESSAGE": "Who are you looking for?", + "RECRUITING_MESSAGE": "Wen suchst du denn?", "RECRUITING_PLACEHOLDER": "Define the profiles you are looking for", + "FEEDBACK": "Receive feedback from Taiga users?", "PUBLIC_PROJECT": "Öffentliches Projekt", "PRIVATE_PROJECT": "Privates Projekt", "PRIVATE_OR_PUBLIC": "Was ist der Unterschied zwischen öffentlichen und privaten Projekten?", "DELETE": "Dieses Projekt löschen", - "LOGO_HELP": "Das Bild wird auf 80x80px skaliert.", "CHANGE_LOGO": "Logo ändern", "ACTION_USE_DEFAULT_LOGO": "Nutze Standardbild", "MAX_PRIVATE_PROJECTS": "Sie haben die maximale Anzahl privater Projekte erreicht, die in Ihrem derzeitigen Plan erlaubt sind", @@ -573,7 +519,7 @@ "REGENERATE_SUBTITLE": "Sie sind im Begriff, die CSV data access URL zu ändern. Die vorherige URL wird deaktiviert. Sind Sie sicher?" }, "CSV": { - "SECTION_TITLE_EPIC": "epics reports", + "SECTION_TITLE_EPIC": "Epics Berichte", "SECTION_TITLE_US": "User-Stories Berichte", "SECTION_TITLE_TASK": "Aufgabenberichte", "SECTION_TITLE_ISSUE": "Ticket Berichte", @@ -586,8 +532,8 @@ "CUSTOM_FIELDS": { "TITLE": "Benutzerfelder", "SUBTITLE": "Spezifizieren Sie die Benutzerfelder für Ihre User-Stories, Aufgaben und Tickets.", - "EPIC_DESCRIPTION": "Epics custom fields", - "EPIC_ADD": "Add a custom field in epics", + "EPIC_DESCRIPTION": "Benutzerdefinierte Felder der Epics", + "EPIC_ADD": "Benutzerdefiniertes Feld bei Epics hinzufügen", "US_DESCRIPTION": "Benutzerdefinierte Felder der User-Story", "US_ADD": "Benutzerdefiniertes Feld bei User-Stories hinzufügen", "TASK_DESCRIPTION": "Aufgaben benutzerdefinierte Felder", @@ -595,6 +541,7 @@ "ISSUE_DESCRIPTION": "Tickets benutzerdefinierte Felder", "ISSUE_ADD": "Fügen Sie den Tickets ein benutzerdefiniertes Feld hinzu", "FIELD_TYPE_TEXT": "Text", + "FIELD_TYPE_RICHTEXT": "Rich text", "FIELD_TYPE_MULTI": "Mehrzeilig", "FIELD_TYPE_DATE": "Datum", "FIELD_TYPE_URL": "Url" @@ -623,10 +570,10 @@ "ACTION_ADD": "Neue Gewichtung hinzufügen" }, "PROJECT_VALUES_STATUS": { - "TITLE": "Status", + "TITLE": "Statuses", "SUBTITLE": "Spezifizieren Sie die Status, die Ihre User-Stories, Aufgaben und Tickets durchlaufen werden.", - "EPIC_TITLE": "Epic Statuses", - "US_TITLE": "User Story Statuses", + "EPIC_TITLE": "Epic Status", + "US_TITLE": "User-Story Status", "TASK_TITLE": "Aufgaben-Status", "ISSUE_TITLE": "Ticket-Status" }, @@ -639,13 +586,13 @@ "PROJECT_VALUES_TAGS": { "TITLE": "Schlagwörter", "SUBTITLE": "View and edit the color of your tags", - "EMPTY": "Currently there are no tags", + "EMPTY": "Zur Zeit sind keine Tags vorhanden", "EMPTY_SEARCH": "Es sieht so aus, als konnte zu Ihren Suchkriterien nichts passendes gefunden werden.", "ACTION_ADD": "Schlagwort hinzufügen", - "NEW_TAG": "New tag", - "MIXING_HELP_TEXT": "Select the tags that you want to merge", - "MIXING_MERGE": "Merge Tags", - "SELECTED": "Selected" + "NEW_TAG": "Neuer Tag", + "MIXING_HELP_TEXT": "Wähle die Tags aus, die zu zusammenführen willst", + "MIXING_MERGE": "Tags zusammenführen", + "SELECTED": "Ausgewählt" }, "ROLES": { "PAGE_TITLE": "Rollen - {{projectName}}", @@ -676,8 +623,8 @@ "INFO_VERIFYING_IP": "Gitlab rAnfragen sind nicht signiert, daher ist der beste Weg die Quelle anhand der IP zu prüfen. Wenn das Feld leer bleibt, wird keine Prüfung der IP vorgenommen." }, "GITHUB": { - "SECTION_NAME": "Github", - "PAGE_TITLE": "Github - {{projectName}}" + "SECTION_NAME": "GitHub", + "PAGE_TITLE": "GitHub - {{projectName}}" }, "GOGS": { "SECTION_NAME": "Gogs", @@ -686,7 +633,6 @@ "WEBHOOKS": { "PAGE_TITLE": "Webhooks - {{projectName}}", "SECTION_NAME": "Webhooks", - "SUBTITLE": "Webhooks meldet externe Dienste über Ereignisse in Taiga, wie Kommentare, User-Stories...", "ADD_NEW": "Fügen Sie ein neues Webhook hinzu", "TYPE_NAME": "Servicename...", "TYPE_PAYLOAD_URL": "Geben Sie die Service Payload URL ein", @@ -732,7 +678,6 @@ "DELETE_MEMBER": "Mitglied löschen", "RESEND": "Neu senden", "SUCCESS_SEND_INVITATION": "Wir haben die Einladung erneut versandt an '{{email}}'.", - "ERROR_SEND_INVITATION": "Wir haben die Einladung nicht versandt.", "SUCCESS_DELETE": "Gelöscht {{message}}.", "ERROR_DELETE": "Das Löschen ist fehlgeschlagen {{message}}.", "DEFAULT_DELETE_MESSAGE": "die Einladung an {{email}}" @@ -761,16 +706,11 @@ "PLACEHOLDER_WRITE_NAME": "Benennen Sie den neuen Status" }, "MENU": { - "TITLE": "Administrator", "PROJECT": "Projekt", "ATTRIBUTES": "Attribute", "MEMBERS": "Mitglieder", "PERMISSIONS": "Berechtigungen", - "INTEGRATIONS": "Integrationen", - "PLUGINS": "Plugins" - }, - "SUBMENU_PROJECT_ATTRIBUTES": { - "TITLE": "Attribute" + "INTEGRATIONS": "Integrationen" }, "SUBMENU_PROJECT_VALUES": { "STATUS": "Status", @@ -781,17 +721,11 @@ "CUSTOM_FIELDS": "Benutzerdefinierte Felder", "TAGS": "Schlagwörter" }, - "SUBMENU_PROJECT_PROFILE": { - "TITLE": "Projektprofil" - }, "SUBMENU_ROLES": { "TITLE": "Rollen", "ACTION_NEW_ROLE": "+ Neue Rolle", "TITLE_ACTION_NEW_ROLE": "Neue Rolle hinzufügen" }, - "SUBMENU_THIDPARTIES": { - "TITLE": "Dienste" - }, "PROJECT_TRANSFER": { "DO_YOU_ACCEPT_PROJECT_OWNERNSHIP": "Möchten Sie der neue Projektleiter werden?", "PRIVATE": "Privat", @@ -806,15 +740,13 @@ "PRIVATE": "Bitte denken Sie daran, dass Sie bis zu {{maxProjects}} private Projekte besitzen können. Dezeit besitzen Sie {{currentProjects}} private Projekte", "PUBLIC": "Bitte denken Sie daran, dass Sie bis zu {{maxProjects}} öffentliche Projekte besitzen können. Dezeit besitzen Sie {{currentProjects}} öffentliche Projekte" }, - "CANT_BE_OWNED": "Zur Zeit können Sie kein Projektleiter für diesen Projekt-Typ werden werden. Wenn Sie Projektleiter für dieses Projekt werden möchten, kontaktieren Sie bitte den Administrator, damit er Ihre Benutzerkonto-Einstellungen anpassen kann, um Projektleiter werden zu können.", - "CHANGE_MY_PLAN": "Meinen Plan ändern" + "CANT_BE_OWNED": "Zur Zeit können Sie kein Projektleiter für diesen Projekt-Typ werden werden. Wenn Sie Projektleiter für dieses Projekt werden möchten, kontaktieren Sie bitte den Administrator, damit er Ihre Benutzerkonto-Einstellungen anpassen kann, um Projektleiter werden zu können." } }, "USER": { "PROFILE": { "PAGE_TITLE": "{{userFullName}} (@{{userUsername}})", "EDIT": "Profil ändern", - "FOLLOW": "Folgen", "CLOSED_US": "Geschlossene User-Story", "PROJECTS": "Projekte", "PROJECTS_EMPTY": "{{username}} besitzt noch keine Projekte", @@ -822,7 +754,6 @@ "CONTACTS_EMPTY": "{{username}} hat noch keine Kontakte", "CURRENT_USER_CONTACTS_EMPTY": "Sie haben noch keine Kontakte", "CURRENT_USER_CONTACTS_EMPTY_EXPLAIN": "Die Leute, mit denen Sie auf Taiga zusammenarbeiten, werden automatisch zu Ihren Kontakten", - "REPORT": "Missbrauch melden", "TABS": { "ACTIVITY_TAB": "Zeitlinie", "ACTIVITY_TAB_TITLE": "Alle Aktivitäten dieses Benutzers anzeigen", @@ -848,13 +779,13 @@ "FILTER_TYPE_ALL": "Alle", "FILTER_TYPE_ALL_TITLE": "Alle anzeigen", "FILTER_TYPE_PROJECTS": "Projekte", - "FILTER_TYPE_PROJECT_TITLES": "Nur Projekte anzeigen", + "FILTER_TYPE_PROJECTS_TITLE": "Nur Projekte anzeigen", "FILTER_TYPE_EPICS": "Epics", - "FILTER_TYPE_EPIC_TITLES": "Show only epics", + "FILTER_TYPE_EPICS_TITLE": "Nur Epics anzeigen", "FILTER_TYPE_USER_STORIES": "Stories", - "FILTER_TYPE_USER_STORIES_TITLES": "Nur User-Stories anzeigen", + "FILTER_TYPE_USER_STORIES_TITLE": "Nur User-Stories anzeigen", "FILTER_TYPE_TASKS": "Aufgaben", - "FILTER_TYPE_TASK_TITLES": "Zeige nur Tasks", + "FILTER_TYPE_TASKS_TITLE": "Zeige nur Tasks", "FILTER_TYPE_ISSUES": "Tickets", "FILTER_TYPE_ISSUES_TITLE": "Nur Fehler anzeigen", "EMPTY_TITLE": "Es sieht so aus, als wäre hier nichts." @@ -862,8 +793,6 @@ }, "PROJECT": { "PAGE_TITLE": "{{projectName}}", - "WELCOME": "Willkommen", - "SECTION_PROJECTS": "Projekte", "HELP": "Sortieren Sie Ihre Projekte nach Wichtigkeit.
Die ersten 10 Projekte erscheinen prominent in der Projektliste der Navigationsleiste.", "PRIVATE": "Privates Projekt", "LOOKING_FOR_PEOPLE": "Dieses Projekt sucht nach Mitarbeitern", @@ -875,16 +804,10 @@ "THIS_PROJECT_IS_BLOCKED": "Dieses Projekt ist vorrübergehend blockiert", "TO_UNBLOCK_CONTACT_THE_ADMIN_STAFF": "Um dein Projekt zu entsperren kontaktiere bitte einen Administrator." }, - "STATS": { - "PROJECT": "Projekt
Punkte", - "DEFINED": "definierte
Punkte", - "ASSIGNED": "zugewiesene
Punkte", - "CLOSED": "geschlossene
Punkte" - }, "SECTION": { "SEARCH": "Suche", "TIMELINE": "Zeitlinie", - "BACKLOG": "Auftragsliste", + "BACKLOG": "Backlog", "KANBAN": "Kanban", "ISSUES": "Tickets", "WIKI": "Wiki", @@ -893,15 +816,9 @@ "ADMIN": "Administrator" }, "NAVIGATION": { - "SECTION_TITLE": "Ihre Projekte", - "PLACEHOLDER_SEARCH": "Suchen...", "ACTION_CREATE_PROJECT": "Projekt anlegen", - "ACTION_IMPORT_PROJECT": "Projekt importieren", "MANAGE_PROJECTS": "Projekte verwalten", "TITLE_CREATE_PROJECT": "Projekt anlegen", - "TITLE_IMPORT_PROJECT": "Projekt importieren", - "TITLE_PRVIOUS_PROJECT": "Frühere Projekte anzeigen", - "TITLE_NEXT_PROJECT": "Weitere Projekte zeigen", "HELP_TITLE": "Taiga Support Seite", "HELP": "Hilfe", "HOMEPAGE": "Homepage", @@ -909,10 +826,6 @@ "FEEDBACK": "Feedback", "NOTIFICATIONS_TITLE": "Benachrichtigungseinstellungen bearbeiten", "NOTIFICATIONS": "Benachrichtigungen", - "ORGANIZATIONS_TITLE": "Organisationen bearbeiten", - "ORGANIZATIONS": "Organisationen bearbeiten", - "SETTINGS_TITLE": "Einstellungen bearbeiten", - "SETTINGS": "Einstellungen", "VIEW_PROFILE_TITLE": "Profil ansehen", "VIEW_PROFILE": "Profil ansehen", "EDIT_PROFILE_TITLE": "Bearbeiten Sie Ihr Profil", @@ -921,24 +834,99 @@ "CHANGE_PASSWORD": "Passwort ändern", "DASHBOARD_TITLE": "Dashboard", "DISCOVER_TITLE": "Entdecke aktuelle Projekte", - "NEW_ITEM": "Neu", - "DISCOVER": "Entdecken", - "ACTION_REORDER": "Benutzen Sie Drag & Drop zum neuen Ordnen" + "DISCOVER": "Entdecken" + }, + "LIKE_BUTTON": { + "LIKE": "Gefällt mir", + "LIKED": "Gefällt mir", + "UNLIKE": "Gefällt mir nicht mehr", + "BUTTON_TITLE": "Like oder Unlike dieses Projekt", + "COUNTER_TITLE": "{total, plural, one{ein Fan} other{# Fans}}" + }, + "WATCH_BUTTON": { + "BUTTON_TITLE": "Beobachte dieses Projekt und setze Benachrichtigungsregeln", + "WATCH": "Beobachten", + "WATCHING": "Beobachtet", + "COUNTER_TITLE": "{total, plural, one{ein Beobachter} other{# Beobachter}}", + "OPTIONS": { + "NOTIFY_ALL": "Alle Benachrichtigungen empfangen", + "NOTIFY_ALL_TITLE": "Alle Benachrichtigungen für dieses Projekt anzeigen", + "NOTIFY_INVOLVED": "Nur Beteiligte", + "NOTIFY_INVOLVED_TITLE": "Erhalte Benachrichtigungen wenn du involviert bist", + "UNWATCH": "Nicht beobachten", + "UNWATCH_TITLE": "Nicht beobachten" + } + }, + "CONTACT_BUTTON": { + "CONTACT_TITLE": "Contact the project team", + "CONTACT_BUTTON": "Contact the project" + }, + "CREATE": { + "TITLE": "Projekt erstellen", + "CHOOSE_TEMPLATE": "Which template fits your project better?", + "TEMPLATE_SCRUM": "Scrum", + "TEMPLATE_SCRUM_DESC": "Prioritize and solve your tasks in short time cycles.", + "TEMPLATE_SCRUM_LONGDESC": "Scrum is an iterative and incremental agile software development methodology for managing product development.\nThe product backlog is what will ultimately be delivered, ordered into the sequence in which it should be delivered. Product Backlogs are broken into manageable, executable chunks named sprints. Every certain amount of time the team initiates a new sprint and commits to deliver a certain number of user stories from the backlog, in accordance with their skills, abilities and resources. The project advances as the backlog becomes depleted.", + "TEMPLATE_KANBAN": "Kanban", + "TEMPLATE_KANBAN_DESC": "Keep a constant workflow on independent tasks", + "TEMPLATE_KANBAN_LONGDESC": "The Kanban methodology is used to divide project development (any sort of project) into stages.\nA kanban card is like an index card or post-it note that details every task (or user story) in a project that needs to be completed. The Kanban board is used to move each card from one state of completion to the next and in so doing, helps track progress.", + "DUPLICATE": "Duplicate project", + "DUPLICATE_DESC": "Start clean and keep your configuration", + "IMPORT": "Projekt importieren", + "IMPORT_DESC": "Import your project from multiple platforms into Taiga", + "INVITE": "Invite to the project", + "SOLO_PROJECT": "You'll be alone in this project", + "INVITE_LATER": "(You'll be able to invite more members later)", + "BACK": "Zurück", + "MAX_PRIVATE_PROJECTS": "Unfortunately, You've reached the maximum number of private projects.\nIf you would like to increase the current limit please contact the administrator.", + "MAX_PUBLIC_PROJECTS": "Unfortunately, You've reached the maximum number of public projects.\nIf you would like to increase the current limit please contact the administrator.", + "PUBLIC_PROJECT": "Öffentliches Projekt", + "PRIVATE_PROJECT": "Privates Projekt" + }, + "COMMON": { + "DETAILS": "New project details", + "PROJECT_TITLE": "Project Name", + "PROJECT_DESCRIPTION": "Project Description" + }, + "DUPLICATE": { + "TITLE": "Duplicate Project", + "DESCRIPTION": "Start clean and keep your configuration", + "SELECT_PLACEHOLDER": "Choose an existing project to duplicate" }, "IMPORT": { - "TITLE": "Projekt importieren", - "UPLOADING_FILE": "Exportdatei wird hochgeladen", - "DESCRIPTION": "Dieser Vorgang kann etwas dauern. Bitte schliessen Sie das Fenster nicht!", + "TITLE": "Import Project", + "DESCRIPTION": "Import your project from multiple platforms into Taiga", "ASYNC_IN_PROGRESS_TITLE": "Unsere Helferlein importieren Ihr Projekt", "ASYNC_IN_PROGRESS_MESSAGE": "Dieser Vorgang könnte ein paar Minuten benötigen
Nach Fertigstellung benachrichtigen wir Sie per E-Mail.", "UPLOAD_IN_PROGRESS_MESSAGE": "Hochgeladen {{uploadedSize}} von {{totalSize}}", "ERROR": "Unsere Helferlein haben Probleme beim Importieren Ihrer Daten. Bitte versuchen Sie es erneut.", - "ERROR_TOO_MANY_REQUEST": "Entschuldigung, unsere Helferlein sind derzeit sehr beschäftigt. Bitte versuchen Sie es in ein paar Minuten erneut.", + "ERROR_TOO_MANY_REQUEST": "Entschuldigung, unsere Helferlein sind zur Zeit sehr beschäftigt. Bitte versuchen Sie es in ein paar Minuten erneut.", "ERROR_MESSAGE": "Unsere Helferlein haben Probleme beim Importieren Ihrer Datei: {{error_message}}", "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) ist zu schwierig für unsere Helferlein, versuchen Sie es bitte mit einer kleineren Datei als ({{maxFileSize}})", "SYNC_SUCCESS": "Ihr Projekt wurde erfolgreich importiert", + "IMPORT": "Import", + "WHO_IS": "Their tasks will be assigned to ...", + "WRITE_EMAIL": "Or if you want, write the email that this user uses in Taiga", + "SEARCH_CONTACT": "Or if you want, search in your contacts", + "WRITE_EMAIL_LABEL": "Write the email that this user uses in Taiga", + "ACCEEDE": "Acceede", + "PROJECT_MEMBERS": "Projektmitglieder", + "PROCESS_DESCRIPTION": "Tell us who from Taiga you want to assign the tasks of {{platform}}", + "MATCH": "Is {{user_external}} the same person as {{user_internal}}?", + "CHOOSE": "Select user", + "LINKS": "Links with {{platform}}", + "LINKS_DESCRIPTION": "Do you want to keep the link of each item with the original {{platform}} card?", + "WARNING_MAIL_USER": "Note that if the user does not have a Taiga account we will not be able to assign the tasks to him.", + "ASSIGN": "Zuweisen", + "PROJECT_SELECTOR": { + "NO_RESULTS": "Es sieht so aus, als konnte zu Ihren Suchkriterien nichts passendes gefunden werden.", + "ACTION_SEARCH": "suche", + "ACTION_BACK": "Zurück" + }, "PROJECT_RESTRICTIONS": { - "PROJECT_MEMBERS_DESC": "Das Projekt, dass Sie importieren möchten, hat {{members}} Mitglieder. Leider erlaubt ihr derzeitiger Plan nicht mehr als {{max_memberships}} Mitglieder pro Projekt. Wenn Sie diese Grenze erhöhen möchten, kontaktieren Sie bitte den Administrator.", + "PROJECT_MEMBERS_DESC_PRIVATE": "The project you are trying to import has {{members}} members including you, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per private project. If you would like to increase that limit please contact the administrator.", + "PROJECT_MEMBERS_DESC_PUBLIC": "The project you are trying to import has {{members}} members including you, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per public project. If you would like to increase that limit please contact the administrator.", + "ACCOUNT_ALLOW_MEMBERS": "Your account only allows {{members}} members", "PRIVATE_PROJECTS_SPACE": { "TITLE": "Leider erlaubt Ihr derzeitiger Plan keine weiteren privaten Projekte anzulegen.", "DESC": "Das Projekt, das Sie versuchen zu importieren, ist privat. Leider erlaubt Ihr derzeitiger Plan keine weiteren privaten Projekte hinzuzufügen." @@ -961,39 +949,67 @@ "TITLE": "Leider erlaubt Ihr derzeitiger Plan keine weiteren öffentlichen Projekte anzulegen oder eine Erhöhung von mehr als {{max_memberships}} Mitglieder pro öffentlichem Projekt", "DESC": "Das Projekt, dass Sie importieren möchten, ist öffentlich und hat mehr als {{members}} Mitglieder." } - } - }, - "LIKE_BUTTON": { - "LIKE": "Gefällt mir", - "LIKED": "Gefällt mir", - "UNLIKE": "Gefällt mir nicht mehr", - "BUTTON_TITLE": "Like oder Unlike dieses Projekt", - "COUNTER_TITLE": "{total, plural, one{ein Fan} other{# Fans}}" - }, - "WATCH_BUTTON": { - "BUTTON_TITLE": "Beobachte dieses Projekt und setze Benachrichtigungsregeln", - "WATCH": "Beobachten", - "WATCHING": "Beobachtet", - "COUNTER_TITLE": "{total, plural, one{ein Beobachter} other{# Beobachter}}", - "OPTIONS": { - "NOTIFY_ALL": "Alle Benachrichtigungen empfangen", - "NOTIFY_ALL_TITLE": "Alle Benachrichtigungen für dieses Projekt anzeigen", - "NOTIFY_INVOLVED": "Nur Beteiligte", - "NOTIFY_INVOLVED_TITLE": "Erhalte Benachrichtigungen wenn du involviert bist", - "UNWATCH": "Nicht beobachten", - "UNWATCH_TITLE": "Nicht beobachten" + }, + "IN_PROGRESS": { + "TITLE": "Projekt importieren", + "DESCRIPTION": "Dieser Vorgang kann etwas dauern. Bitte schliessen Sie das Fenster nicht!" + }, + "WARNING": { + "TITLE": "Some taks will be unassigned", + "DESCRIPTION": "There are still unidentified people. The cards assigned to these people will remain unassigned. Check all the contacts to not lose that information.", + "CHECK": "Check contacts" + }, + "TAIGA": { + "SELECTOR": "Import your Taiga project" + }, + "TRELLO": { + "SELECTOR": "Import your Trello boards into Taiga", + "CHOOSE_PROJECT": "Choose board that you want to import", + "NO_PROJECTS": "It seems you have no boards in Trello" + }, + "GITHUB": { + "SELECTOR": "Import your GitHub project issues", + "CHOOSE_PROJECT": "Find the project you want to import", + "NO_PROJECTS": "It seems you have no porjects in GitHub", + "HOW_DO_YOU_WANT_TO_IMPORT": "How do you want to import your issues into Taiga?", + "KANBAN_PROJECT": "As user stories in a kanban project", + "KANBAN_PROJECT_DESCRIPTION": "After that you can enable scrum with backlog.", + "SCRUM_PROJECT": "As user stories in a scrum project", + "SCRUM_PROJECT_DESCRIPTION": "After that you can enable kanban mode.", + "ISSUES_PROJECT": "As issues", + "ISSUES_PROJECT_DESCRIPTION": "You will not be able to use your issues in kanban or scrum mode. You will be able to enable kanban or scrum for new user stories" + }, + "ASANA": { + "SELECTOR": "Import your Asana project and choose how to manage it", + "CHOOSE_PROJECT": "Choose project that you want to import", + "NO_PROJECTS": "It seems you have no porjects in Asana", + "KANBAN_PROJECT": "Kanban", + "SCRUM_PROJECT": "Scrum", + "CREATE_AS_SCRUM_DESCRIPTION": "The tasks and sub-tasks of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_KANBAN_DESCRIPTION": "The tasks and sub-tasks of your project will be created as Taiga user stories and tasks." + }, + "JIRA": { + "SELECTOR": "Import your Jira project and choose how to manage it", + "CHOOSE_PROJECT": "Choose project or board that you want to import", + "NO_PROJECTS": "It seems you have no porjects or boards in Jira", + "URL": "Your Jira URL", + "KANBAN_PROJECT": "Kanban", + "SCRUM_PROJECT": "Scrum", + "ISSUES_PROJECT": "Tickets", + "CREATE_AS_SCRUM_DESCRIPTION": "The issues and sub-issues of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_KANBAN_DESCRIPTION": "The issues and sub-issues of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_ISSUES_DESCRIPTION": "What do you want to do with sub-issues from the Jira project? (Taiga doesn't allow sub-issues)", + "CREATE_NEW_ISSUES": "Convert sub-issues to new Taiga issues", + "NOT_CREATE_NEW_ISSUES": "Do not import sub-issues" } } }, "LIGHTBOX": { "DELETE_ACCOUNT": { - "SECTION_NAME": "Dein Taiga Benutzerkonto löschen", "CONFIRM": "Sind Sie sicher, dass Sie Ihr Taiga Benutzerkonto löschen wollen?", - "NEWSLETTER_LABEL_TEXT": "Ich möchte keinen Newsletter mehr erhalten", "CANCEL": "Zurück zu Einstellungen", "ACCEPT": "Benutzerkonto löschen", - "BLOCK_PROJECT": "Beachten Sie, dass alle Projekte die Sie besitzen, gesperrt werden, nachdem Sie Ihr Konto gelöscht haben. Wenn Sie möchten, dass Ihre Projekte nicht gesperrt werden, ernennen Sie ein anderes Mitglied zum Projektleiter für jedes Projekt, bevor Sie Ihr Konto löschen.", - "SUBTITLE": "Schade, dass du uns verlassen willst. Wir sind hier, falls du uns nochmal suchst. :(" + "BLOCK_PROJECT": "Beachten Sie, dass alle Projekte die Sie besitzen, gesperrt werden, nachdem Sie Ihr Konto gelöscht haben. Wenn Sie möchten, dass Ihre Projekte nicht gesperrt werden, ernennen Sie ein anderes Mitglied zum Projektleiter für jedes Projekt, bevor Sie Ihr Konto löschen." }, "DELETE_PROJECT": { "TITLE": "Projekt löschen", @@ -1007,6 +1023,12 @@ }, "ADD_MEMBER": { "TITLE": "Neues Mitglied", + "PLACEHOLDER": "Filter users or write an email to invite", + "ADD_EMAIL": "Add email", + "REMOVE": "Remove", + "INVITE": "Invite", + "CHOOSE_ROLE": "Choose a role", + "PLACEHOLDER_INVITATION_TEXT": "(Optional) Fügen Sie einen persönlichen Text zur Einladung hinzu. Erzählen Sie Ihren neuen Mitgliedern etwas Schönes. ;-)", "HELP_TEXT": "Wenn Benutzer schon bei Taiga registriert sind, werden diese automatisch hinzugefügt. Ansonsten erhalten sie eine Einladung." }, "CREATE_ISSUE": { @@ -1050,8 +1072,8 @@ "CREATE_MEMBER": { "PLACEHOLDER_INVITATION_TEXT": "(Optional) Fügen Sie einen persönlichen Text zur Einladung hinzu. Erzählen Sie Ihren neuen Mitgliedern etwas Schönes. ;-)", "PLACEHOLDER_TYPE_EMAIL": "Geben Sie eine E-Mail ein", - "LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "You are about to reach the maximum number of members allowed for this project, {{maxMembers}} members. If you would like to increase the current limit, please contact the administrator.", - "LIMIT_USERS_WARNING_MESSAGE": "You are about to reach the maximum number of members allowed for this project, {{maxMembers}} members." + "LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "Dieses Projekt erreicht bald die maximale Anzahl von {{maxMembers}} Mitgliedern. Wenn Sie diese Grenze erhöhen möchten, kontaktieren Sie bitte den Administrator.", + "LIMIT_USERS_WARNING_MESSAGE": "Dieses Projekt erreicht bald die maximale Anzahl von {{maxMembers}} Mitgliedern." }, "LEAVE_PROJECT_WARNING": { "TITLE": "Das Projekt kann nicht ohne einen Projektleiter existieren.", @@ -1068,27 +1090,33 @@ "TITLE": "Wen möchtest du zum neuen Projektleiter ernennen?", "ADD_COMMENT": "Kommentar hinzufügen", "BUTTON": "Fragen Sie dieses Projektmitglied, um Projektleiter zu werden" + }, + "CONTACT_PROJECT": { + "TITLE": "Send an email to", + "WARNING": "The email will be received by the project admins", + "PLACEHOLDER": "Write your message", + "SEND": "Send" } }, "EPIC": { "PAGE_TITLE": "{{epicSubject}} - Epic {{epicRef}} - {{projectName}}", - "PAGE_DESCRIPTION": "Status: {{epicStatus }}. Description: {{epicDescription}}", + "PAGE_DESCRIPTION": "Status: {{epicStatus }}. Beschreibung: {{epicDescription}}", "SECTION_NAME": "Epic", - "TITLE_LIGHTBOX_UNLINK_RELATED_USERSTORY": "Unlink related userstory", - "MSG_LIGHTBOX_UNLINK_RELATED_USERSTORY": "It will delete the link to the related userstory '{{subject}}'", - "ERROR_UNLINK_RELATED_USERSTORY": "We have not been able to unlink: {{errorMessage}}", + "TITLE_LIGHTBOX_UNLINK_RELATED_USERSTORY": "Verknüpfung zur zugehören User-Story lösen", + "MSG_LIGHTBOX_UNLINK_RELATED_USERSTORY": "Dies wird die Verknüpfung zur zugehörigen User-Story '{{subject}}' löschen", + "ERROR_UNLINK_RELATED_USERSTORY": "Die Verknüpfung konnte nicht gelöscht werden: {{errorMessage}}", "CREATE_RELATED_USERSTORIES": "Create a relationship with", "NEW_USERSTORY": "Neue User-Story", - "EXISTING_USERSTORY": "Existing user story", + "EXISTING_USERSTORY": "Bestehende User-Story", "CHOOSE_PROJECT_FOR_CREATION": "What's the project?", "SUBJECT": "Thema", "SUBJECT_BULK_MODE": "Subject (bulk insert)", "CHOOSE_PROJECT_FROM": "What's the project?", "CHOOSE_USERSTORY": "What's the user story?", "NO_USERSTORIES": "This project has no User Stories yet. Please select another project.", - "FILTER_USERSTORIES": "Filter user stories", + "FILTER_USERSTORIES": "User-Stories filter", "LIGHTBOX_TITLE_BLOKING_EPIC": "Blocking epic", - "ACTION_DELETE": "Delete epic" + "ACTION_DELETE": "Epic löschen" }, "US": { "PAGE_TITLE": "{{userStorySubject}} - User-Story {{userStoryRef}} - {{projectName}}", @@ -1101,15 +1129,9 @@ "ADD_BULK": "Mehrere neue User-Stories hinzufügen", "PROMOTED": "Diese User-Story entstand aus Ticket:", "TITLE_LINK_GO_TO_ISSUE": "Zum Ticket wechseln", - "EXTERNAL_REFERENCE": "Dies User-Story wurde angelegt von", - "GO_TO_EXTERNAL_REFERENCE": "Zur Quelle wechseln", - "BLOCKED": "Diese User-Story wird blockiert", "TITLE_DELETE_ACTION": "User-Story löschen", "LIGHTBOX_TITLE_BLOKING_US": "Blockiert uns", - "TASK_COMPLETED": "{{totalClosedTasks}}/{{totalTasks}} Aufgaben fertiggestellt", - "ASSIGN": "Zugeordnete User-Story", "NOT_ESTIMATED": "Nicht eingeschätzt", - "TOTAL_US_POINTS": "User-Story-Punkte insgesamt", "TRIBE": { "PUBLISH": "Als Gig in Taiga Tribe veröffentlichen", "PUBLISH_INFO": "Weitere Infos", @@ -1119,23 +1141,19 @@ "CLOSE": "Schließen", "SYNCHRONIZE_LINK": "mit Taiga Tribe synchronisieren", "PUBLISH_MORE_INFO_TITLE": "Brauchen Sie jemanden für diese Aufgabe?", - "PUBLISH_MORE_INFO_TEXT": "

If you need help with a particular piece of work you can easily create gigs on Taiga Tribe and receive help from all over the world. You will be able to control and manage the gig enjoying a great community eager to contribute.

TaigaTribe was born as a Taiga sibling. Both platforms can live separately but we believe that there is much power in using them combined so we are making sure the integration works like a charm.

" + "PUBLISH_MORE_INFO_TEXT": "

If you need help with a particular piece of work you can easily create gigs on Taiga Tribe and receive help from all over the world. You will be able to control and manage the gig enjoying a great community eager to contribute.

TaigaTribe was born as a Taiga sibling. Both platforms can live separately but we believe that there is much power in using them combined so we are making sure the integration works like a charm.

" }, "FIELDS": { "TEAM_REQUIREMENT": "Team Anforderung", - "CLIENT_REQUIREMENT": "Kundenanforderung", - "FINISH_DATE": "Endtermin" + "CLIENT_REQUIREMENT": "Kundenanforderung" } }, "COMMENTS": { "DELETED_INFO": "Kommentar gelöscht von {{user}}", - "TITLE": "Kommentare", "COMMENTS_COUNT": "{{comments}} Kommentare", - "ORDER": "Reihenfolge", "OLDER_FIRST": "Ältere zuerst", "RECENT_FIRST": "Letzte zuerst", "COMMENT": "Kommentieren", - "EDIT_COMMENT": "Kommentar bearbeiten", "EDITED_COMMENT": "Bearbeitet:", "SHOW_HISTORY": "View historic", "TYPE_NEW_COMMENT": "Geben Sie hier einen neuen Kommentar ein", @@ -1148,80 +1166,44 @@ } }, "ACTIVITY": { - "SHOW_ACTIVITY": "Aktivitäten zeigen", - "DATETIME": "DD. MMM YYYY HH:mm", - "SHOW_MORE": "+ Vorherige Einträge zeigen ({{showMore}} vorhanden)", "TITLE": "Aktivität", "ACTIVITIES_COUNT": "{{activities}} Aktivitäten", - "REMOVED": "entfernt", - "ADDED": "hinzugefügt", "TAGS_ADDED": "Tags hinzugefügt:", "TAGS_REMOVED": "Tags entfernt:", "US_POINTS": "{{role}} points", "NEW_ATTACHMENT": "neuer Anhang:", "DELETED_ATTACHMENT": "gelöschter Anhang:", - "UPDATED_ATTACHMENT": "updated attachment ({{filename}}):", - "CREATED_CUSTOM_ATTRIBUTE": "created custom attribute", - "UPDATED_CUSTOM_ATTRIBUTE": "updated custom attribute", - "SIZE_CHANGE": "Machte {size, plural, one{eine Änderung} other{# Änderungen}}", + "UPDATED_ATTACHMENT": "Anhang aktualisiert ({{filename}}):", + "CREATED_CUSTOM_ATTRIBUTE": "benutzerdefiniertes Attribut erstellt", + "UPDATED_CUSTOM_ATTRIBUTE": "benutzerdefiniertes Attribut aktualisiert", "BECAME_DEPRECATED": "ist veraltet", - "BECAME_UNDEPRECATED": "became undeprecated", + "BECAME_UNDEPRECATED": "ist wieder aktuell", "TEAM_REQUIREMENT": "Team Anforderung", "CLIENT_REQUIREMENT": "Kundenanforderung", "BLOCKED": "Blockiert", "VALUES": { - "YES": "ja", - "NO": "nein", - "EMPTY": "leer", "UNASSIGNED": "nicht zugeordnet" }, "FIELDS": { "SUBJECT": "Thema", - "NAME": "Name", "DESCRIPTION": "Beschreibung", - "CONTENT": "Inhalt", "STATUS": "Status", - "IS_CLOSED": "ist geschlossen", - "FINISH_DATE": "Endtermin", "TYPE": "Typen", - "PRIORITY": "Priorität", - "SEVERITY": "Gewichtung", "ASSIGNED_TO": "zugewiesen an", - "WATCHERS": "Beobachter", "MILESTONE": "Sprint", - "USER_STORY": "User-Story", - "PROJECT": "Projekt", - "IS_BLOCKED": "wird blockiert", - "BLOCKED_NOTE": "Blockierungsgrund", - "POINTS": "Punkte", - "CLIENT_REQUIREMENT": "Kunden Anforderung", - "TEAM_REQUIREMENT": "Team Anforderung", - "IS_IOCAINE": "ist Iocaine", - "TAGS": "Schlagwörter", - "ATTACHMENTS": "Anhänge", - "IS_DEPRECATED": "ist veraltet", - "IS_NOT_DEPRECATED": "ist nicht verworfen", - "ORDER": "Befehl", - "BACKLOG_ORDER": "Backlog Befehl", - "SPRINT_ORDER": "Sprint Befehl", - "KANBAN_ORDER": "Kanban Befehl", - "TASKBOARD_ORDER": "Taskboard Befehl", - "US_ORDER": "User-Story Befehl", "COLOR": "Farbe" } }, "BACKLOG": { - "PAGE_TITLE": "Auftragsliste - {{projectName}}", - "PAGE_DESCRIPTION": "Das Auftragslisten-Panel mit User-Stories und Sprints des Projekts. {{projectName}}: {{projectDescription}}", - "SECTION_NAME": "Auftragsliste", + "PAGE_TITLE": "Backlog - {{projectName}}", + "PAGE_DESCRIPTION": "Das Backlog-Panel mit User-Stories und Sprints des Projekts. {{projectName}}: {{projectDescription}}", + "SECTION_NAME": "Backlog", "CUSTOMIZE_GRAPH": "Personalisiere deinen Backloggraph", "CUSTOMIZE_GRAPH_TEXT": "Um schöne Graphen, die Dir bei der Entwicklung Deines Projekts helfen, zu sehen, musst du Estimatepoints und Sprints einstellen", "CUSTOMIZE_GRAPH_ADMIN": "Administrator", "CUSTOMIZE_GRAPH_TITLE": "Stelle Points und Sprints über das Adminpanel ein", "MOVE_US_TO_CURRENT_SPRINT": "Zum aktuellen Sprint wechseln", - "MOVE_US_TO_LATEST_SPRINT": "Move to latest Sprint", - "SHOW_FILTERS": "Filter zeigen", - "SHOW_TAGS": "Tags anzeigen", + "MOVE_US_TO_LATEST_SPRINT": "Zum aktuellen Sprint wechseln.", "EMPTY": "Das Backlog ist leer!", "CREATE_NEW_US": "Eine neue User-Story anlegen", "CREATE_NEW_US_EMPTY_HELP": "Sie sollten eine User-Story anlegen", @@ -1248,6 +1230,12 @@ "SHOW": "Schlagwörter anzeigen", "HIDE": "Schlagwörter ausblenden" }, + "FORECASTING": { + "TITLE": "Velocity forecasting", + "BACKLOG": "Backlog anzeigen", + "NEW_SPRINT": "Candidate User Stories for your next sprint based on your velocity. Click to create a new sprint.", + "CURRENT_SPRINT": "Candidate User Stories for your sprint based on your velocity. Click to add to current sprint." + }, "TABLE": { "COLUMN_US": "User-Stories", "TITLE_COLUMN_POINTS": "Ansicht mittels Rolle auswählen" @@ -1270,8 +1258,6 @@ }, "FILTERS": { "TOGGLE": "Filter sichtbar schalten", - "TITLE": "Filter", - "REMOVE": "Filter entfernen", "HIDE": "Filter verbergen", "SHOW": "Filter anzeigen" }, @@ -1280,10 +1266,9 @@ "DATE": "DD. MMM YYYY", "LINK_TASKBOARD": "Sprint Taskboard", "TITLE_LINK_TASKBOARD": "Gehe zu Taskboard von \"{{name}}\"", - "NUMBER_SPRINTS": "
Sprints", "EMPTY": "Derzeit sind keine Sprints vorhanden", "WARNING_EMPTY_SPRINT_ANONYMOUS": "Dieser Sprint enthält keiner User Stories", - "WARNING_EMPTY_SPRINT": "Ziehe Stories aus deiner Auftragsliste her, um einen neuen Sprint zu starten", + "WARNING_EMPTY_SPRINT": "Ziehe Stories aus deinem Backlog hierher, um einen neuen Sprint zu starten", "TITLE_ACTION_NEW_SPRINT": "Neuen Sprint hinzufügen", "TEXT_ACTION_NEW_SPRINT": "Du möchtest einen neuen Sprint in Deinem Projekt erstellen", "ACTION_SHOW_CLOSED_SPRINTS": "Geschlossene Sprints anzeigen", @@ -1305,7 +1290,6 @@ "TITLE_ACTION_ADD": "Neue Aufgabe hinzufügen", "TITLE_ACTION_ADD_BULK": "Mehrere Aufgaben hinzufügen", "TITLE_ACTION_ASSIGN": "Aufgabe zuweisen", - "TITLE_ACTION_EDIT": "Aufgabe bearbeiten", "PLACEHOLDER_CARD_TITLE": "Das könnte ein Task sein", "PLACEHOLDER_CARD_TEXT": "Teile Stories in Tasks auf um sie einzeln zu verfolgen", "TABLE": { @@ -1335,17 +1319,11 @@ "TITLE_SELECT_STATUS": "Status Bezeichnung", "OWNER_US": "Diese Aufgabe gehört zu", "TITLE_LINK_GO_OWNER": "Zur User-Story wechseln", - "ORIGIN_US": "Diese Aufgabe wurde erstellt durch", - "TITLE_LINK_GO_ORIGIN": "Zu User-Story wechseln", - "BLOCKED": "Diese Aufgabe wird blockiert", "TITLE_DELETE_ACTION": "Aufgabe löschen", "LIGHTBOX_TITLE_BLOKING_TASK": "Blockierende Aufgabe", "FIELDS": { - "MILESTONE": "Sprint", - "USER_STORY": "User-Story", "IS_IOCAINE": "Ist Iocaine" }, - "ACTION_IOCAINE": "Locaine", "TITLE_ACTION_IOCAINE": "Fühlen Sie sich von einer Aufgabe etwas erdrückt? Stellen Sie sicher, dass andere davon erfahren, indem Sie auf Locaine klicken, wenn Sie eine Aufgabe ändern. Es ist möglich, gegen dieses (fiktive) tödliche Gift immun zu werden, indem man kleine Mengen über einen Zeitraum hinweg einnimmt. Genauso, wie es möglich ist, besser in dem zu werden, was man tut, indem man gelegentlich zusätzliche Herausforderungen annimmt!" }, "NOTIFICATION": { @@ -1374,14 +1352,12 @@ "ISSUES": { "PAGE_TITLE": "Tickets - {{projectName}}", "PAGE_DESCRIPTION": "Das Ticket-Listen Panel des Projekts {{projectName}}: {{projectDescription}}", - "LIST_SECTION_NAME": "Tickets", "SECTION_NAME": "Ticket", "ACTION_NEW_ISSUE": "+ NEUES TICKET", "ACTION_PROMOTE_TO_US": "Zur User-Story aufwerten", "PROMOTED": "Dieses Ticket wurde aufgewertet zu User-Story:", "EXTERNAL_REFERENCE": "Dieses Ticket wurde erstellt durch", "GO_TO_EXTERNAL_REFERENCE": "Zur Quelle wechseln", - "BLOCKED": "Dieses Ticket wird blockiert", "ACTION_DELETE": "Ticket löschen", "LIGHTBOX_TITLE_BLOKING_ISSUE": "Blockierendes Ticket", "FIELDS": { @@ -1423,15 +1399,11 @@ "SECTION_NAME": "Kanban", "TITLE_ACTION_FOLD": "Seite einklappen", "TITLE_ACTION_UNFOLD": "Spalte aufklappen", - "TITLE_ACTION_FOLD_CARDS": "Karten einklappen", - "TITLE_ACTION_UNFOLD_CARDS": "Karten aufklappen", "TITLE_ACTION_ADD_US": "Neue User-Story hinzufügen", "TITLE_ACTION_ADD_BULK": "Neue Menge hinzufügen", "ACTION_SHOW_ARCHIVED": "Archivierte anzeigen", "ACTION_HIDE_ARCHIVED": "Archivierte verbergen", "HIDDEN_USER_STORIES": "Die User-Stories in diesem Status werden automatisch verborgen", - "ARCHIVED": "Sie haben es archiviert", - "UNDO_ARCHIVED": "Wiederholen Sie Drag & Drop zum Rückgängigmachen", "PLACEHOLDER_CARD_TITLE": "Dies sind deine User Stories", "PLACEHOLDER_CARD_TEXT": "Stories können Unteraufgaben für weitere Anforderungen haben" }, @@ -1452,7 +1424,6 @@ "PAGE_TITLE": "Team - {{projectName}}", "PAGE_DESCRIPTION": "Das Team Panel, um alle Mitglieder des Projekts anzuzeigen {{projectName}}: {{projectDescription}}", "SECTION_NAME": "Team", - "APP_TITLE": "TEAM - {{projectName}}", "PLACEHOLDER_INPUT_SEARCH": "Unter Anzeigenamen suchen...", "COLUMN_MR_WOLF": "Herr Wolf", "EXPLANATION_COLUMN_MR_WOLF": "Geschlossene Tickets", @@ -1488,18 +1459,9 @@ "OPTION_ALL": "Alle", "OPTION_INVOLVED": "Beteiligt", "OPTION_NONE": "Keine" - }, - "POPOVER": { - "USER_PROFILE": "Benutzerprofil", - "CHANGE_PASSWORD": "Passwort ändern", - "NOTIFICATIONS": "Benachrichtigungen", - "FEEDBACK": "Feedback", - "TITLE_AVATAR": "Benutzereinstellungen" } }, "USER_PROFILE": { - "IMAGE_HELP": "The image will be scaled to 80x80px.", - "ACTION_CHANGE_IMAGE": "Ändern", "ACTION_USE_GRAVATAR": "Use default image", "ACTION_DELETE_ACCOUNT": "Ihr Taiga Benutzerkonto löschen", "CHANGE_EMAIL_SUCCESS": "Sehen Sie in Ihren Posteingang!
Wir haben eine E-Mail an Ihr Konto gesendet
mit der Anleitung, wie Sie Ihre neue Adresse anlegen", @@ -1517,25 +1479,10 @@ "THEME_DEFAULT": "-- Standard-Theme benutzen --" } }, - "WIZARD": { - "SECTION_TITLE_CREATE_PROJECT": "Projekt erstellen", - "CREATE_PROJECT_TEXT": "Frisch und sauber. Wie aufregend!", - "CHOOSE_TEMPLATE": "Welches Template passt am besten zu Ihrem Projekt?", - "CHOOSE_TEMPLATE_TITLE": "Mehr Infos über Projekt-Templates", - "CHOOSE_TEMPLATE_INFO": "Weitere Infos", - "PROJECT_DETAILS": "Projekt Details", - "PUBLIC_PROJECT": "Öffentliches Projekt", - "PRIVATE_PROJECT": "Privates Projekt", - "CREATE_PROJECT": "Projekt anlegen", - "MAX_PRIVATE_PROJECTS": "Sie haben die maximale Anzahl privater Projekte erreicht", - "MAX_PUBLIC_PROJECTS": "Leider haben Sie die maximale Anzahl öffentlicher Projekte erreicht", - "CHANGE_PLANS": "Änderungs-Pläne" - }, "WIKI": { "PAGE_TITLE": "{{wikiPageName}} - Wiki - {{projectName}}", "PAGE_DESCRIPTION": "Letzte Bearbeitung am {{lastModifiedDate}} ({{totalEditions}} Gesamtzahl der Bearbeitungen) Inhalt: {{ wikiPageContent }}", "DATETIME": "DD MMM YYYY HH:mm", - "PLACEHOLDER_PAGE": "Schreiben Sie Ihre Wiki Seite", "REMOVE": "Diese Wiki Seite entfernen", "DELETE_LIGHTBOX_TITLE": "Wiki Seite löschen", "DELETE_LINK_TITLE": "Entferne Wiki Link", @@ -1601,11 +1548,11 @@ "NEW_COMMENT_US": "{{username}} schrieb einen Kommentar in der User-Story {{obj_name}}", "NEW_COMMENT_ISSUE": "{{username}} schrieb einen Kommentar im Ticket {{obj_name}}", "NEW_COMMENT_TASK": "{{username}} schrieb einen Kommentar in der Aufgabe {{obj_name}}", - "NEW_COMMENT_EPIC": "{{username}} has commented in the epic {{obj_name}}", + "NEW_COMMENT_EPIC": "{{username}} hat das Epic {{obj_name}} kommentiert", "NEW_MEMBER": "{{project_name}} hat ein neues Mitglied", "US_ADDED_MILESTONE": "{{username}} fügte dem Sprint {{sprint_name}} die User-Story {{obj_name}} hinzu", "US_MOVED": "{{username}} wurde in die Story {{obj_name}} verschoben", - "US_REMOVED_FROM_MILESTONE": "{{username}} fügte der Auftragsliste die User-Story {{obj_name}} hinzu", + "US_REMOVED_FROM_MILESTONE": "{{username}} fügte dem Backlog die User-Story {{obj_name}} hinzu", "BLOCKED": "{{username}} vermerkte die Blockierung von {{obj_name}}", "UNBLOCKED": "{{username}} hob die Blockierung von {{obj_name}} auf", "NEW_USER": "{{username}} ist Taiga beigetreten" @@ -1656,7 +1603,7 @@ }, "STEP2": { "TITLE": "Produkt Backlog", - "TEXT": "Die Auftragsliste zeigt dir alle Anforderungen (User Stories) für das Projekt an. Hier kannst du auch deine Sprints planen." + "TEXT": "Das Backlog zeigt dir alle Anforderungen (User Stories) für das Projekt an. Hier kannst du auch deine Sprints planen." }, "STEP3": { "TITLE": "Sprints", @@ -1664,7 +1611,7 @@ }, "STEP4": { "TITLE": "User-Stories", - "TEXT": "Dies sind die Anforderungen. Du kannst sie der Auftragsliste hinzufügen und sie zu einem Sprint hinzufügen." + "TEXT": "Dies sind die Anforderungen. Du kannst sie dem Backlog hinzufügen und sie zu einem Sprint hinzufügen." } }, "KANBAN": { @@ -1693,7 +1640,6 @@ "MOST_LIKED": "Most liked", "MOST_LIKED_EMPTY": "There are no LIKED projects yet", "VIEW_MORE": "View more", - "RECRUITING": "Dieses Projekt sucht nach Mitarbeitern", "FEATURED": "Featured Projects", "EMPTY": "There are no projects to show with this search criteria.
Try again!", "FILTERS": { diff --git a/app/locales/taiga/locale-en.json b/app/locales/taiga/locale-en.json index 18ce3111..bfb1cdcc 100644 --- a/app/locales/taiga/locale-en.json +++ b/app/locales/taiga/locale-en.json @@ -4,7 +4,6 @@ "NO": "No", "OR": "or", "LOADING": "Loading...", - "LOADING_PROJECT": "Loading project...", "DATE": "DD MMM YYYY", "DATETIME": "DD MMM YYYY HH:mm", "SAVE": "Save", @@ -27,12 +26,9 @@ "BLOCKED_NOTE": "Why is this blocked?", "BLOCKED_REASON": "Please explain the reason", "CREATED_BY": "Created by {{fullDisplayName}}", - "FROM": "from", - "TO": "to", "CLOSE": "close", "GO_HOME": "Take me home", "PLUGINS": "Plugins", - "BETA": "We are on beta!", "ONE_ITEM_LINE": "One item per line...", "NEW_BULK": "New bulk insert", "RELATED_TASKS": "Related tasks", @@ -148,7 +144,6 @@ "PRIORITY": "Priority", "ASSIGNED_TO": "Assigned to", "POINTS": "Points", - "BLOCKED_NOTE": "blocked note", "IS_BLOCKED": "is blocked", "REF": "Ref", "VOTES": "Votes", @@ -187,13 +182,10 @@ "COUNTER_TITLE": "{total, plural, one{one watcher} other{# watchers}}" }, "VOTE_BUTTON": { - "UPVOTE": "Upvote", - "UPVOTED": "Upvoted", - "DOWNVOTE": "Downvote", - "VOTERS": "Voters", "BUTTON_TITLE": "Upvote/Downvote this item", "COUNTER_TITLE": "{total, plural, one{one vote} other{# votes}}" }, + "CUSTOM_ATTRIBUTES": { "CUSTOM_FIELDS": "Custom Fields", "SAVE": "Save Custom Field", @@ -202,11 +194,9 @@ "CONFIRM_DELETE": "Remeber that all values in this custom field will be deleted.\n Are you sure you want to continue?" }, "FILTERS": { - "TITLE": "filters", "INPUT_PLACEHOLDER": "Subject or reference", "TITLE_ACTION_FILTER_BUTTON": "search", "TITLE": "Filters", - "INPUT_SEARCH_PLACEHOLDER": "Subject or ref", "TITLE_ACTION_SEARCH": "Search", "ACTION_SAVE_CUSTOM_FILTER": "save as custom filter", "PLACEHOLDER_FILTER_NAME": "Write the filter name and press enter", @@ -221,41 +211,14 @@ "CREATED_BY": "Created by", "CUSTOM_FILTERS": "Custom filters", "EPIC": "Epic" - }, - "CONFIRM_DELETE": { - "TITLE": "Delete custom filter", - "MESSAGE": "the custom filter '{{customFilterName}}'" } }, "WYSIWYG": { - "H1_BUTTON": "First Level Heading", - "H1_SAMPLE_TEXT": "Your title here...", - "H2_BUTTON": "Second Level Heading", - "H2_SAMPLE_TEXT": "Your title here...", - "H3_BUTTON": "Third Level Heading", - "H3_SAMPLE_TEXT": "Your title here...", - "BOLD_BUTTON": "Bold", - "BOLD_BUTTON_SAMPLE_TEXT": "Your text here...", - "ITALIC_BUTTON": "Italic", - "ITALIC_SAMPLE_TEXT": "Your text here...", - "STRIKE_BUTTON": "Strike", - "STRIKE_SAMPLE_TEXT": "Your text here...", - "BULLETED_LIST_BUTTON": "Bulleted List", - "BULLETED_LIST_SAMPLE_TEXT": "Your text here...", - "NUMERIC_LIST_BUTTON": "Numeric List", - "NUMERIC_LIST_SAMPLE_TEXT": "Your text here...", - "PICTURE_BUTTON": "Picture", - "PICTURE_SAMPLE_TEXT": "Your alternative text to picture here...", - "LINK_BUTTON": "Link", - "LINK_SAMPLE_TEXT": "Your text to link here....", - "QUOTE_BLOCK_BUTTON": "Quote Block", - "QUOTE_BLOCK_SAMPLE_TEXT": "Your text here...", - "CODE_BLOCK_BUTTON": "Code Block", - "CODE_BLOCK_SAMPLE_TEXT": "Your text here...", - "PREVIEW_BUTTON": "Preview", - "EDIT_BUTTON": "Edit", - "ATTACH_FILE_HELP": "Attach files by dragging & dropping on the textarea above.", - "ATTACH_FILE_HELP_SAVE_FIRST": "Save first before if you want to attach files by dragging & dropping on the textarea above.", + "CODE_SNIPPET": "Code Snippet", + "DB_CLICK": "double click to edit", + "SELECT_LANGUAGE_PLACEHOLDER": "Select Language", + "SELECT_LANGUAGE_REMOVE_FORMATING": "Remove formatting", + "OUTDATED": "Another person has made changes while you were editing. Check the new version on the activiy tab before you save your changes.", "MARKDOWN_HELP": "Markdown syntax help" }, "PERMISIONS_CATEGORIES": { @@ -308,10 +271,6 @@ "ADD_WIKI_LINKS": "Add wiki links", "DELETE_WIKI_LINKS": "Delete wiki links" } - }, - "META": { - "PAGE_TITLE": "Taiga", - "PAGE_DESCRIPTION": "Taiga is a project management platform for startups and agile developers & designers who want a simple, beautiful tool that makes work truly enjoyable." } }, "LOGIN": { @@ -331,7 +290,8 @@ "TITLE_LINK_FORGOT_PASSWORD": "Did you forget your password?", "ACTION_ENTER": "Enter", "ACTION_SIGN_IN": "Login", - "PLACEHOLDER_AUTH_PASSWORD": "Password (case sensitive)" + "PLACEHOLDER_AUTH_PASSWORD": "Password (case sensitive)", + "ALT_LOGIN": "Or login with" }, "LOGIN_FORM": { "ERROR_AUTH_INCORRECT": "According to our Oompa Loompas, your username/email or password are incorrect.", @@ -367,7 +327,6 @@ }, "CHANGE_PASSWORD": { "PAGE_TITLE": "Change you password - Taiga", - "PAGE_DESCRIPTION": "Set a new password for your Taiga account and hey!, you may want to eat some more iron-rich food, it's good for your brain :P", "SECTION_NAME": "Change password", "FIELD_CURRENT_PASSWORD": "Current password", "PLACEHOLDER_CURRENT_PASSWORD": "Your current password (or empty if you have no password yet)", @@ -392,8 +351,7 @@ }, "INVITATION_LOGIN_FORM": { "NOT_FOUND": "Our Oompa Loompas can't find your invitation.", - "SUCCESS": "You've successfully joined this project, Welcome to {{project_name}}", - "ERROR": "According to our Oompa Loompas, your are not registered yet or typed an invalid password." + "SUCCESS": "You've successfully joined this project, Welcome to {{project_name}}" }, "HOME": { "PAGE_TITLE": "Home - Taiga", @@ -464,10 +422,7 @@ "TITLE_LIGHTBOX_DELETE_ATTACHMENT": "Delete attachment...", "MSG_LIGHTBOX_DELETE_ATTACHMENT": "the attachment '{{fileName}}'", "ERROR_DELETE_ATTACHMENT": "We have not been able to delete: {{errorMessage}}", - "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) is too heavy for our Oompa Loompas, try it with a smaller than ({{maxFileSize}})", - "FIELDS": { - "IS_DEPRECATED": "is deprecated" - } + "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) is too heavy for our Oompa Loompas, try it with a smaller than ({{maxFileSize}})" }, "PAGINATION": { "PREVIOUS": "Prev", @@ -503,13 +458,10 @@ "ASYNC_MESSAGE": "We will send you an email when ready.", "SYNC_MESSAGE": "If the download doesn't start automatically click here.", "ERROR": "Our Oompa Loompas have some problems generating your dump. Please try it again.", - "ERROR_BUSY": "Sorry, our Oompa Loompas are very busy right now. Please try again in a few minutes.", - "ERROR_MESSAGE": "Our Oompa Loompas have some problems generating your dump: {{message}}" + "ERROR_BUSY": "Sorry, our Oompa Loompas are very busy right now. Please try again in a few minutes." }, "MODULES": { "TITLE": "Modules", - "ENABLE": "Enable", - "DISABLE": "Disable", "EPICS": "Epics", "EPICS_DESCRIPTION": "Visualize and manage the most strategic part of your project", "BACKLOG": "Backlog", @@ -538,17 +490,16 @@ "PAGE_TITLE": "{{sectionName}} - Project profile - {{projectName}}", "PROJECT_DETAILS": "Project details", "PROJECT_NAME": "Project name", - "PROJECT_SLUG": "Project slug", "TAGS": "Tags", "DESCRIPTION": "Description", "RECRUITING": "Is this project looking for people?", "RECRUITING_MESSAGE": "Who are you looking for?", "RECRUITING_PLACEHOLDER": "Define the profiles you are looking for", + "FEEDBACK": "Receive feedback from Taiga users?", "PUBLIC_PROJECT": "Public project", "PRIVATE_PROJECT": "Private project", "PRIVATE_OR_PUBLIC": "What's the difference between public and private projects?", "DELETE": "Delete this project", - "LOGO_HELP": "The image will be scaled to 80x80px.", "CHANGE_LOGO": "Change logo", "ACTION_USE_DEFAULT_LOGO": "Use default image", "MAX_PRIVATE_PROJECTS": "You've reached the maximum number of private projects allowed by your current plan", @@ -596,6 +547,7 @@ "ISSUE_DESCRIPTION": "Issues custom fields", "ISSUE_ADD": "Add a custom field in issues", "FIELD_TYPE_TEXT": "Text", + "FIELD_TYPE_RICHTEXT": "Rich text", "FIELD_TYPE_MULTI": "Multi-line", "FIELD_TYPE_DATE": "Date", "FIELD_TYPE_URL": "Url" @@ -624,7 +576,7 @@ "ACTION_ADD": "Add new severity" }, "PROJECT_VALUES_STATUS": { - "TITLE": "Status", + "TITLE": "Statuses", "SUBTITLE": "Specify the statuses your user stories, tasks and issues will go through", "EPIC_TITLE": "Epic Statuses", "US_TITLE": "User Story Statuses", @@ -677,8 +629,8 @@ "INFO_VERIFYING_IP": "Gitlab requests are not signed so the best way of verifying the origin is by IP. If the field is empty there will be no IP validation." }, "GITHUB": { - "SECTION_NAME": "Github", - "PAGE_TITLE": "Github - {{projectName}}" + "SECTION_NAME": "GitHub", + "PAGE_TITLE": "GitHub - {{projectName}}" }, "GOGS": { "SECTION_NAME": "Gogs", @@ -687,7 +639,6 @@ "WEBHOOKS": { "PAGE_TITLE": "Webhooks - {{projectName}}", "SECTION_NAME": "Webhooks", - "SUBTITLE": "Webhooks notify external services about events in Taiga, like comments, user stories....", "ADD_NEW": "Add a New Webhook", "TYPE_NAME": "Type the service name", "TYPE_PAYLOAD_URL": "Type the service payload url", @@ -733,7 +684,6 @@ "DELETE_MEMBER": "Delete member", "RESEND": "Resend", "SUCCESS_SEND_INVITATION": "We've sent the invitation again to '{{email}}'.", - "ERROR_SEND_INVITATION": "We haven't sent the invitation.", "SUCCESS_DELETE": "We've deleted {{message}}.", "ERROR_DELETE": "We have not been able to delete {{message}}.", "DEFAULT_DELETE_MESSAGE": "the invitation to {{email}}" @@ -756,21 +706,17 @@ }, "US_STATUS": { "ACTION_ADD_STATUS": "Add new status", - "IS_ARCHIVED_COLUMN": "Is archived?", + "IS_ARCHIVED_COLUMN": "Archived", + "IS_CLOSED_COLUMN": "Closed", "WIP_LIMIT_COLUMN": "WIP Limit", "PLACEHOLDER_WRITE_NAME": "Write a name for the new status" }, "MENU": { - "TITLE": "Admin", "PROJECT": "Project", "ATTRIBUTES": "Attributes", "MEMBERS": "Members", "PERMISSIONS": "Permissions", - "INTEGRATIONS": "Integrations", - "PLUGINS": "Plugins" - }, - "SUBMENU_PROJECT_ATTRIBUTES": { - "TITLE": "Attributes" + "INTEGRATIONS": "Integrations" }, "SUBMENU_PROJECT_VALUES": { "STATUS": "Status", @@ -781,17 +727,11 @@ "CUSTOM_FIELDS": "Custom fields", "TAGS": "Tags" }, - "SUBMENU_PROJECT_PROFILE": { - "TITLE": "Project Profile" - }, "SUBMENU_ROLES": { "TITLE": "Roles", "ACTION_NEW_ROLE": "+ New role", "TITLE_ACTION_NEW_ROLE": "Add new role" }, - "SUBMENU_THIDPARTIES": { - "TITLE": "Services" - }, "PROJECT_TRANSFER": { "DO_YOU_ACCEPT_PROJECT_OWNERNSHIP": "Would you like to become the new project owner?", "PRIVATE": "Private", @@ -806,15 +746,13 @@ "PRIVATE": "Please remember that you can own up to {{maxProjects}} private projects. You currently own {{currentProjects}} private projects", "PUBLIC": "Please remember that you can own up to {{maxProjects}} public projects. You currently own {{currentProjects}} public projects" }, - "CANT_BE_OWNED": "At the moment you cannot become an owner of a project of this type. If you would like to become the owner of this project, please contact the administrator so they change your account settings to enable project ownership.", - "CHANGE_MY_PLAN": "Change my plan" + "CANT_BE_OWNED": "At the moment you cannot become an owner of a project of this type. If you would like to become the owner of this project, please contact the administrator so they change your account settings to enable project ownership." } }, "USER": { "PROFILE": { "PAGE_TITLE": "{{userFullName}} (@{{userUsername}})", "EDIT": "Edit profile", - "FOLLOW": "Follow", "CLOSED_US": "Closed US", "PROJECTS": "Projects", "PROJECTS_EMPTY": "{{username}} doesn't' have projects yet", @@ -822,7 +760,6 @@ "CONTACTS_EMPTY": "{{username}} doesn't have contacts yet", "CURRENT_USER_CONTACTS_EMPTY": "You don't have contacts yet", "CURRENT_USER_CONTACTS_EMPTY_EXPLAIN": "The people with whom you work at Taiga will be your contacts automatically", - "REPORT": "Report Abuse", "TABS": { "ACTIVITY_TAB": "Timeline", "ACTIVITY_TAB_TITLE": "Show all the activity of this user", @@ -848,13 +785,13 @@ "FILTER_TYPE_ALL": "All", "FILTER_TYPE_ALL_TITLE": "Show all", "FILTER_TYPE_PROJECTS": "Projects", - "FILTER_TYPE_PROJECT_TITLES": "Show only projects", + "FILTER_TYPE_PROJECTS_TITLE": "Show only projects", "FILTER_TYPE_EPICS": "Epics", - "FILTER_TYPE_EPIC_TITLES": "Show only epics", + "FILTER_TYPE_EPICS_TITLE": "Show only epics", "FILTER_TYPE_USER_STORIES": "Stories", - "FILTER_TYPE_USER_STORIES_TITLES": "Show only user stories", + "FILTER_TYPE_USER_STORIES_TITLE": "Show only user stories", "FILTER_TYPE_TASKS": "Tasks", - "FILTER_TYPE_TASK_TITLES": "Show only tasks", + "FILTER_TYPE_TASKS_TITLE": "Show only tasks", "FILTER_TYPE_ISSUES": "Issues", "FILTER_TYPE_ISSUES_TITLE": "Show only issues", "EMPTY_TITLE": "It looks like there's nothing to show here." @@ -862,8 +799,6 @@ }, "PROJECT": { "PAGE_TITLE": "{{projectName}}", - "WELCOME": "Welcome", - "SECTION_PROJECTS": "Projects", "HELP": "Reorder your projects to set in the top the most used ones.
The top 10 projects will appear in the top navigation bar project list", "PRIVATE": "Private project", "LOOKING_FOR_PEOPLE": "This project is looking for people", @@ -875,12 +810,6 @@ "THIS_PROJECT_IS_BLOCKED": "This project is temporarily blocked", "TO_UNBLOCK_CONTACT_THE_ADMIN_STAFF": "In order to unblock your projects, contact the administrator." }, - "STATS": { - "PROJECT": "project
points", - "DEFINED": "defined
points", - "ASSIGNED": "assigned
points", - "CLOSED": "closed
points" - }, "SECTION": { "SEARCH": "Search", "TIMELINE": "Timeline", @@ -893,15 +822,9 @@ "ADMIN": "Admin" }, "NAVIGATION": { - "SECTION_TITLE": "Your projects", - "PLACEHOLDER_SEARCH": "Search in...", "ACTION_CREATE_PROJECT": "Create project", - "ACTION_IMPORT_PROJECT": "Import project", "MANAGE_PROJECTS": "Manage projects", "TITLE_CREATE_PROJECT": "Create project", - "TITLE_IMPORT_PROJECT": "Import project", - "TITLE_PRVIOUS_PROJECT": "Show previous projects", - "TITLE_NEXT_PROJECT": "Show next projects", "HELP_TITLE": "Taiga Support Page", "HELP": "Help", "HOMEPAGE": "Homepage", @@ -909,10 +832,6 @@ "FEEDBACK": "Feedback", "NOTIFICATIONS_TITLE": "Edit your notification settings", "NOTIFICATIONS": "Notifications", - "ORGANIZATIONS_TITLE": "Edit your organizations", - "ORGANIZATIONS": "Edit organizations", - "SETTINGS_TITLE": "Edit your settings", - "SETTINGS": "Settings", "VIEW_PROFILE_TITLE": "View Profile", "VIEW_PROFILE": "View Profile", "EDIT_PROFILE_TITLE": "Edit your profile", @@ -921,14 +840,68 @@ "CHANGE_PASSWORD": "Change password", "DASHBOARD_TITLE": "Dashboard", "DISCOVER_TITLE": "Discover trending projects", - "NEW_ITEM": "New", - "DISCOVER": "Discover", - "ACTION_REORDER": "Drag & drop to reorder" + "DISCOVER": "Discover" + }, + "LIKE_BUTTON": { + "LIKE": "Like", + "LIKED": "Liked", + "UNLIKE": "Unlike", + "BUTTON_TITLE": "Like or unlike this project", + "COUNTER_TITLE": "{total, plural, one{one fan} other{# fans}}" + }, + "WATCH_BUTTON": { + "BUTTON_TITLE": "Watch this project and set notification policy", + "WATCH": "Watch", + "WATCHING": "Watching", + "COUNTER_TITLE": "{total, plural, one{one watcher} other{# watchers}}", + "OPTIONS": { + "NOTIFY_ALL": "Receive all notifications", + "NOTIFY_ALL_TITLE": "Receive all notifications for this project", + "NOTIFY_INVOLVED": "Only involved", + "NOTIFY_INVOLVED_TITLE": "Recive notificacions only when you are involved", + "UNWATCH": "Unwatch", + "UNWATCH_TITLE": "Unwatch this project" + } + }, + "CONTACT_BUTTON": { + "CONTACT_TITLE": "Contact the project team", + "CONTACT_BUTTON": "Contact the project" + }, + "CREATE": { + "TITLE": "Create Project", + "CHOOSE_TEMPLATE": "Which template fits your project better?", + "TEMPLATE_SCRUM": "Scrum", + "TEMPLATE_SCRUM_DESC": "Prioritize and solve your tasks in short time cycles.", + "TEMPLATE_SCRUM_LONGDESC": "Scrum is an iterative and incremental agile software development methodology for managing product development.\nThe product backlog is what will ultimately be delivered, ordered into the sequence in which it should be delivered. Product Backlogs are broken into manageable, executable chunks named sprints. Every certain amount of time the team initiates a new sprint and commits to deliver a certain number of user stories from the backlog, in accordance with their skills, abilities and resources. The project advances as the backlog becomes depleted.", + "TEMPLATE_KANBAN": "Kanban", + "TEMPLATE_KANBAN_DESC": "Keep a constant workflow on independent tasks", + "TEMPLATE_KANBAN_LONGDESC": "The Kanban methodology is used to divide project development (any sort of project) into stages.\nA kanban card is like an index card or post-it note that details every task (or user story) in a project that needs to be completed. The Kanban board is used to move each card from one state of completion to the next and in so doing, helps track progress.", + "DUPLICATE": "Duplicate project", + "DUPLICATE_DESC": "Start clean and keep your configuration", + "IMPORT": "Import project", + "IMPORT_DESC": "Import your project from multiple platforms into Taiga", + "INVITE": "Invite to the project", + "SOLO_PROJECT": "You'll be alone in this project", + "INVITE_LATER": "(You'll be able to invite more members later)", + "BACK": "Back", + "MAX_PRIVATE_PROJECTS": "Unfortunately, You've reached the maximum number of private projects.\nIf you would like to increase the current limit please contact the administrator.", + "MAX_PUBLIC_PROJECTS": "Unfortunately, You've reached the maximum number of public projects.\nIf you would like to increase the current limit please contact the administrator.", + "PUBLIC_PROJECT": "Public Project", + "PRIVATE_PROJECT": "Private Project" + }, + "COMMON": { + "DETAILS": "New project details", + "PROJECT_TITLE": "Project Name", + "PROJECT_DESCRIPTION": "Project Description" + }, + "DUPLICATE": { + "TITLE": "Duplicate Project", + "DESCRIPTION": "Start clean and keep your configuration", + "SELECT_PLACEHOLDER": "Choose an existing project to duplicate" }, "IMPORT": { - "TITLE": "Importing Project", - "UPLOADING_FILE": "Uploading dump file", - "DESCRIPTION": "This process can take a while, please keep the window open.", + "TITLE": "Import Project", + "DESCRIPTION": "Import your project from multiple platforms into Taiga", "ASYNC_IN_PROGRESS_TITLE": "Our Oompa Loompas are importing your project", "ASYNC_IN_PROGRESS_MESSAGE": "This process could take a few minutes
We will send you an email when ready", "UPLOAD_IN_PROGRESS_MESSAGE": "Uploaded {{uploadedSize}} of {{totalSize}}", @@ -937,8 +910,29 @@ "ERROR_MESSAGE": "Our Oompa Loompas have some problems importing your dump data: {{error_message}}", "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) is too heavy for our Oompa Loompas, try it with a smaller than ({{maxFileSize}})", "SYNC_SUCCESS": "Your project has been imported successfuly", + "IMPORT": "Import", + "WHO_IS": "Their tasks will be assigned to ...", + "WRITE_EMAIL": "Or if you want, write the email that this user uses in Taiga", + "SEARCH_CONTACT": "Or if you want, search in your contacts", + "WRITE_EMAIL_LABEL": "Write the email that this user uses in Taiga", + "ACCEEDE": "Acceede", + "PROJECT_MEMBERS": "Project Members", + "PROCESS_DESCRIPTION": "Tell us who from Taiga you want to assign the tasks of {{platform}}", + "MATCH": "Is {{user_external}} the same person as {{user_internal}}?", + "CHOOSE": "Select user", + "LINKS": "Links with {{platform}}", + "LINKS_DESCRIPTION": "Do you want to keep the link of each item with the original {{platform}} card?", + "WARNING_MAIL_USER": "Note that if the user does not have a Taiga account we will not be able to assign the tasks to him.", + "ASSIGN": "Assign", + "PROJECT_SELECTOR": { + "NO_RESULTS": "It looks like nothing was found with your search criteria", + "ACTION_SEARCH": "search", + "ACTION_BACK": "Back" + }, "PROJECT_RESTRICTIONS": { - "PROJECT_MEMBERS_DESC": "The project you are trying to import has {{members}} members, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per project. If you would like to increase that limit please contact the administrator.", + "PROJECT_MEMBERS_DESC_PRIVATE": "The project you are trying to import has {{members}} members including you, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per private project. If you would like to increase that limit please contact the administrator.", + "PROJECT_MEMBERS_DESC_PUBLIC": "The project you are trying to import has {{members}} members including you, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per public project. If you would like to increase that limit please contact the administrator.", + "ACCOUNT_ALLOW_MEMBERS": "Your account only allows {{members}} members", "PRIVATE_PROJECTS_SPACE": { "TITLE": "Unfortunately, your current plan does not allow for additional private projects", "DESC": "The project you are trying to import is private. Unfortunately, your current plan does not allow for additional private projects." @@ -961,39 +955,67 @@ "TITLE": "Unfortunately your current plan doesn't allow additional public projects or an increase of more than {{max_memberships}} members per public project", "DESC": "The project that you are trying to import is public and has more than {{members}} members." } - } - }, - "LIKE_BUTTON": { - "LIKE": "Like", - "LIKED": "Liked", - "UNLIKE": "Unlike", - "BUTTON_TITLE": "Like or unlike this project", - "COUNTER_TITLE": "{total, plural, one{one fan} other{# fans}}" - }, - "WATCH_BUTTON": { - "BUTTON_TITLE": "Watch this project and set notification policy", - "WATCH": "Watch", - "WATCHING": "Watching", - "COUNTER_TITLE": "{total, plural, one{one watcher} other{# watchers}}", - "OPTIONS": { - "NOTIFY_ALL": "Receive all notifications", - "NOTIFY_ALL_TITLE": "Receive all notifications for this project", - "NOTIFY_INVOLVED": "Only involved", - "NOTIFY_INVOLVED_TITLE": "Recive notificacions only when you are involved", - "UNWATCH": "Unwatch", - "UNWATCH_TITLE": "Unwatch this project" + }, + "IN_PROGRESS": { + "TITLE": "Importing Project", + "DESCRIPTION": "This process can take a while, please keep the window open." + }, + "WARNING": { + "TITLE": "Some taks will be unassigned", + "DESCRIPTION": "There are still unidentified people. The cards assigned to these people will remain unassigned. Check all the contacts to not lose that information.", + "CHECK": "Check contacts" + }, + "TAIGA": { + "SELECTOR": "Import your Taiga project" + }, + "TRELLO": { + "SELECTOR": "Import your Trello boards into Taiga", + "CHOOSE_PROJECT": "Choose board that you want to import", + "NO_PROJECTS": "It seems you have no boards in Trello" + }, + "GITHUB": { + "SELECTOR": "Import your GitHub project issues", + "CHOOSE_PROJECT": "Find the project you want to import", + "NO_PROJECTS": "It seems you have no porjects in GitHub", + "HOW_DO_YOU_WANT_TO_IMPORT": "How do you want to import your issues into Taiga?", + "KANBAN_PROJECT": "As user stories in a kanban project", + "KANBAN_PROJECT_DESCRIPTION": "After that you can enable scrum with backlog.", + "SCRUM_PROJECT": "As user stories in a scrum project", + "SCRUM_PROJECT_DESCRIPTION": "After that you can enable kanban mode.", + "ISSUES_PROJECT": "As issues", + "ISSUES_PROJECT_DESCRIPTION": "You will not be able to use your issues in kanban or scrum mode. You will be able to enable kanban or scrum for new user stories" + }, + "ASANA": { + "SELECTOR": "Import your Asana project and choose how to manage it", + "CHOOSE_PROJECT": "Choose project that you want to import", + "NO_PROJECTS": "It seems you have no porjects in Asana", + "KANBAN_PROJECT": "Kanban", + "SCRUM_PROJECT": "Scrum", + "CREATE_AS_SCRUM_DESCRIPTION": "The tasks and sub-tasks of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_KANBAN_DESCRIPTION": "The tasks and sub-tasks of your project will be created as Taiga user stories and tasks." + }, + "JIRA": { + "SELECTOR": "Import your Jira project and choose how to manage it", + "CHOOSE_PROJECT": "Choose project or board that you want to import", + "NO_PROJECTS": "It seems you have no porjects or boards in Jira", + "URL": "Your Jira URL", + "KANBAN_PROJECT": "Kanban", + "SCRUM_PROJECT": "Scrum", + "ISSUES_PROJECT": "Issues", + "CREATE_AS_SCRUM_DESCRIPTION": "The issues and sub-issues of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_KANBAN_DESCRIPTION": "The issues and sub-issues of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_ISSUES_DESCRIPTION": "What do you want to do with sub-issues from the Jira project? (Taiga doesn't allow sub-issues)", + "CREATE_NEW_ISSUES": "Convert sub-issues to new Taiga issues", + "NOT_CREATE_NEW_ISSUES": "Do not import sub-issues" } } }, "LIGHTBOX": { "DELETE_ACCOUNT": { - "SECTION_NAME": "Delete Taiga Account", "CONFIRM": "Are you sure you want to delete your Taiga account?", - "NEWSLETTER_LABEL_TEXT": "I don't wanna receive your newsletter anymore", "CANCEL": "Back to settings", "ACCEPT": "Delete account", - "BLOCK_PROJECT": "Note that all the projects you own projects will be blocked after you delete your account. If you do want a project blocked, transfer ownership to another member of each project prior to deleting your account. ", - "SUBTITLE": "Sorry to see you go. We'll be here if you should ever consider us again! :(" + "BLOCK_PROJECT": "Note that all the projects you own projects will be blocked after you delete your account. If you do want a project blocked, transfer ownership to another member of each project prior to deleting your account. " }, "DELETE_PROJECT": { "TITLE": "Delete project", @@ -1007,6 +1029,12 @@ }, "ADD_MEMBER": { "TITLE": "New Member", + "PLACEHOLDER": "Filter users or write an email to invite", + "ADD_EMAIL": "Add email", + "REMOVE": "Remove", + "INVITE": "Invite", + "CHOOSE_ROLE": "Choose a role", + "PLACEHOLDER_INVITATION_TEXT": "(Optional) Add a personalized text to the invitation. Tell something lovely to your new members ;-)", "HELP_TEXT": "If users are already registered on Taiga, they will be added automatically. Otherwise they will receive an invitation." }, "CREATE_ISSUE": { @@ -1068,6 +1096,12 @@ "TITLE": "Who do you want to be the new project owner?", "ADD_COMMENT": "Add comment", "BUTTON": "Ask this project member to become the new project owner" + }, + "CONTACT_PROJECT": { + "TITLE": "Send an email to", + "WARNING": "The email will be received by the project admins", + "PLACEHOLDER": "Write your message", + "SEND": "Send" } }, "EPIC": { @@ -1101,15 +1135,9 @@ "ADD_BULK": "Add some new User Stories in bulk", "PROMOTED": "This US has been promoted from Issue:", "TITLE_LINK_GO_TO_ISSUE": "Go to issue", - "EXTERNAL_REFERENCE": "This US has been created from", - "GO_TO_EXTERNAL_REFERENCE": "Go to origin", - "BLOCKED": "This user story is blocked", "TITLE_DELETE_ACTION": "Delete User Story", "LIGHTBOX_TITLE_BLOKING_US": "Blocking us", - "TASK_COMPLETED": "{{totalClosedTasks}}/{{totalTasks}} tasks completed", - "ASSIGN": "Assign User Story", "NOT_ESTIMATED": "Not estimated", - "TOTAL_US_POINTS": "Total Us points", "TRIBE": { "PUBLISH": "Publish as Gig in Taiga Tribe", "PUBLISH_INFO": "More info", @@ -1119,23 +1147,19 @@ "CLOSE": "Close", "SYNCHRONIZE_LINK": "synchronize with Taiga Tribe", "PUBLISH_MORE_INFO_TITLE": "Do you need somebody for this task?", - "PUBLISH_MORE_INFO_TEXT": "

If you need help with a particular piece of work you can easily create gigs on Taiga Tribe and receive help from all over the world. You will be able to control and manage the gig enjoying a great community eager to contribute.

TaigaTribe was born as a Taiga sibling. Both platforms can live separately but we believe that there is much power in using them combined so we are making sure the integration works like a charm.

" + "PUBLISH_MORE_INFO_TEXT": "

If you need help with a particular piece of work you can easily create gigs on Taiga Tribe and receive help from all over the world. You will be able to control and manage the gig enjoying a great community eager to contribute.

TaigaTribe was born as a Taiga sibling. Both platforms can live separately but we believe that there is much power in using them combined so we are making sure the integration works like a charm.

" }, "FIELDS": { "TEAM_REQUIREMENT": "Team Requirement", - "CLIENT_REQUIREMENT": "Client Requirement", - "FINISH_DATE": "Finish date" + "CLIENT_REQUIREMENT": "Client Requirement" } }, "COMMENTS": { "DELETED_INFO": "Comment deleted by {{user}}", - "TITLE": "Comments", "COMMENTS_COUNT": "{{comments}} Comments", - "ORDER": "Order", "OLDER_FIRST": "Older first", "RECENT_FIRST": "Recent first", "COMMENT": "Comment", - "EDIT_COMMENT": "Edit comment", "EDITED_COMMENT": "Edited:", "SHOW_HISTORY": "View historic", "TYPE_NEW_COMMENT": "Type a new comment here", @@ -1148,13 +1172,8 @@ } }, "ACTIVITY": { - "SHOW_ACTIVITY": "Show activity", - "DATETIME": "DD MMM YYYY HH:mm", - "SHOW_MORE": "+ Show previous entries ({{showMore}} more)", "TITLE": "Activity", "ACTIVITIES_COUNT": "{{activities}} Activities", - "REMOVED": "removed", - "ADDED": "added", "TAGS_ADDED": "tags added:", "TAGS_REMOVED": "tags removed:", "US_POINTS": "{{role}} points", @@ -1163,50 +1182,21 @@ "UPDATED_ATTACHMENT": "updated attachment ({{filename}}): ", "CREATED_CUSTOM_ATTRIBUTE": "created custom attribute", "UPDATED_CUSTOM_ATTRIBUTE": "updated custom attribute", - "SIZE_CHANGE": "Made {size, plural, one{one change} other{# changes}}", "BECAME_DEPRECATED": "became deprecated", "BECAME_UNDEPRECATED": "became undeprecated", "TEAM_REQUIREMENT": "Team Requirement", "CLIENT_REQUIREMENT": "Client Requirement", "BLOCKED": "Blocked", "VALUES": { - "YES": "yes", - "NO": "no", - "EMPTY": "empty", "UNASSIGNED": "unassigned" }, "FIELDS": { "SUBJECT": "subject", - "NAME": "name", "DESCRIPTION": "description", - "CONTENT": "content", "STATUS": "status", - "IS_CLOSED": "is closed", - "FINISH_DATE": "finish date", "TYPE": "type", - "PRIORITY": "priority", - "SEVERITY": "severity", "ASSIGNED_TO": "assigned to", - "WATCHERS": "watchers", "MILESTONE": "sprint", - "USER_STORY": "user story", - "PROJECT": "project", - "IS_BLOCKED": "is blocked", - "BLOCKED_NOTE": "blocked note", - "POINTS": "points", - "CLIENT_REQUIREMENT": "client requirement", - "TEAM_REQUIREMENT": "team requirement", - "IS_IOCAINE": "is iocaine", - "TAGS": "tags", - "ATTACHMENTS": "attachments", - "IS_DEPRECATED": "is deprecated", - "IS_NOT_DEPRECATED": "is not deprecated", - "ORDER": "order", - "BACKLOG_ORDER": "backlog order", - "SPRINT_ORDER": "sprint order", - "KANBAN_ORDER": "kanban order", - "TASKBOARD_ORDER": "taskboard order", - "US_ORDER": "us order", "COLOR": "color" } }, @@ -1220,8 +1210,6 @@ "CUSTOMIZE_GRAPH_TITLE": "Set up the points and sprints through the Admin", "MOVE_US_TO_CURRENT_SPRINT": "Move to Current Sprint", "MOVE_US_TO_LATEST_SPRINT": "Move to latest Sprint", - "SHOW_FILTERS": "Show filters", - "SHOW_TAGS": "Show tags", "EMPTY": "The backlog is empty!", "CREATE_NEW_US": "Create a new US", "CREATE_NEW_US_EMPTY_HELP": "You may want to create a new user story", @@ -1248,6 +1236,12 @@ "SHOW": "Show tags", "HIDE": "Hide tags" }, + "FORECASTING": { + "TITLE": "Velocity forecasting", + "BACKLOG": "Display backlog", + "NEW_SPRINT": "Candidate User Stories for your next sprint based on your velocity. Click to create a new sprint.", + "CURRENT_SPRINT": "Candidate User Stories for your sprint based on your velocity. Click to add to current sprint." + }, "TABLE": { "COLUMN_US": "User Stories", "TITLE_COLUMN_POINTS": "Select view per Role" @@ -1270,8 +1264,6 @@ }, "FILTERS": { "TOGGLE": "Toggle filters visibility", - "TITLE": "Filters", - "REMOVE": "Remove Filters", "HIDE": "Hide Filters", "SHOW": "Show Filters" }, @@ -1280,7 +1272,6 @@ "DATE": "DD MMM YYYY", "LINK_TASKBOARD": "Sprint Taskboard", "TITLE_LINK_TASKBOARD": "Go to Taskboard of \"{{name}}\"", - "NUMBER_SPRINTS": "
sprints", "EMPTY": "There are no sprints yet", "WARNING_EMPTY_SPRINT_ANONYMOUS": "This sprint has no User Stories", "WARNING_EMPTY_SPRINT": "Drop here Stories from your backlog to start a new sprint", @@ -1305,7 +1296,6 @@ "TITLE_ACTION_ADD": "Add a new Task", "TITLE_ACTION_ADD_BULK": "Add some new Tasks in bulk", "TITLE_ACTION_ASSIGN": "Assign task", - "TITLE_ACTION_EDIT": "Edit task", "PLACEHOLDER_CARD_TITLE": "This could be a task", "PLACEHOLDER_CARD_TEXT": "Split Stories into tasks to track them separately", "TABLE": { @@ -1335,17 +1325,11 @@ "TITLE_SELECT_STATUS": "Status Name", "OWNER_US": "This task belongs to", "TITLE_LINK_GO_OWNER": "Go to user story", - "ORIGIN_US": "This task has been created from", - "TITLE_LINK_GO_ORIGIN": "Go to user story", - "BLOCKED": "This task is blocked", "TITLE_DELETE_ACTION": "Delete Task", "LIGHTBOX_TITLE_BLOKING_TASK": "Blocking task", "FIELDS": { - "MILESTONE": "Sprint", - "USER_STORY": "User story", "IS_IOCAINE": "Is iocaine" }, - "ACTION_IOCAINE": "Iocaine", "TITLE_ACTION_IOCAINE": "Feeling a bit overwhelmed by a task? Make sure others know about it by clicking on Iocaine when editing a task. It's possible to become immune to this (fictional) deadly poison by consuming small amounts over time just as it's possible to get better at what you do by occasionally taking on extra challenges!" }, "NOTIFICATION": { @@ -1374,14 +1358,12 @@ "ISSUES": { "PAGE_TITLE": "Issues - {{projectName}}", "PAGE_DESCRIPTION": "The issues list panel of the project {{projectName}}: {{projectDescription}}", - "LIST_SECTION_NAME": "Issues", "SECTION_NAME": "Issue", "ACTION_NEW_ISSUE": "+ NEW ISSUE", "ACTION_PROMOTE_TO_US": "Promote to User Story", "PROMOTED": "This issue has been promoted to US:", "EXTERNAL_REFERENCE": "This issue has been created from", "GO_TO_EXTERNAL_REFERENCE": "Go to origin", - "BLOCKED": "This issue is blocked", "ACTION_DELETE": "Delete issue", "LIGHTBOX_TITLE_BLOKING_ISSUE": "Blocking issue", "FIELDS": { @@ -1423,15 +1405,11 @@ "SECTION_NAME": "Kanban", "TITLE_ACTION_FOLD": "Fold column", "TITLE_ACTION_UNFOLD": "Unfold column", - "TITLE_ACTION_FOLD_CARDS": "Fold cards", - "TITLE_ACTION_UNFOLD_CARDS": "Unfold cards", "TITLE_ACTION_ADD_US": "Add New User Story", "TITLE_ACTION_ADD_BULK": "Add New bulk", "ACTION_SHOW_ARCHIVED": "Show archived", "ACTION_HIDE_ARCHIVED": "Hide archived", "HIDDEN_USER_STORIES": "The user stories in this status are hidden by default", - "ARCHIVED": "You have archived", - "UNDO_ARCHIVED": "Drag & drop again to undo", "PLACEHOLDER_CARD_TITLE": "These are your User Stories", "PLACEHOLDER_CARD_TEXT": "Stories might also have subtasks to separate requirements" }, @@ -1452,7 +1430,6 @@ "PAGE_TITLE": "Team - {{projectName}}", "PAGE_DESCRIPTION": "The team panel to show all the members of the project {{projectName}}: {{projectDescription}}", "SECTION_NAME": "Team", - "APP_TITLE": "TEAM - {{projectName}}", "PLACEHOLDER_INPUT_SEARCH": "Search by full name...", "COLUMN_MR_WOLF": "Mr. Wolf", "EXPLANATION_COLUMN_MR_WOLF": "Closed issues", @@ -1488,18 +1465,9 @@ "OPTION_ALL": "All", "OPTION_INVOLVED": "Involved", "OPTION_NONE": "None" - }, - "POPOVER": { - "USER_PROFILE": "User Profile", - "CHANGE_PASSWORD": "Change Password", - "NOTIFICATIONS": "Notifications", - "FEEDBACK": "Feedback", - "TITLE_AVATAR": "User preferences" } }, "USER_PROFILE": { - "IMAGE_HELP": "The image will be scaled to 80x80px.", - "ACTION_CHANGE_IMAGE": "Change", "ACTION_USE_GRAVATAR": "Use default image", "ACTION_DELETE_ACCOUNT": "Delete Taiga account", "CHANGE_EMAIL_SUCCESS": "Check your inbox!
We have sent a mail to your account
with the instructions to set your new address", @@ -1517,25 +1485,11 @@ "THEME_DEFAULT": "-- use default theme --" } }, - "WIZARD": { - "SECTION_TITLE_CREATE_PROJECT": "Create Project", - "CREATE_PROJECT_TEXT": "Fresh and clean. So exciting!", - "CHOOSE_TEMPLATE": "Which template fits your project best?", - "CHOOSE_TEMPLATE_TITLE": "More info about project templates", - "CHOOSE_TEMPLATE_INFO": "More info", - "PROJECT_DETAILS": "Project Details", - "PUBLIC_PROJECT": "Public Project", - "PRIVATE_PROJECT": "Private Project", - "CREATE_PROJECT": "Create project", - "MAX_PRIVATE_PROJECTS": "You've reached the maximum number of private projects", - "MAX_PUBLIC_PROJECTS": "Unfortunately, you've reached the maximum number of public projects", - "CHANGE_PLANS": "change plans" - }, + "WIKI": { "PAGE_TITLE": "{{wikiPageName}} - Wiki - {{projectName}}", "PAGE_DESCRIPTION": "Last edition on {{lastModifiedDate}} ({{totalEditions}} editions in total) Content: {{ wikiPageContent }}", "DATETIME": "DD MMM YYYY HH:mm", - "PLACEHOLDER_PAGE": "Write your wiki page", "REMOVE": "Remove this wiki page", "DELETE_LIGHTBOX_TITLE": "Delete Wiki Page", "DELETE_LINK_TITLE": "Delete Wiki link", @@ -1693,7 +1647,6 @@ "MOST_LIKED": "Most liked", "MOST_LIKED_EMPTY": "There are no LIKED projects yet", "VIEW_MORE": "View more", - "RECRUITING": "This project is looking for people", "FEATURED": "Featured Projects", "EMPTY": "There are no projects to show with this search criteria.
Try again!", "FILTERS": { diff --git a/app/locales/taiga/locale-es.json b/app/locales/taiga/locale-es.json index e12ab653..1c9f684e 100644 --- a/app/locales/taiga/locale-es.json +++ b/app/locales/taiga/locale-es.json @@ -4,7 +4,6 @@ "NO": "No", "OR": "o", "LOADING": "Cargando...", - "LOADING_PROJECT": "Cargando proyecto...", "DATE": "DD MMM YYYY", "DATETIME": "DD MMM YYYY HH:mm", "SAVE": "Guardar", @@ -27,12 +26,9 @@ "BLOCKED_NOTE": "¿Por qué está bloqueada?", "BLOCKED_REASON": "Por favor, explica la razón", "CREATED_BY": "Creada por {{fullDisplayName}}", - "FROM": "de", - "TO": "a", "CLOSE": "cerrar", "GO_HOME": "Llévame a casa", "PLUGINS": "Plugins", - "BETA": "¡Estamos en fase beta!", "ONE_ITEM_LINE": "Un elemento por línea...", "NEW_BULK": "Nueva inserción en bloque", "RELATED_TASKS": "Tareas relacionadas", @@ -41,7 +37,7 @@ "LOGOUT": "Cerrar sesión", "EXTERNAL_USER": "un usuario externo", "GENERIC_ERROR": "Uno de nuestros Oompa Loompas dice {{error}}.", - "IOCAINE_TEXT": "¿Te sientes fuera de tu zona de confort en una tarea? Asegúrate de que los demás están al tanto de ello, marca el check de la Iocaína al editar una tarea. Igual eu era posible llegar a ser inmune a este veneno mortal a base de consumir pequeñas dosis a lo largo del tiempo, es posible conseguir mejor en lo que estás haciendo si afrontas de vez en cuando esta clase de retos!", + "IOCAINE_TEXT": "Este miembro se siente un poco abrumado por esta tarea. Será inmune al veneno de la iocaína con el tiempo con tu ayuda, Ahora, puede necesitar un abrazo ;-).", "CLIENT_REQUIREMENT": "Requerimiento de cliente es un nuevo requisito que no se esperaba y es necesario que forme parte del proyecto.", "TEAM_REQUIREMENT": "Requerimiento del equipo es un nuevo requisito que debe existir en el proyecto pero que no conllevará ningún coste para el cliente.", "OWNER": "Dueño del proyecto", @@ -148,7 +144,6 @@ "PRIORITY": "Prioridad", "ASSIGNED_TO": "Asignado a", "POINTS": "Puntos", - "BLOCKED_NOTE": "Motivo del bloqueo", "IS_BLOCKED": "está bloqueada", "REF": "Ref", "VOTES": "Votos", @@ -187,10 +182,6 @@ "COUNTER_TITLE": "{total, plural, one{un observador} other{# observadores}}" }, "VOTE_BUTTON": { - "UPVOTE": "Votar", - "UPVOTED": "Votado", - "DOWNVOTE": "No votar", - "VOTERS": "Votos", "BUTTON_TITLE": "Votar o no este elemento", "COUNTER_TITLE": "{total, plural, one{un voto} other{# votos}}" }, @@ -202,10 +193,9 @@ "CONFIRM_DELETE": "Se borrarán todos los valores de este atributo personalizado. \n¿Estás seguro de que quieres continuar?" }, "FILTERS": { - "TITLE": "Filtros", "INPUT_PLACEHOLDER": "Asunto o referencia", "TITLE_ACTION_FILTER_BUTTON": "busqueda", - "INPUT_SEARCH_PLACEHOLDER": "Asunto o referencia", + "TITLE": "Filtros", "TITLE_ACTION_SEARCH": "Buscar", "ACTION_SAVE_CUSTOM_FILTER": "guardar como filtro personalizado", "PLACEHOLDER_FILTER_NAME": "Escribe un nombre para el filtro y pulsa enter", @@ -220,41 +210,10 @@ "CREATED_BY": "Creada por", "CUSTOM_FILTERS": "Filtros personalizados", "EPIC": "Épica" - }, - "CONFIRM_DELETE": { - "TITLE": "Eliminar filtros personalizados", - "MESSAGE": "el filtro personalizado '{{customFilterName}}'" } }, "WYSIWYG": { - "H1_BUTTON": "Título de primer nivel", - "H1_SAMPLE_TEXT": "Tu título aquí...", - "H2_BUTTON": "Título de segundo nivel", - "H2_SAMPLE_TEXT": "Tu título aquí...", - "H3_BUTTON": "Título de tercer nivel", - "H3_SAMPLE_TEXT": "Tu título aquí...", - "BOLD_BUTTON": "Negrita", - "BOLD_BUTTON_SAMPLE_TEXT": "Tu texto aquí...", - "ITALIC_BUTTON": "Cursiva", - "ITALIC_SAMPLE_TEXT": "Tu texto aquí...", - "STRIKE_BUTTON": "Tachado", - "STRIKE_SAMPLE_TEXT": "Tu texto aquí...", - "BULLETED_LIST_BUTTON": "Lista con viñetas", - "BULLETED_LIST_SAMPLE_TEXT": "Tu texto aquí...", - "NUMERIC_LIST_BUTTON": "Lista numérica", - "NUMERIC_LIST_SAMPLE_TEXT": "Tu texto aquí...", - "PICTURE_BUTTON": "Imagen", - "PICTURE_SAMPLE_TEXT": "Tu texto alternatívo para la imagen aquí...", - "LINK_BUTTON": "Enlace", - "LINK_SAMPLE_TEXT": "Tu texto del enlace aquí...", - "QUOTE_BLOCK_BUTTON": "Cita", - "QUOTE_BLOCK_SAMPLE_TEXT": "Tu texto aquí...", - "CODE_BLOCK_BUTTON": "Código", - "CODE_BLOCK_SAMPLE_TEXT": "Tu texto aquí...", - "PREVIEW_BUTTON": "Previsualizar", - "EDIT_BUTTON": "Editar", - "ATTACH_FILE_HELP": "Adjunte archivos arrastrando y soltando dentro del area de texto", - "ATTACH_FILE_HELP_SAVE_FIRST": "Si desea guardar adjuntos guarde primero, luego arrastre y suelte los archivos en el area de texto mas arriba", + "OUTDATED": "Otra persona ha realizado cambios durante tu edición. Comprueba la nueva versión en la pestaña de activiy antes de guardar los cambios.", "MARKDOWN_HELP": "Ayuda de sintaxis Markdown" }, "PERMISIONS_CATEGORIES": { @@ -307,10 +266,6 @@ "ADD_WIKI_LINKS": "Crear enlaces", "DELETE_WIKI_LINKS": "Borrar enlaces" } - }, - "META": { - "PAGE_TITLE": "Taiga", - "PAGE_DESCRIPTION": "Taiga es una plataforma de gestión de proyectos orientada a startups y equipos ágiles que buscan una herramienta sencilla, elegante y que les haga disfrutar trabajando." } }, "LOGIN": { @@ -366,7 +321,6 @@ }, "CHANGE_PASSWORD": { "PAGE_TITLE": "Cambia tu contraseña - Taiga", - "PAGE_DESCRIPTION": "Indica una nueva contraseña para tu cuenta en Taiga y bueno, es posible que necesites comer un poco más de alimentos ricos en hierro, son buenos para tu cerebro :P", "SECTION_NAME": "Cambiar contraseña", "FIELD_CURRENT_PASSWORD": "Contraseña actual", "PLACEHOLDER_CURRENT_PASSWORD": "Tu contraseña actual (o déjalo vacío si todavía no tienes contraseña)", @@ -391,8 +345,7 @@ }, "INVITATION_LOGIN_FORM": { "NOT_FOUND": "Nuestros Oompa Loompas no pueden encontrar su invitación.", - "SUCCESS": "¡Acabas de unirte al proyecto! Bienvenido a {{project_name}}", - "ERROR": "Según nuestros Oompa Loompas tú no estás registrado o has escrito mal tu contraseña." + "SUCCESS": "¡Acabas de unirte al proyecto! Bienvenido a {{project_name}}" }, "HOME": { "PAGE_TITLE": "Inicio - Taiga", @@ -463,10 +416,7 @@ "TITLE_LIGHTBOX_DELETE_ATTACHMENT": "Borrar adjunto...", "MSG_LIGHTBOX_DELETE_ATTACHMENT": "el adjunto '{{fileName}}'", "ERROR_DELETE_ATTACHMENT": "No hemos podido borrarlo: {{errorMessage}}", - "ERROR_MAX_SIZE_EXCEEDED": "El fichero '{{fileName}}' ({{fileSize}}) es demasiado pesado para nuestros Oompa Loompas, prueba con uno de menos de ({{maxFileSize}}).", - "FIELDS": { - "IS_DEPRECATED": "Está desactualizado" - } + "ERROR_MAX_SIZE_EXCEEDED": "El fichero '{{fileName}}' ({{fileSize}}) es demasiado pesado para nuestros Oompa Loompas, prueba con uno de menos de ({{maxFileSize}})." }, "PAGINATION": { "PREVIOUS": "Anterior", @@ -502,13 +452,10 @@ "ASYNC_MESSAGE": "Te enviaremos un email cuando esté listo.", "SYNC_MESSAGE": "Si la descarga no comienza automáticamente haz click aquí.", "ERROR": "Nuestros Oompa Loompas tienen algunos problemas generando el volcado de tus datos. Por favor inténtalo de nuevo.", - "ERROR_BUSY": "Lo sentimos, nuestros Oompa Loompas están muy ocupados en este momento. Por favor inténtalo nuevamente en unos minutos.", - "ERROR_MESSAGE": "Nuestros Oompa Loompas han tenido algunos problemas generando el volcado de datos: {{message}}" + "ERROR_BUSY": "Lo sentimos, nuestros Oompa Loompas están muy ocupados en este momento. Por favor inténtalo nuevamente en unos minutos." }, "MODULES": { "TITLE": "Módulos", - "ENABLE": "Activado", - "DISABLE": "Desactivado", "EPICS": "Épicas", "EPICS_DESCRIPTION": "Visualizar y administrar la parte mas estrategica del proyecto.", "BACKLOG": "Backlog", @@ -537,17 +484,16 @@ "PAGE_TITLE": "{{sectionName}} - Perfil de Proyecto - {{projectName}}\n", "PROJECT_DETAILS": "Info del proyecto", "PROJECT_NAME": "Nombre del proyecto", - "PROJECT_SLUG": "Slug de proyecto", "TAGS": "Etiquetas", "DESCRIPTION": "Descripción", "RECRUITING": "¿Este proyecto está buscando a gente?", "RECRUITING_MESSAGE": "¿Qué estás buscando?", "RECRUITING_PLACEHOLDER": "Define el perfil de lo que estás buscando", + "FEEDBACK": "¿Recibir feedback de los usuarios de Taiga?", "PUBLIC_PROJECT": "Proyecto público", "PRIVATE_PROJECT": "Proyecto privado", "PRIVATE_OR_PUBLIC": "¿Cuál es la diferencia entre proyecto público y privado?", "DELETE": "Eliminar este proyecto", - "LOGO_HELP": "La imagen se escalará a 80x80px.", "CHANGE_LOGO": "Cambia el logo", "ACTION_USE_DEFAULT_LOGO": "Usar imagen por defecto", "MAX_PRIVATE_PROJECTS": "Has alcanzado el número máximo de proyectos privados permitidos por su actual plan", @@ -595,6 +541,7 @@ "ISSUE_DESCRIPTION": "Atributos personalizados de peticiones", "ISSUE_ADD": "Añadir un atributo personalizado en las peticiones", "FIELD_TYPE_TEXT": "Texto", + "FIELD_TYPE_RICHTEXT": "Texto enriquecido", "FIELD_TYPE_MULTI": "Multilínea", "FIELD_TYPE_DATE": "Fecha", "FIELD_TYPE_URL": "Url" @@ -623,7 +570,7 @@ "ACTION_ADD": "Añadir nueva gravedad" }, "PROJECT_VALUES_STATUS": { - "TITLE": "Estado", + "TITLE": "Statuses", "SUBTITLE": "Especifica los estado que atravesarán tus historias de usuario, tareas y peticiones", "EPIC_TITLE": "Estados de Epicas", "US_TITLE": "Estados de historias de usuario", @@ -676,8 +623,8 @@ "INFO_VERIFYING_IP": "Las peticiones de Gitlab no van firmadas, con la IP de origen verificamos su procedencia. Déjalo vacío y no se verificarán." }, "GITHUB": { - "SECTION_NAME": "Github", - "PAGE_TITLE": "Github - {{projectName}}" + "SECTION_NAME": "GitHub", + "PAGE_TITLE": "GitHub - {{projectName}}" }, "GOGS": { "SECTION_NAME": "Gogs", @@ -686,7 +633,6 @@ "WEBHOOKS": { "PAGE_TITLE": "Webhooks - {{projectName}}", "SECTION_NAME": "Webhooks", - "SUBTITLE": "Los Webhooks notificarán a servicios externos sobre todos los eventos que ocurren en Taiga como comentarios, historias de usuario...", "ADD_NEW": "Añadir un Nuevo Webhook", "TYPE_NAME": "Escribe el nombre del servicio", "TYPE_PAYLOAD_URL": "Escribe la 'payload URL' del servicio", @@ -732,7 +678,6 @@ "DELETE_MEMBER": "Borrar miembro", "RESEND": "Enviar de nuevo", "SUCCESS_SEND_INVITATION": "Hemos enviado nuevamente la invitación a '{{email}}'.", - "ERROR_SEND_INVITATION": "No hemos enviado la invitación.", "SUCCESS_DELETE": "Hemos eliminado {{message}}.", "ERROR_DELETE": "No se ha podido eliminar {{message}}. ", "DEFAULT_DELETE_MESSAGE": "la invitación enviada a" @@ -761,16 +706,11 @@ "PLACEHOLDER_WRITE_NAME": "Escribe un nombre para el nuevo estado" }, "MENU": { - "TITLE": "Admin", "PROJECT": "Proyecto", "ATTRIBUTES": "Atributos", "MEMBERS": "Miembros", "PERMISSIONS": "Permisos", - "INTEGRATIONS": "Integraciones", - "PLUGINS": "Plugins" - }, - "SUBMENU_PROJECT_ATTRIBUTES": { - "TITLE": "Atributos" + "INTEGRATIONS": "Integraciones" }, "SUBMENU_PROJECT_VALUES": { "STATUS": "Estados", @@ -781,17 +721,11 @@ "CUSTOM_FIELDS": "Atributos personalizados", "TAGS": "Etiquetas" }, - "SUBMENU_PROJECT_PROFILE": { - "TITLE": "Perfil de proyecto" - }, "SUBMENU_ROLES": { "TITLE": "Roles", "ACTION_NEW_ROLE": "+ Nuevo Rol", "TITLE_ACTION_NEW_ROLE": "Añadir nuevo rol" }, - "SUBMENU_THIDPARTIES": { - "TITLE": "Servicios" - }, "PROJECT_TRANSFER": { "DO_YOU_ACCEPT_PROJECT_OWNERNSHIP": "¿Te gustaría ser el nuevo project owner?", "PRIVATE": "Privado", @@ -806,15 +740,13 @@ "PRIVATE": "Por favor recuerde que puede ser dueño de maximo {{maxProjects}} proyectos privados. Usted tiene actualmente {{currentProjects}} proyectos privados bajo su poder", "PUBLIC": "Pro favor recuerde que solo puede ser dueño de maximo {{maxProjects}} proyectos publicos. Actualmente tiene {{currentProjects}} proyectos publicos bajo su poder" }, - "CANT_BE_OWNED": "en el momento no puede ser el dueño de un proyecto de este tipo. Si desea ser el dueño de este proyecto, por favor contacte al administrador para cambiar la configuracion que le permita ser dueño del proyecto", - "CHANGE_MY_PLAN": "Cambiar mi plan" + "CANT_BE_OWNED": "en el momento no puede ser el dueño de un proyecto de este tipo. Si desea ser el dueño de este proyecto, por favor contacte al administrador para cambiar la configuracion que le permita ser dueño del proyecto" } }, "USER": { "PROFILE": { "PAGE_TITLE": "{{userFullName}} (@{{userUsername}})", "EDIT": "Editar perfil", - "FOLLOW": "Seguir", "CLOSED_US": "Historias cerradas", "PROJECTS": "Proyectos", "PROJECTS_EMPTY": "{{username}} no tiene proyectos todavía", @@ -822,7 +754,6 @@ "CONTACTS_EMPTY": "{{username}} no tiene contactos todavía", "CURRENT_USER_CONTACTS_EMPTY": "No tienes contactos todavía", "CURRENT_USER_CONTACTS_EMPTY_EXPLAIN": "Las personas con las que trabajas en Taiga serán tus contactos automáticamente", - "REPORT": "Reportar Abuso", "TABS": { "ACTIVITY_TAB": "Timeline", "ACTIVITY_TAB_TITLE": "Muestra toda la actividad de este usuario", @@ -848,13 +779,13 @@ "FILTER_TYPE_ALL": "Todas", "FILTER_TYPE_ALL_TITLE": "Mostrar todos", "FILTER_TYPE_PROJECTS": "Proyectos", - "FILTER_TYPE_PROJECT_TITLES": "Mostrar sólo proyectos", + "FILTER_TYPE_PROJECTS_TITLE": "Mostrar sólo proyectos", "FILTER_TYPE_EPICS": "Épicas", - "FILTER_TYPE_EPIC_TITLES": "Mostrar sólo épicas", + "FILTER_TYPE_EPICS_TITLE": "Mostrar sólo épicas", "FILTER_TYPE_USER_STORIES": "Historias", - "FILTER_TYPE_USER_STORIES_TITLES": "Mostrar sólo historias de usuario", + "FILTER_TYPE_USER_STORIES_TITLE": "Mostrar sólo historias de usuario", "FILTER_TYPE_TASKS": "Tareas", - "FILTER_TYPE_TASK_TITLES": "Mostrar sólo tareas", + "FILTER_TYPE_TASKS_TITLE": "Mostrar sólo tareas", "FILTER_TYPE_ISSUES": "Peticiones", "FILTER_TYPE_ISSUES_TITLE": "Mostrar sólo peticiones", "EMPTY_TITLE": "Parece que no se ha encontrado nada." @@ -862,8 +793,6 @@ }, "PROJECT": { "PAGE_TITLE": "{{projectName}}", - "WELCOME": "Bienvenido", - "SECTION_PROJECTS": "Proyectos", "HELP": "Reordena tus proyectos para ver arriba los que más utilizas.
Los 10 primeros aparecerán en la lista de proyectos de la barra de navegación de arriba.", "PRIVATE": "Proyecto privado", "LOOKING_FOR_PEOPLE": "Este proyecto está buscando a gente", @@ -875,12 +804,6 @@ "THIS_PROJECT_IS_BLOCKED": "Este proyecto esta temporalmente bloqueado", "TO_UNBLOCK_CONTACT_THE_ADMIN_STAFF": "Para desbloquear sus proyectos, contacte al administrador." }, - "STATS": { - "PROJECT": "puntos
proyecto", - "DEFINED": "puntos
definidos", - "ASSIGNED": "puntos
asignados", - "CLOSED": "puntos
cerrados" - }, "SECTION": { "SEARCH": "Buscar", "TIMELINE": "Timeline", @@ -893,15 +816,9 @@ "ADMIN": "Admin" }, "NAVIGATION": { - "SECTION_TITLE": "Tus proyectos", - "PLACEHOLDER_SEARCH": "Buscar en...", "ACTION_CREATE_PROJECT": "Crear proyecto", - "ACTION_IMPORT_PROJECT": "Importar proyecto", "MANAGE_PROJECTS": "Administrar proyectos", "TITLE_CREATE_PROJECT": "Crear proyecto", - "TITLE_IMPORT_PROJECT": "Importar proyecto", - "TITLE_PRVIOUS_PROJECT": "Mostrar proyectos anteriores", - "TITLE_NEXT_PROJECT": "Mostrar siguientes proyectos", "HELP_TITLE": "Página de Soporte de Taiga", "HELP": "Ayuda", "HOMEPAGE": "Página de inicio", @@ -909,10 +826,6 @@ "FEEDBACK": "Feedback", "NOTIFICATIONS_TITLE": "Edita la configuración de tus notificaciones", "NOTIFICATIONS": "Notificaciones", - "ORGANIZATIONS_TITLE": "Edita tus organizaciónes", - "ORGANIZATIONS": "Editar organizaciones", - "SETTINGS_TITLE": "Editar tus configuraciones", - "SETTINGS": "Configuraciones", "VIEW_PROFILE_TITLE": "Ver perfil", "VIEW_PROFILE": "Ver perfil", "EDIT_PROFILE_TITLE": "Editar tu perfil", @@ -921,14 +834,68 @@ "CHANGE_PASSWORD": "Cambiar contraseña", "DASHBOARD_TITLE": "Dashboard", "DISCOVER_TITLE": "Descubre los proyectos más relevantes", - "NEW_ITEM": "Nueva", - "DISCOVER": "Descubrir", - "ACTION_REORDER": "Arrastrar y soltar para reordenar" + "DISCOVER": "Descubrir" + }, + "LIKE_BUTTON": { + "LIKE": "Me gusta", + "LIKED": "Me gusta", + "UNLIKE": "Ya no!", + "BUTTON_TITLE": "Marca o desmarcar como favorito este proyecto", + "COUNTER_TITLE": "{total, plural, one{un fan} other{# fans}}" + }, + "WATCH_BUTTON": { + "BUTTON_TITLE": "Observa este proyecto y define la política de notificación", + "WATCH": "Observar", + "WATCHING": "Observando", + "COUNTER_TITLE": "{total, plural, one{un observador} other{# observadores}}", + "OPTIONS": { + "NOTIFY_ALL": "Recibir todas las notificaciones", + "NOTIFY_ALL_TITLE": "Recibir todas las notificaciones de este proyecto", + "NOTIFY_INVOLVED": "Estoy involucrado", + "NOTIFY_INVOLVED_TITLE": "Recibe notificaciones sólo cuando tú estéß involucrado", + "UNWATCH": "No observar", + "UNWATCH_TITLE": "Dejar de observar este proyecto" + } + }, + "CONTACT_BUTTON": { + "CONTACT_TITLE": "Contacta con el equipo de proyecto", + "CONTACT_BUTTON": "Contacta con el proyecto" + }, + "CREATE": { + "TITLE": "Crear Proyecto", + "CHOOSE_TEMPLATE": "¿Que plantilla se ajusta mejor con tu proyecto?", + "TEMPLATE_SCRUM": "Scrum", + "TEMPLATE_SCRUM_DESC": "Prioriza y soluciona tus tareas en ciclos cortos de tiempo.", + "TEMPLATE_SCRUM_LONGDESC": "Scrum es una metodología ágil, iterativa e incremental, de desarrollo de software para la gestión del desarrollo de productos.\nEl backlog de producto es lo que finalmente será entregado, ordenado en el orden que debe ser entregado. El product backlog se divide en trozos manejables y ejecutables llamados sprints. Cada cierto tiempo el equipo inicia un nuevo sprint y se compromete a entregar un número de user stories del backlog, de acuerdo a la capacidad, habilidades y recursos. El proyecto avanza hasta que el backlog se vacía.", + "TEMPLATE_KANBAN": "Kanban", + "TEMPLATE_KANBAN_DESC": "Mantén un flujo constante de tareas independientes", + "TEMPLATE_KANBAN_LONGDESC": "La metodología Kanban se usa para dividir el proceso de desarrollo (o cualquier tipo de proyecto) en etapas. Una tarjeta de Kanban es como una ficha o un post-it que detalla cada tarea (o user story) en un proyecto para ser completada. El tablero de Kanban se usa para mover cada tarjeta de un estado de progreso al siguiente, y de este modo ayuda a trazar el progreso.", + "DUPLICATE": "Duplicar proyecto", + "DUPLICATE_DESC": "Empieza un nuevo proyecto manteniendo tu configuración", + "IMPORT": "Importar proyecto", + "IMPORT_DESC": "Importa tu proyecto desde múltiples plataformas a Taiga", + "INVITE": "Invitar al proyecto", + "SOLO_PROJECT": "Estarás solo en este proyecto", + "INVITE_LATER": "(Podrás invitar otros miembros más adelante)", + "BACK": "Back", + "MAX_PRIVATE_PROJECTS": "l", + "MAX_PUBLIC_PROJECTS": "Desafortunadamente, has alcanzado el número máximo de proyectos públicos.\nSi desea aumentar este limite, por favor contacte al administrador.", + "PUBLIC_PROJECT": "Proyecto público", + "PRIVATE_PROJECT": "Proyecto privado" + }, + "COMMON": { + "DETAILS": "Nuevos detalles del proyecto", + "PROJECT_TITLE": "Nombre del proyecto", + "PROJECT_DESCRIPTION": "Descripción del proyecto" + }, + "DUPLICATE": { + "TITLE": "Duplicar Proyecto", + "DESCRIPTION": "Empieza un nuevo proyecto manteniendo tu configuración", + "SELECT_PLACEHOLDER": "Elije uno de tus proyectos para duplicar" }, "IMPORT": { - "TITLE": "Importando Proyecto", - "UPLOADING_FILE": "Subiendo el fichero con el volcado de datos", - "DESCRIPTION": "Este proceso puede tardar un ratito, por favor mantén la ventana abierta.", + "TITLE": "Importar Proyecto", + "DESCRIPTION": "Importa tu proyecto desde múltiples plataformas a Taiga", "ASYNC_IN_PROGRESS_TITLE": "Nuestros Oompa Loompa están importando tu proyecto", "ASYNC_IN_PROGRESS_MESSAGE": "Este proceso puede llevarnos algún tiempo
Te enviaremos un email cuando esté listo", "UPLOAD_IN_PROGRESS_MESSAGE": "Subidos {{uploadedSize}} de {{totalSize}}", @@ -937,8 +904,29 @@ "ERROR_MESSAGE": "Nuestros Oompa Loompas tienen algunos problemas importando tus datos: {{error_message}}", "ERROR_MAX_SIZE_EXCEEDED": "El fichero '{{fileName}}' ({{fileSize}}) es demasiado pesado para nuestros Oompa Loompas, prueba con uno de menos de ({{maxFileSize}}).", "SYNC_SUCCESS": "Tu proyecto se ha importado con éxito.", + "IMPORT": "Importar", + "WHO_IS": "Sus tareas serán asignadas a...", + "WRITE_EMAIL": "O si tu quieres, escribe el email que este usuario usa en Taiga", + "SEARCH_CONTACT": "O si quieres, busca en tus contactos", + "WRITE_EMAIL_LABEL": "Escribe el email que este usuario usa en Taiga", + "ACCEEDE": "Acceder", + "PROJECT_MEMBERS": "Miembros del proyecto", + "PROCESS_DESCRIPTION": "Dinos a que usuario de Taiga le quieres asignar las tareas de {{platform}}", + "MATCH": "¿{{user_external}} y {{user_internal}} son la misma persona?", + "CHOOSE": "Selecciona un usuario", + "LINKS": "Enlaces con {{platform}}", + "LINKS_DESCRIPTION": "¿Quieres mantener el enlace de cada elemento con la tarjeta original en {{platform}}?", + "WARNING_MAIL_USER": "Tenga en cuenta que si el usuario no tienen cuenta en Taiga no podremos asignarle las tareas.", + "ASSIGN": "Asignar", + "PROJECT_SELECTOR": { + "NO_RESULTS": "Parece que no se encontro nada con este criterio de busqueda", + "ACTION_SEARCH": "buscar", + "ACTION_BACK": "Back" + }, "PROJECT_RESTRICTIONS": { - "PROJECT_MEMBERS_DESC": "El proyecto que esta tratando de importar tiene {{members}} miembros, desafortunadamente, su plna actual solo le permite un maximo de {{max_memberships}} miembros por proyecto. si desea aumentar este limite por favor contacte al administrador.", + "PROJECT_MEMBERS_DESC_PRIVATE": "El proyecto que estas tratando de importar tiene {{members}} miembros incluyéndote a ti, desafortunadamente tu plan actual permite como máximo {{max_memberships}} miembros por proyecto privado. Si quieres aumentar este limite, por favor contacta al administrador.", + "PROJECT_MEMBERS_DESC_PUBLIC": "El proyecto que estas tratando de importar tiene {{members}} miembros incluyéndote a ti, desafortunadamente tu plan actual permite como máximo {{max_memberships}} miembros por proyecto público. Si quieres aumentar este limite, por favor contacta al administrador.", + "ACCOUNT_ALLOW_MEMBERS": "Tu cuenta sólo permite {{members}} miembros", "PRIVATE_PROJECTS_SPACE": { "TITLE": "Desafortunadamente, su plan actual no permite a los proyectos privados adicionales", "DESC": "El proyecto que trata de importar es privado. Desafortunadamente, su plan actual no le permite adicionar mas proyectos privados" @@ -961,39 +949,67 @@ "TITLE": "Desafortunadamente su plan actual no le permite adicionar proyectos publicos o un aumento de {{max_memberships}} miembros por proyecto publico", "DESC": "El proyecto que estás intentando importar es público y tiene más de {{members}} miembros." } - } - }, - "LIKE_BUTTON": { - "LIKE": "Me gusta", - "LIKED": "Me gusta", - "UNLIKE": "Ya no!", - "BUTTON_TITLE": "Marca o desmarcar como favorito este proyecto", - "COUNTER_TITLE": "{total, plural, one{un fan} other{# fans}}" - }, - "WATCH_BUTTON": { - "BUTTON_TITLE": "Observa este proyecto y define la política de notificación", - "WATCH": "Observar", - "WATCHING": "Observando", - "COUNTER_TITLE": "{total, plural, one{un observador} other{# observadores}}", - "OPTIONS": { - "NOTIFY_ALL": "Recibir todas las notificaciones", - "NOTIFY_ALL_TITLE": "Recibir todas las notificaciones de este proyecto", - "NOTIFY_INVOLVED": "Estoy involucrado", - "NOTIFY_INVOLVED_TITLE": "Recibe notificaciones sólo cuando tú estéß involucrado", - "UNWATCH": "No observar", - "UNWATCH_TITLE": "Dejar de observar este proyecto" + }, + "IN_PROGRESS": { + "TITLE": "Importando Proyecto", + "DESCRIPTION": "Este proceso puede tardar un ratito, por favor mantén la ventana abierta." + }, + "WARNING": { + "TITLE": "Algunas tareas estarán sin asignar", + "DESCRIPTION": "Todavía hay gente sin identificar. Las tarjetas asignadas a estas personas se quedarán sin asignar. Revisa todos los contactos para que no se pierda esta información.", + "CHECK": "Verificar contactos" + }, + "TAIGA": { + "SELECTOR": "Importa tu proyecto de Taiga" + }, + "TRELLO": { + "SELECTOR": "Importa tus tableros de Trello en Taiga", + "CHOOSE_PROJECT": "Elige el tablero que quieres importar", + "NO_PROJECTS": "Parece que no tienes tableros en Trello" + }, + "GITHUB": { + "SELECTOR": "Importa tus peticiones de proyecto de GitHub", + "CHOOSE_PROJECT": "Encuentra el proyecto que quieres importar", + "NO_PROJECTS": "Parece que no tienes proyectos en GitHub", + "HOW_DO_YOU_WANT_TO_IMPORT": "¿Cómo quieres importar las peticiones en Taiga?", + "KANBAN_PROJECT": "Como historias de usuario en un proyecto kanban", + "KANBAN_PROJECT_DESCRIPTION": "ll", + "SCRUM_PROJECT": "Como historias de usuario en un proyecto scrum", + "SCRUM_PROJECT_DESCRIPTION": "Después de esto podrás activar el modo kanban", + "ISSUES_PROJECT": "Como petición ", + "ISSUES_PROJECT_DESCRIPTION": "No podrás usar tus peticiones en el modo kanban o scrum. Podrás activar el kanban o scrum para las nuevas historias de usuario" + }, + "ASANA": { + "SELECTOR": "Importa tu proyecto de Asana y elije cómo gestionarlo", + "CHOOSE_PROJECT": "Elige el proyecto que quieres importar", + "NO_PROJECTS": "Parece que no tienes proyectos en Asana", + "KANBAN_PROJECT": "Kanban", + "SCRUM_PROJECT": "Scrum", + "CREATE_AS_SCRUM_DESCRIPTION": "Las tareas y sub-tareas de tu proyecto se crearán como historias de usuario y tareas en Taiga.", + "CREATE_AS_KANBAN_DESCRIPTION": "Las tareas y sub-tareas de tu proyecto se crearán como historias de usuario y tareas en Taiga." + }, + "JIRA": { + "SELECTOR": "Importa tu proyecto de Jira y elije cómo gestionarlo", + "CHOOSE_PROJECT": "Elige el proyecto o panel que quieres importar", + "NO_PROJECTS": "Parece que no tienes proyectos o paneles en Jira", + "URL": "Tu URL de Jira", + "KANBAN_PROJECT": "Kanban", + "SCRUM_PROJECT": "Scrum", + "ISSUES_PROJECT": "Peticiones", + "CREATE_AS_SCRUM_DESCRIPTION": "Las peticiones y sub-peticiones de tu proyecto se crearán como historias de usuario y tareas en Taiga.", + "CREATE_AS_KANBAN_DESCRIPTION": "Las peticiones y sub-peticiones de tu proyecto se crearán como historias de usuario y tareas en Taiga.", + "CREATE_AS_ISSUES_DESCRIPTION": "¿Qué quieres hacer con las sub-peticiones del proyecto de Jira? (Taiga no posee sub-peticiones)", + "CREATE_NEW_ISSUES": "Convertir sub-peticiones como nuevas peticiones de Taiga", + "NOT_CREATE_NEW_ISSUES": "No importar sub-peticiones" } } }, "LIGHTBOX": { "DELETE_ACCOUNT": { - "SECTION_NAME": "Eliminar cuenta de Taiga", "CONFIRM": "¿Está seguro que deseas eliminar tu cuenta de Taiga?", - "NEWSLETTER_LABEL_TEXT": "No quiero recibir la newsletter nunca más.", "CANCEL": "Volver a los ajustes", "ACCEPT": "Eliminar cuenta", - "BLOCK_PROJECT": "Recuerde que todos los proyectos de los cuales usted es dueño seran bloqueados despues de eliminar su cuenta. si desea mantener un proyecto bloqueado, transfiera el dominio a otro usuario en cada proyecto antes de eliminar la cuenta.", - "SUBTITLE": "Sentimos mucho verte ir. Estaremos aquí por si alguna vez nos consideras de nuevo! :(" + "BLOCK_PROJECT": "Recuerde que todos los proyectos de los cuales usted es dueño seran bloqueados despues de eliminar su cuenta. si desea mantener un proyecto bloqueado, transfiera el dominio a otro usuario en cada proyecto antes de eliminar la cuenta." }, "DELETE_PROJECT": { "TITLE": "Borrar proyecto", @@ -1007,6 +1023,12 @@ }, "ADD_MEMBER": { "TITLE": "Nuevo miembro", + "PLACEHOLDER": "Filtra los usuarios o escribe un email para enviar la invitación", + "ADD_EMAIL": "Añade un email", + "REMOVE": "Borrar", + "INVITE": "Invitar", + "CHOOSE_ROLE": "Elije un rol", + "PLACEHOLDER_INVITATION_TEXT": "(Opcional) Añade un texto personalizado a la invitación. Dile algo encantador a tus nuevos miembros ;-)", "HELP_TEXT": "Si los usuarios ya están registrado en Taiga, se añadirán automáticamente. De lo contrario recibirán una invitación." }, "CREATE_ISSUE": { @@ -1068,6 +1090,12 @@ "TITLE": "¿A quién quiere ser el nuevo dueño del proyecto?", "ADD_COMMENT": "Añadir comentario", "BUTTON": "Pregunte a este usuario para convertirlo en el nuero dueño del proyecto" + }, + "CONTACT_PROJECT": { + "TITLE": "Enviar email a", + "WARNING": "Los administradores del proyecto recibirán el email", + "PLACEHOLDER": "Escribe tu mensaje", + "SEND": "Enviar" } }, "EPIC": { @@ -1082,12 +1110,12 @@ "EXISTING_USERSTORY": "Historia de usuario existente", "CHOOSE_PROJECT_FOR_CREATION": "¿Qué es el proyecto?", "SUBJECT": "Asunto", - "SUBJECT_BULK_MODE": "Subject (bulk insert)", + "SUBJECT_BULK_MODE": "Tema (inserción masiva)", "CHOOSE_PROJECT_FROM": "¿Qué es el proyecto?", "CHOOSE_USERSTORY": "Cual es la historia de usuario?", "NO_USERSTORIES": "Este proyecto no tiene historias de usuario todavia. Por favor, seleccione otro proyecto.", "FILTER_USERSTORIES": "Filtrar historias de usuario", - "LIGHTBOX_TITLE_BLOKING_EPIC": "Blocking epic", + "LIGHTBOX_TITLE_BLOKING_EPIC": "Bloqueo de épica", "ACTION_DELETE": "Borrar epic" }, "US": { @@ -1101,15 +1129,9 @@ "ADD_BULK": "Añadir nuevas Historias de Usuario en bloque", "PROMOTED": "Esta historia ha sido promovida desde la petición:", "TITLE_LINK_GO_TO_ISSUE": "Ir a petición", - "EXTERNAL_REFERENCE": "Esta historia ha sido creada desde", - "GO_TO_EXTERNAL_REFERENCE": "Ir al origen", - "BLOCKED": "Esta historia de usuario está bloqueada", "TITLE_DELETE_ACTION": "Borrar Historia de Usuario", "LIGHTBOX_TITLE_BLOKING_US": "Historia bloqueada", - "TASK_COMPLETED": "{{totalClosedTasks}}/{{totalTasks}} tareas completadas", - "ASSIGN": "Asignar Historia de Usuario", "NOT_ESTIMATED": "No estimada", - "TOTAL_US_POINTS": "Total puntos de historia", "TRIBE": { "PUBLISH": "Publicar como Gig en la Tribu Taiga", "PUBLISH_INFO": "Mas información", @@ -1119,23 +1141,19 @@ "CLOSE": "Cerrar", "SYNCHRONIZE_LINK": "sincronizar con la Tribu Taiga", "PUBLISH_MORE_INFO_TITLE": "Necesita a alguien para esta tarea?", - "PUBLISH_MORE_INFO_TEXT": "

SI necesita ayuda con una parte especifica del trabajo puede crear facilmente gigs en la Tribu Taiga y recibir ayuda de todo el mundo. Tendra la habilidad de manejar y controlar su gig disfrutando de una comunidad dispuesta a colaborar.

la Tribu Taiga nacio como una rama de Taiga. Ambas plataformas viven separadas Pero creemos que hay mucho poder al usarlas combinadamente y asi aseguramos que la integracion funciona muy bien.

" + "PUBLISH_MORE_INFO_TEXT": "

Si necesitas ayuda con una tarea en particular, puedes crear 'gigs' en Taiga Tribe y recibir ayuda de todo el mundo. Podrás controlar y gestionar el 'gig' disfrutando de una gran comunidad deseosa de contribuir.

TaigaTribe es el hermano ideal de Taiga. Ambas plataformas pueden vivir separadamente pero creemos que hay mucho poder en usarlas combinadas, por lo que estamos asegurándonos de que la integración entre ambas funcione como un tiro.

" }, "FIELDS": { "TEAM_REQUIREMENT": "Requerido por el Equipo", - "CLIENT_REQUIREMENT": "Requerido por el Cliente", - "FINISH_DATE": "Fecha de finalización" + "CLIENT_REQUIREMENT": "Requerido por el Cliente" } }, "COMMENTS": { "DELETED_INFO": "Comentario borrado por {{user}}", - "TITLE": "Comentarios", "COMMENTS_COUNT": "{{comments}} Comentarios", - "ORDER": "Orden", "OLDER_FIRST": "Mas antiguo primero", "RECENT_FIRST": "Mas reciente primero", "COMMENT": "Comentar", - "EDIT_COMMENT": "Editar comentario", "EDITED_COMMENT": "Editado:", "SHOW_HISTORY": "Ver histórico", "TYPE_NEW_COMMENT": "Escribe un nuevo comentario aquí", @@ -1148,13 +1166,8 @@ } }, "ACTIVITY": { - "SHOW_ACTIVITY": "Mostrar actividad", - "DATETIME": "DD MMM YYYY HH:mm", - "SHOW_MORE": "+ Ver entradas anteriores ({{showMore}} más)", "TITLE": "Actividad", "ACTIVITIES_COUNT": "{{activities}} Actividades", - "REMOVED": "borrado", - "ADDED": "agregado", "TAGS_ADDED": "etiquetas añadidas", "TAGS_REMOVED": "Etiquetas borradas:", "US_POINTS": "{{role}} puntos", @@ -1163,50 +1176,21 @@ "UPDATED_ATTACHMENT": "actualizar adjunto ({{filename}}):", "CREATED_CUSTOM_ATTRIBUTE": "atributo personalizado creado", "UPDATED_CUSTOM_ATTRIBUTE": "atributo personalizado actualizado", - "SIZE_CHANGE": "{size, plural, one{Un cambio realizado} other{# cambios realizados}}", "BECAME_DEPRECATED": "esta obsoleto", "BECAME_UNDEPRECATED": "no esta obsoleto", "TEAM_REQUIREMENT": "Requerido por el Equipo", "CLIENT_REQUIREMENT": "Requerido por el Cliente", "BLOCKED": "Bloqueada", "VALUES": { - "YES": "sí", - "NO": "no", - "EMPTY": "vacío", "UNASSIGNED": "sin asignar" }, "FIELDS": { "SUBJECT": "asunto", - "NAME": "nombre", "DESCRIPTION": "descripción", - "CONTENT": "contenido", "STATUS": "estado", - "IS_CLOSED": "está cerrada", - "FINISH_DATE": "fecha de finalización", "TYPE": "tipo", - "PRIORITY": "prioridad", - "SEVERITY": "gravedad", "ASSIGNED_TO": "asignado a", - "WATCHERS": "observadores", "MILESTONE": "sprint", - "USER_STORY": "historia de usuario", - "PROJECT": "proyecto", - "IS_BLOCKED": "está bloqueada", - "BLOCKED_NOTE": "motivo del bloqueo", - "POINTS": "puntos", - "CLIENT_REQUIREMENT": "requerido por el cliente", - "TEAM_REQUIREMENT": "requerido por el equipo", - "IS_IOCAINE": "tiene iocaína", - "TAGS": "etiquetas", - "ATTACHMENTS": "adjuntos", - "IS_DEPRECATED": "está desactualizado", - "IS_NOT_DEPRECATED": "No es obsoleto", - "ORDER": "orden", - "BACKLOG_ORDER": "orden en backlog", - "SPRINT_ORDER": "orden en sprint", - "KANBAN_ORDER": "orden en kanban", - "TASKBOARD_ORDER": "orden en panel de tareas", - "US_ORDER": "orden en historia", "COLOR": "color" } }, @@ -1220,8 +1204,6 @@ "CUSTOMIZE_GRAPH_TITLE": "Modifica los puntos y sprints a través de la zona de Administración", "MOVE_US_TO_CURRENT_SPRINT": "Mover al Sprint en curso", "MOVE_US_TO_LATEST_SPRINT": "Mover al Sprint más reciente", - "SHOW_FILTERS": "Mostrar filtros", - "SHOW_TAGS": "Ver etiquetas", "EMPTY": "¡El backlog está vacío!", "CREATE_NEW_US": "Crear una nueva historia", "CREATE_NEW_US_EMPTY_HELP": "Es posible que desees crear una nueva historia de usuario", @@ -1248,6 +1230,12 @@ "SHOW": "Mostrar etiquetas", "HIDE": "Ocultar etiquetas" }, + "FORECASTING": { + "TITLE": "Previsión de velocidad", + "BACKLOG": "Mostrar el backlog", + "NEW_SPRINT": "Historias de Usuarios candidatas para el próximo sprint, basado en tu velocidad. Haga clic para crear un nuevo sprint.", + "CURRENT_SPRINT": "Historias de Usuarios candidatas para el sprint, basado en tu velocidad. Haga clic para añadirlas al sprint en curso." + }, "TABLE": { "COLUMN_US": "Historias de Usuario", "TITLE_COLUMN_POINTS": "Seleccionar vista por Rol" @@ -1270,8 +1258,6 @@ }, "FILTERS": { "TOGGLE": "Cambia la visibilidad de los filtros", - "TITLE": "Filtros", - "REMOVE": "Borrar Filtros", "HIDE": "Ocultar filtros", "SHOW": "Ver Filtros" }, @@ -1280,7 +1266,6 @@ "DATE": "DD MMM YYYY", "LINK_TASKBOARD": "Panel de Tareas del Sprint", "TITLE_LINK_TASKBOARD": "Ir al panel de tareas de \"{{name}}\"", - "NUMBER_SPRINTS": "
sprints", "EMPTY": "Todavía no hay Sprints", "WARNING_EMPTY_SPRINT_ANONYMOUS": "Este sprint no tiene historias de usuario", "WARNING_EMPTY_SPRINT": "Arrastra aquí las historias desde tu backlog para comenzar un nuevo sprint", @@ -1305,7 +1290,6 @@ "TITLE_ACTION_ADD": "Añade una nueva tarea", "TITLE_ACTION_ADD_BULK": "Añadir nuevas tareas en bloque", "TITLE_ACTION_ASSIGN": "Asignar tarea", - "TITLE_ACTION_EDIT": "Editar tarea", "PLACEHOLDER_CARD_TITLE": "Esto podría ser una tarea", "PLACEHOLDER_CARD_TEXT": "Divide las historias en tareas para controlarlas de manera separada", "TABLE": { @@ -1335,17 +1319,11 @@ "TITLE_SELECT_STATUS": "Nombre del estado", "OWNER_US": "Esta tarea pertenece a\n", "TITLE_LINK_GO_OWNER": "Ir a historia de usuario", - "ORIGIN_US": "Esta tarea pertenece a ", - "TITLE_LINK_GO_ORIGIN": "Ir a historia de usuario", - "BLOCKED": "Esta tarea está bloqueada", "TITLE_DELETE_ACTION": "Eliminar Tarea", "LIGHTBOX_TITLE_BLOKING_TASK": "Tarea bloqueada", "FIELDS": { - "MILESTONE": "Sprint", - "USER_STORY": "Historia de usuario", "IS_IOCAINE": "Tiene iocaína" }, - "ACTION_IOCAINE": "Iocaína", "TITLE_ACTION_IOCAINE": "¿Te sientes fuera de tu zona de confort en una tarea? Asegúrate de que los demás están al tanto de ello, marca el check de la Iocaína al editar una tarea. Igual eu era posible llegar a ser inmune a este veneno mortal a base de consumir pequeñas dosis a lo largo del tiempo, es posible conseguir mejor en lo que estás haciendo si afrontas de vez en cuando esta clase de retos!" }, "NOTIFICATION": { @@ -1374,14 +1352,12 @@ "ISSUES": { "PAGE_TITLE": "Peticiones - {{projectName}}", "PAGE_DESCRIPTION": "El panel de peticiones del proyecto {{projectName}}: {{projectDescription}}\n", - "LIST_SECTION_NAME": "Peticiones", "SECTION_NAME": "Petición", "ACTION_NEW_ISSUE": "+ NUEVA PETICIÓN", "ACTION_PROMOTE_TO_US": "Promover a Historia de Usuario", "PROMOTED": "Esta petición ha sido promovida a la historia:", "EXTERNAL_REFERENCE": "Esta petición ha sido creada a partir de ", "GO_TO_EXTERNAL_REFERENCE": "Ir al origen", - "BLOCKED": "La petición está bloqueada", "ACTION_DELETE": "Borrar petición", "LIGHTBOX_TITLE_BLOKING_ISSUE": "Petición bloqueada", "FIELDS": { @@ -1423,15 +1399,11 @@ "SECTION_NAME": "Kanban", "TITLE_ACTION_FOLD": "Plegar columna", "TITLE_ACTION_UNFOLD": "Desplegar columna", - "TITLE_ACTION_FOLD_CARDS": "Plegar tarjetas", - "TITLE_ACTION_UNFOLD_CARDS": "Desplegar tarjetas", "TITLE_ACTION_ADD_US": "Añadir Nueva Historia de Usuario", "TITLE_ACTION_ADD_BULK": "Añadir nuevas en bloque", "ACTION_SHOW_ARCHIVED": "Ver archivados", "ACTION_HIDE_ARCHIVED": "Ocultar archivados", "HIDDEN_USER_STORIES": "Las historias de usuario en este estado están ocultas por defecto", - "ARCHIVED": "Tu has archivado", - "UNDO_ARCHIVED": "Arrástrala y suéltala de nuevo para deshacer el cambio", "PLACEHOLDER_CARD_TITLE": "Estas son tus Historias de Usuario", "PLACEHOLDER_CARD_TEXT": "Las historias pueden tener tareas para separar los requerimientos" }, @@ -1452,7 +1424,6 @@ "PAGE_TITLE": "Equipo - {{projectName}}", "PAGE_DESCRIPTION": "EL panel de equipo, para mostrar a todos los miembros del proyecto {{projectName}}: {{projectDescription}}", "SECTION_NAME": "Equipo", - "APP_TITLE": "EQUIPO - {{projectName}}", "PLACEHOLDER_INPUT_SEARCH": "Buscar por nombre completo...", "COLUMN_MR_WOLF": "Sr. Lobo", "EXPLANATION_COLUMN_MR_WOLF": "Peticiones cerradas", @@ -1488,18 +1459,9 @@ "OPTION_ALL": "Todas", "OPTION_INVOLVED": "Involucrado", "OPTION_NONE": "Ninguna" - }, - "POPOVER": { - "USER_PROFILE": "Perfil de Usuario", - "CHANGE_PASSWORD": "Cambiar contraseña", - "NOTIFICATIONS": "Notificaciones", - "FEEDBACK": "Feedback", - "TITLE_AVATAR": "Preferencias de usuario" } }, "USER_PROFILE": { - "IMAGE_HELP": "La imagen se escalará a 80x80px.", - "ACTION_CHANGE_IMAGE": "Cambiar", "ACTION_USE_GRAVATAR": "Usar imagen por defecto", "ACTION_DELETE_ACCOUNT": "Elimina cuenta de Taiga", "CHANGE_EMAIL_SUCCESS": "¡Revisa tu bandeja de entrada!
Hemos enviado un mail a tu cuenta
con instrucciones para establecer tu nueva dirección", @@ -1517,25 +1479,10 @@ "THEME_DEFAULT": "-- usar tema por defecto --" } }, - "WIZARD": { - "SECTION_TITLE_CREATE_PROJECT": "Crear Proyecto", - "CREATE_PROJECT_TEXT": "Fresco y claro. ¡Es emocionante!", - "CHOOSE_TEMPLATE": "¿Que plantilla se ajusta mejor con tu proyecto?", - "CHOOSE_TEMPLATE_TITLE": "Mas informacion acerca de la plantillas del proyecto", - "CHOOSE_TEMPLATE_INFO": "Mas información", - "PROJECT_DETAILS": "Detalles del proyecto", - "PUBLIC_PROJECT": "Proyecto público", - "PRIVATE_PROJECT": "Proyecto privado", - "CREATE_PROJECT": "Crear proyecto", - "MAX_PRIVATE_PROJECTS": "Has alcanzado el número máximo de proyectos privados", - "MAX_PUBLIC_PROJECTS": "Desafortunadamente, has alcanzado el número máximo de proyectos públicos", - "CHANGE_PLANS": "cambiar planes" - }, "WIKI": { "PAGE_TITLE": "{{wikiPageName}} - Wiki - {{projectName}}", "PAGE_DESCRIPTION": "última edición el {{lastModifiedDate}} ({{totalEditions}} ediciones en total) Contenido: {{ wikiPageContent }}", "DATETIME": "DD MMM YYYY HH:mm", - "PLACEHOLDER_PAGE": "Escribe el contenido de tu página", "REMOVE": "Eliminar esta página del wiki", "DELETE_LIGHTBOX_TITLE": "Eliminar Página del Wiki", "DELETE_LINK_TITLE": "Eliminar enlace de la Wiki", @@ -1693,7 +1640,6 @@ "MOST_LIKED": "Favoritos", "MOST_LIKED_EMPTY": "No hay proyectos marcados como FAVORITOS todavía.", "VIEW_MORE": "Ver más", - "RECRUITING": "Este proyecto está buscando a gente", "FEATURED": "Proyectos Destacados", "EMPTY": "No hay proyectos que mostrar para estos criterios de búsqueda.
¡Inténtalo de nuevo!", "FILTERS": { diff --git a/app/locales/taiga/locale-fi.json b/app/locales/taiga/locale-fi.json index 0934d020..3ed4ff5d 100644 --- a/app/locales/taiga/locale-fi.json +++ b/app/locales/taiga/locale-fi.json @@ -4,7 +4,6 @@ "NO": "Ei", "OR": "or", "LOADING": "Ladataan...", - "LOADING_PROJECT": "Ladataan projektia...", "DATE": "DD.MM.YY", "DATETIME": "DD.MM.YY - HH:mm", "SAVE": "Tallenna", @@ -27,12 +26,9 @@ "BLOCKED_NOTE": "Why is this blocked?", "BLOCKED_REASON": "Ole hyvä ja anna syy", "CREATED_BY": "Luonut {{fullDisplayName}}", - "FROM": "käyttäjältä", - "TO": "käyttäjälle", "CLOSE": "sulje", "GO_HOME": "Vie minut kotiin", "PLUGINS": "Pluginit", - "BETA": "Tämä on beta-versio!", "ONE_ITEM_LINE": "Yksi riviä kohti...", "NEW_BULK": "Lisää monta", "RELATED_TASKS": "Liittyvät tehtävät", @@ -41,7 +37,7 @@ "LOGOUT": "Kirjaudu ulos", "EXTERNAL_USER": "ulkoinen käyttäjä", "GENERIC_ERROR": "Oompa Loompas havaitsivat virheen {{error}}.", - "IOCAINE_TEXT": "Jos tehtävä ahdistaa, merkitse se myrkylliseksi. Ajan mittaa pieninä annoksina saattaa kastokykysi myrkkyä vastaan parantua.", + "IOCAINE_TEXT": "This member is feeling a bit overwhelmed by this task. Will become immune to the iocaine poison over time with your help. For now, may need a hug.", "CLIENT_REQUIREMENT": "Client requirement is new requirement that was not previously expected and it is required to be part of the project", "TEAM_REQUIREMENT": "Team requirement is a requirement that must exist in the project but should have no cost for the client", "OWNER": "Project Owner", @@ -148,7 +144,6 @@ "PRIORITY": "Tärkeys", "ASSIGNED_TO": "Tekijä", "POINTS": "Pisteet", - "BLOCKED_NOTE": "estetty muistiinpano", "IS_BLOCKED": "on estetty", "REF": "Ref", "VOTES": "Ääniä", @@ -187,10 +182,6 @@ "COUNTER_TITLE": "{total, plural, one{one watcher} other{# watchers}}" }, "VOTE_BUTTON": { - "UPVOTE": "Upvote", - "UPVOTED": "Upvoted", - "DOWNVOTE": "Downvote", - "VOTERS": "Voters", "BUTTON_TITLE": "Upvote/Downvote this item", "COUNTER_TITLE": "{total, plural, one{one vote} other{# votes}}" }, @@ -202,10 +193,9 @@ "CONFIRM_DELETE": "Remeber that all values in this custom field will be deleted.\n Are you sure you want to continue?" }, "FILTERS": { - "TITLE": "Suodattimet", "INPUT_PLACEHOLDER": "Aihe tai viittaus", "TITLE_ACTION_FILTER_BUTTON": "hae", - "INPUT_SEARCH_PLACEHOLDER": "Otsikko tai viittaus", + "TITLE": "Suodattimet", "TITLE_ACTION_SEARCH": "Hae", "ACTION_SAVE_CUSTOM_FILTER": "tallenna omaksi suodattimeksi", "PLACEHOLDER_FILTER_NAME": "Anna suodattimen nimi ja paina enter", @@ -220,41 +210,10 @@ "CREATED_BY": "Luoja", "CUSTOM_FILTERS": "Omat suodattimet", "EPIC": "Epic" - }, - "CONFIRM_DELETE": { - "TITLE": "Poista oma suodatin", - "MESSAGE": "oma suodatin '{{customFilterName}}'" } }, "WYSIWYG": { - "H1_BUTTON": "Päätason otsikko", - "H1_SAMPLE_TEXT": "Nimikkeesei tänne...", - "H2_BUTTON": "Toisen tason otsikko", - "H2_SAMPLE_TEXT": "Nimikkeesi tänne...", - "H3_BUTTON": "Kolmannen tason otsikko", - "H3_SAMPLE_TEXT": "Nimikkeesi tänne...", - "BOLD_BUTTON": "Lihavoitu", - "BOLD_BUTTON_SAMPLE_TEXT": "Kirjoita tänne...", - "ITALIC_BUTTON": "Kursiivi", - "ITALIC_SAMPLE_TEXT": "Kirjoita tänne...", - "STRIKE_BUTTON": "Lakko", - "STRIKE_SAMPLE_TEXT": "Kirjoita tänne...", - "BULLETED_LIST_BUTTON": "Numeroimaton lista", - "BULLETED_LIST_SAMPLE_TEXT": "Kirjoita tänne...", - "NUMERIC_LIST_BUTTON": "Numeroitu lista", - "NUMERIC_LIST_SAMPLE_TEXT": "Kirjoita tänne...", - "PICTURE_BUTTON": "Kuva", - "PICTURE_SAMPLE_TEXT": "Vaihtoehtoinen kuvan teksti tänne...", - "LINK_BUTTON": "Linkki", - "LINK_SAMPLE_TEXT": "Linkkiteksti tänne...", - "QUOTE_BLOCK_BUTTON": "Lainaus", - "QUOTE_BLOCK_SAMPLE_TEXT": "Kirjoita tänne...", - "CODE_BLOCK_BUTTON": "Koodi-lohko", - "CODE_BLOCK_SAMPLE_TEXT": "Kirjoita tänne...", - "PREVIEW_BUTTON": "Esikatselu", - "EDIT_BUTTON": "Muokkaa", - "ATTACH_FILE_HELP": "Attach files by dragging & dropping on the textarea above.", - "ATTACH_FILE_HELP_SAVE_FIRST": "Save first before if you want to attach files by dragging & dropping on the textarea above.", + "OUTDATED": "Another person has made changes while you were editing. Check the new version on the activiy tab before you save your changes.", "MARKDOWN_HELP": "Merkintätavan ohjeet" }, "PERMISIONS_CATEGORIES": { @@ -307,10 +266,6 @@ "ADD_WIKI_LINKS": "Lisää wiki-linkkejä", "DELETE_WIKI_LINKS": "Poista wiki-linkkejä" } - }, - "META": { - "PAGE_TITLE": "Taiga", - "PAGE_DESCRIPTION": "Taiga is a project management platform for startups and agile developers & designers who want a simple, beautiful tool that makes work truly enjoyable." } }, "LOGIN": { @@ -366,7 +321,6 @@ }, "CHANGE_PASSWORD": { "PAGE_TITLE": "Change you password - Taiga", - "PAGE_DESCRIPTION": "Set a new password for your Taiga account and hey!, you may want to eat some more iron-rich food, it's good for your brain :P", "SECTION_NAME": "Muuta salasanaa", "FIELD_CURRENT_PASSWORD": "Nykyinen salasana", "PLACEHOLDER_CURRENT_PASSWORD": "Nykyinen salasanasi (tai on tyhjä jos sinulla ei vielä ole)", @@ -391,8 +345,7 @@ }, "INVITATION_LOGIN_FORM": { "NOT_FOUND": "Our Oompa Loompas can't find your invitation.", - "SUCCESS": "Olet onnistuneesti liittynyt projektiin {{project_name}}. Tervetuloa!", - "ERROR": "Oompa Loompas sanovat että käyttäjänimesi tai sähköpostisi tai salasanasi on väärä." + "SUCCESS": "Olet onnistuneesti liittynyt projektiin {{project_name}}. Tervetuloa!" }, "HOME": { "PAGE_TITLE": "Home - Taiga", @@ -463,10 +416,7 @@ "TITLE_LIGHTBOX_DELETE_ATTACHMENT": "Poista liite...", "MSG_LIGHTBOX_DELETE_ATTACHMENT": "liite '{{fileName}}'", "ERROR_DELETE_ATTACHMENT": "Emme pystyneet poistamaan: {{errorMessage}}", - "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) on liian iso Oompa Loompaseille, kokeile pienemmällä kuin ({{maxFileSize}})", - "FIELDS": { - "IS_DEPRECATED": "on vanhentunut" - } + "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) on liian iso Oompa Loompaseille, kokeile pienemmällä kuin ({{maxFileSize}})" }, "PAGINATION": { "PREVIOUS": "Edellinen", @@ -502,13 +452,10 @@ "ASYNC_MESSAGE": "Lähetämme sähköpostia, kun on valmista.", "SYNC_MESSAGE": "Jos lataus ei ala automaattisesti klikkaa tästä.", "ERROR": "Oompa Loompas eivät onnistuneet tekemään tiedostoasi. Yritä uudelleen.", - "ERROR_BUSY": "Valitettavasti Oompa Loompas ovat kiireisiä juuri. Yritä kohta uudestaan.", - "ERROR_MESSAGE": "Oompa Loompas eivät onnistuneet luomaan tiedostoasi: {{message}}" + "ERROR_BUSY": "Valitettavasti Oompa Loompas ovat kiireisiä juuri. Yritä kohta uudestaan." }, "MODULES": { "TITLE": "Modulit", - "ENABLE": "Aktivoi", - "DISABLE": "Passivoi", "EPICS": "Epics", "EPICS_DESCRIPTION": "Visualize and manage the most strategic part of your project", "BACKLOG": "Odottavat", @@ -537,17 +484,16 @@ "PAGE_TITLE": "{{sectionName}} - Projektin profiili - {{projectName}}", "PROJECT_DETAILS": "Projektin tiedot", "PROJECT_NAME": "Projektin nimi", - "PROJECT_SLUG": "Projektin hukka-aika", "TAGS": "Avainsanat", "DESCRIPTION": "Kuvaus", "RECRUITING": "Is this project looking for people?", "RECRUITING_MESSAGE": "Who are you looking for?", "RECRUITING_PLACEHOLDER": "Define the profiles you are looking for", + "FEEDBACK": "Receive feedback from Taiga users?", "PUBLIC_PROJECT": "Julkinen projekti", "PRIVATE_PROJECT": "Yksityinen projekti", "PRIVATE_OR_PUBLIC": "What's the difference between public and private projects?", "DELETE": "Poista tämä projekti", - "LOGO_HELP": "The image will be scaled to 80x80px.", "CHANGE_LOGO": "Change logo", "ACTION_USE_DEFAULT_LOGO": "Use default image", "MAX_PRIVATE_PROJECTS": "You've reached the maximum number of private projects allowed by your current plan", @@ -595,6 +541,7 @@ "ISSUE_DESCRIPTION": "Pyyntöjen omat kentät", "ISSUE_ADD": "Lisää oma kenttä pyynnöille", "FIELD_TYPE_TEXT": "Text", + "FIELD_TYPE_RICHTEXT": "Rich text", "FIELD_TYPE_MULTI": "Multi-line", "FIELD_TYPE_DATE": "Date", "FIELD_TYPE_URL": "Url" @@ -623,7 +570,7 @@ "ACTION_ADD": "Lisää uusi vakavuus" }, "PROJECT_VALUES_STATUS": { - "TITLE": "Tila", + "TITLE": "Statuses", "SUBTITLE": "Määrittele tilat joiden kautta käyttäjätarinasi, tehtäväsi ja pyyntösi kulkevat", "EPIC_TITLE": "Epic Statuses", "US_TITLE": "User Story Statuses", @@ -676,8 +623,8 @@ "INFO_VERIFYING_IP": "Gitlab pyynnöt eivät ole allekirjoitettuja joten tarkista IP. Jos IP on tyhjä, ei sitä tarkisteta." }, "GITHUB": { - "SECTION_NAME": "Github", - "PAGE_TITLE": "Github - {{projectName}}" + "SECTION_NAME": "GitHub", + "PAGE_TITLE": "GitHub - {{projectName}}" }, "GOGS": { "SECTION_NAME": "Gogs", @@ -686,7 +633,6 @@ "WEBHOOKS": { "PAGE_TITLE": "Webhooks - {{projectName}}", "SECTION_NAME": "Webhookit", - "SUBTITLE": "Webhookit ilmoittvat ulkoisille palveluille Taigan kommenteista, käyttäjätarinoista ...", "ADD_NEW": "Lisää webhook", "TYPE_NAME": "Anna palvelun nimi", "TYPE_PAYLOAD_URL": "Anna palvelun yhteysosoite (URL)", @@ -732,7 +678,6 @@ "DELETE_MEMBER": "Poista jäsen", "RESEND": "Resend", "SUCCESS_SEND_INVITATION": "Olemme lähettäneet kutsun uudelleen osoitteeseen '{{email}}'.", - "ERROR_SEND_INVITATION": "Olemme lähettäneet kutsun.", "SUCCESS_DELETE": "Olemme poistaneet viestin {{message}}.", "ERROR_DELETE": "Emme pystyneet poistamaan viestiä {{message}}.", "DEFAULT_DELETE_MESSAGE": "kutsu sähköpostiin {{email}}" @@ -761,16 +706,11 @@ "PLACEHOLDER_WRITE_NAME": "Anna uuden tilan nimi" }, "MENU": { - "TITLE": "Hallinnoi", "PROJECT": "Projekti", "ATTRIBUTES": "Attribuutit", "MEMBERS": "Jäsenet", "PERMISSIONS": "Oikeudet", - "INTEGRATIONS": "Intergraatiot", - "PLUGINS": "Pluginit" - }, - "SUBMENU_PROJECT_ATTRIBUTES": { - "TITLE": "Attribuutit" + "INTEGRATIONS": "Intergraatiot" }, "SUBMENU_PROJECT_VALUES": { "STATUS": "Tila", @@ -781,17 +721,11 @@ "CUSTOM_FIELDS": "Omat kentät", "TAGS": "Avainsanat" }, - "SUBMENU_PROJECT_PROFILE": { - "TITLE": "Projektin profiili" - }, "SUBMENU_ROLES": { "TITLE": "Roolit", "ACTION_NEW_ROLE": "+ Uusi rooli", "TITLE_ACTION_NEW_ROLE": "Lisää uusi rooli" }, - "SUBMENU_THIDPARTIES": { - "TITLE": "Palvelut" - }, "PROJECT_TRANSFER": { "DO_YOU_ACCEPT_PROJECT_OWNERNSHIP": "Would you like to become the new project owner?", "PRIVATE": "Private", @@ -806,15 +740,13 @@ "PRIVATE": "Please remember that you can own up to {{maxProjects}} private projects. You currently own {{currentProjects}} private projects", "PUBLIC": "Please remember that you can own up to {{maxProjects}} public projects. You currently own {{currentProjects}} public projects" }, - "CANT_BE_OWNED": "At the moment you cannot become an owner of a project of this type. If you would like to become the owner of this project, please contact the administrator so they change your account settings to enable project ownership.", - "CHANGE_MY_PLAN": "Change my plan" + "CANT_BE_OWNED": "At the moment you cannot become an owner of a project of this type. If you would like to become the owner of this project, please contact the administrator so they change your account settings to enable project ownership." } }, "USER": { "PROFILE": { "PAGE_TITLE": "{{userFullName}} (@{{userUsername}})", "EDIT": "Edit profile", - "FOLLOW": "Follow", "CLOSED_US": "Closed US", "PROJECTS": "Projektit", "PROJECTS_EMPTY": "{{username}} doesn't' have projects yet", @@ -822,7 +754,6 @@ "CONTACTS_EMPTY": "{{username}} doesn't have contacts yet", "CURRENT_USER_CONTACTS_EMPTY": "You don't have contacts yet", "CURRENT_USER_CONTACTS_EMPTY_EXPLAIN": "The people with whom you work at Taiga will be your contacts automatically", - "REPORT": "Report Abuse", "TABS": { "ACTIVITY_TAB": "Timeline", "ACTIVITY_TAB_TITLE": "Show all the activity of this user", @@ -848,13 +779,13 @@ "FILTER_TYPE_ALL": "Kaikki", "FILTER_TYPE_ALL_TITLE": "Show all", "FILTER_TYPE_PROJECTS": "Projektit", - "FILTER_TYPE_PROJECT_TITLES": "Show only projects", + "FILTER_TYPE_PROJECTS_TITLE": "Show only projects", "FILTER_TYPE_EPICS": "Epics", - "FILTER_TYPE_EPIC_TITLES": "Show only epics", + "FILTER_TYPE_EPICS_TITLE": "Show only epics", "FILTER_TYPE_USER_STORIES": "Stories", - "FILTER_TYPE_USER_STORIES_TITLES": "Show only user stories", + "FILTER_TYPE_USER_STORIES_TITLE": "Show only user stories", "FILTER_TYPE_TASKS": "Tehtävät", - "FILTER_TYPE_TASK_TITLES": "Show only tasks", + "FILTER_TYPE_TASKS_TITLE": "Show only tasks", "FILTER_TYPE_ISSUES": "Pyynnöt", "FILTER_TYPE_ISSUES_TITLE": "Show only issues", "EMPTY_TITLE": "It looks like there's nothing to show here." @@ -862,8 +793,6 @@ }, "PROJECT": { "PAGE_TITLE": "{{projectName}}", - "WELCOME": "Tervetuloa", - "SECTION_PROJECTS": "Projektit", "HELP": "Reorder your projects to set in the top the most used ones.
The top 10 projects will appear in the top navigation bar project list", "PRIVATE": "Yksityinen projekti", "LOOKING_FOR_PEOPLE": "This project is looking for people", @@ -875,12 +804,6 @@ "THIS_PROJECT_IS_BLOCKED": "This project is temporarily blocked", "TO_UNBLOCK_CONTACT_THE_ADMIN_STAFF": "In order to unblock your projects, contact the administrator." }, - "STATS": { - "PROJECT": "projekti
pisteet", - "DEFINED": "määritely
pistettä", - "ASSIGNED": "kohdistettu
pistettä", - "CLOSED": "suljettu
pistettä" - }, "SECTION": { "SEARCH": "Hae", "TIMELINE": "Timeline", @@ -893,15 +816,9 @@ "ADMIN": "Hallinnoi" }, "NAVIGATION": { - "SECTION_TITLE": "Projektisi", - "PLACEHOLDER_SEARCH": "Hae täältä...", "ACTION_CREATE_PROJECT": "Luo projekti", - "ACTION_IMPORT_PROJECT": "Import project", "MANAGE_PROJECTS": "Manage projects", "TITLE_CREATE_PROJECT": "Create project", - "TITLE_IMPORT_PROJECT": "Import project", - "TITLE_PRVIOUS_PROJECT": "Näytä aikaisemmat projektit", - "TITLE_NEXT_PROJECT": "Näytä seuraavat projektit", "HELP_TITLE": "Taiga Support Page", "HELP": "Help", "HOMEPAGE": "Homepage", @@ -909,10 +826,6 @@ "FEEDBACK": "Palaute", "NOTIFICATIONS_TITLE": "Edit your notification settings", "NOTIFICATIONS": "Ilmoitukset", - "ORGANIZATIONS_TITLE": "Edit your organizations", - "ORGANIZATIONS": "Edit organizations", - "SETTINGS_TITLE": "Edit your settings", - "SETTINGS": "Settings", "VIEW_PROFILE_TITLE": "View Profile", "VIEW_PROFILE": "View Profile", "EDIT_PROFILE_TITLE": "Edit your profile", @@ -921,24 +834,99 @@ "CHANGE_PASSWORD": "Muuta salasanaa", "DASHBOARD_TITLE": "Dashboard", "DISCOVER_TITLE": "Discover trending projects", - "NEW_ITEM": "Uusi", - "DISCOVER": "Discover", - "ACTION_REORDER": "Drag & drop to reorder" + "DISCOVER": "Discover" + }, + "LIKE_BUTTON": { + "LIKE": "Like", + "LIKED": "Liked", + "UNLIKE": "Unlike", + "BUTTON_TITLE": "Like or unlike this project", + "COUNTER_TITLE": "{total, plural, one{one fan} other{# fans}}" + }, + "WATCH_BUTTON": { + "BUTTON_TITLE": "Watch this project and set notification policy", + "WATCH": "Watch", + "WATCHING": "Seuraa", + "COUNTER_TITLE": "{total, plural, one{one watcher} other{# watchers}}", + "OPTIONS": { + "NOTIFY_ALL": "Receive all notifications", + "NOTIFY_ALL_TITLE": "Receive all notifications for this project", + "NOTIFY_INVOLVED": "Only involved", + "NOTIFY_INVOLVED_TITLE": "Recive notificacions only when you are involved", + "UNWATCH": "Unwatch", + "UNWATCH_TITLE": "Unwatch this project" + } + }, + "CONTACT_BUTTON": { + "CONTACT_TITLE": "Contact the project team", + "CONTACT_BUTTON": "Contact the project" + }, + "CREATE": { + "TITLE": "Luo projekti", + "CHOOSE_TEMPLATE": "Which template fits your project better?", + "TEMPLATE_SCRUM": "Scrum", + "TEMPLATE_SCRUM_DESC": "Prioritize and solve your tasks in short time cycles.", + "TEMPLATE_SCRUM_LONGDESC": "Scrum is an iterative and incremental agile software development methodology for managing product development.\nThe product backlog is what will ultimately be delivered, ordered into the sequence in which it should be delivered. Product Backlogs are broken into manageable, executable chunks named sprints. Every certain amount of time the team initiates a new sprint and commits to deliver a certain number of user stories from the backlog, in accordance with their skills, abilities and resources. The project advances as the backlog becomes depleted.", + "TEMPLATE_KANBAN": "Kanban", + "TEMPLATE_KANBAN_DESC": "Keep a constant workflow on independent tasks", + "TEMPLATE_KANBAN_LONGDESC": "The Kanban methodology is used to divide project development (any sort of project) into stages.\nA kanban card is like an index card or post-it note that details every task (or user story) in a project that needs to be completed. The Kanban board is used to move each card from one state of completion to the next and in so doing, helps track progress.", + "DUPLICATE": "Duplicate project", + "DUPLICATE_DESC": "Start clean and keep your configuration", + "IMPORT": "Luo projekti tiedostosta", + "IMPORT_DESC": "Import your project from multiple platforms into Taiga", + "INVITE": "Invite to the project", + "SOLO_PROJECT": "You'll be alone in this project", + "INVITE_LATER": "(You'll be able to invite more members later)", + "BACK": "Palvelin", + "MAX_PRIVATE_PROJECTS": "Unfortunately, You've reached the maximum number of private projects.\nIf you would like to increase the current limit please contact the administrator.", + "MAX_PUBLIC_PROJECTS": "Unfortunately, You've reached the maximum number of public projects.\nIf you would like to increase the current limit please contact the administrator.", + "PUBLIC_PROJECT": "Public Project", + "PRIVATE_PROJECT": "Private Project" + }, + "COMMON": { + "DETAILS": "New project details", + "PROJECT_TITLE": "Project Name", + "PROJECT_DESCRIPTION": "Project Description" + }, + "DUPLICATE": { + "TITLE": "Duplicate Project", + "DESCRIPTION": "Start clean and keep your configuration", + "SELECT_PLACEHOLDER": "Choose an existing project to duplicate" }, "IMPORT": { - "TITLE": "Luetaan sisään projektia", - "UPLOADING_FILE": "Ladataan tiedostoa", - "DESCRIPTION": "Tämä voi kestää hetken, pidä ikkuna auki.", + "TITLE": "Import Project", + "DESCRIPTION": "Import your project from multiple platforms into Taiga", "ASYNC_IN_PROGRESS_TITLE": " Oompa Loompas tuovat projektia", "ASYNC_IN_PROGRESS_MESSAGE": "Tämä voi kestää muutaman minuutin
Lähetämme sähköpostin on valmista", "UPLOAD_IN_PROGRESS_MESSAGE": "LAdattu {{uploadedSize}} / {{totalSize}}", "ERROR": "Oompa Loompas eivät onnistuneet tuomaan tiedostoasi. Yritä uudestaan.", - "ERROR_TOO_MANY_REQUEST": "Oompa Loompas ovat kiireisiä juuri nyt. Yritä hetken päästä uudelleen.", + "ERROR_TOO_MANY_REQUEST": "Valitettavasti Oompa Loompas ovat kiireisiä juuri. Yritä kohta uudestaan.", "ERROR_MESSAGE": "Oompa Loompas eivät pysty lukemaan tiedostoasi: {{error_message}}", "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) on liian iso Oompa Loompaseille, kokeile pienemmällä kuin ({{maxFileSize}})", "SYNC_SUCCESS": "Projektisi on tuotu sisään onnistuneesti", + "IMPORT": "Import", + "WHO_IS": "Their tasks will be assigned to ...", + "WRITE_EMAIL": "Or if you want, write the email that this user uses in Taiga", + "SEARCH_CONTACT": "Or if you want, search in your contacts", + "WRITE_EMAIL_LABEL": "Write the email that this user uses in Taiga", + "ACCEEDE": "Acceede", + "PROJECT_MEMBERS": "Project Members", + "PROCESS_DESCRIPTION": "Tell us who from Taiga you want to assign the tasks of {{platform}}", + "MATCH": "Is {{user_external}} the same person as {{user_internal}}?", + "CHOOSE": "Select user", + "LINKS": "Links with {{platform}}", + "LINKS_DESCRIPTION": "Do you want to keep the link of each item with the original {{platform}} card?", + "WARNING_MAIL_USER": "Note that if the user does not have a Taiga account we will not be able to assign the tasks to him.", + "ASSIGN": "Assign", + "PROJECT_SELECTOR": { + "NO_RESULTS": "It looks like nothing was found with your search criteria", + "ACTION_SEARCH": "hae", + "ACTION_BACK": "Palvelin" + }, "PROJECT_RESTRICTIONS": { - "PROJECT_MEMBERS_DESC": "The project you are trying to import has {{members}} members, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per project. If you would like to increase that limit please contact the administrator.", + "PROJECT_MEMBERS_DESC_PRIVATE": "The project you are trying to import has {{members}} members including you, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per private project. If you would like to increase that limit please contact the administrator.", + "PROJECT_MEMBERS_DESC_PUBLIC": "The project you are trying to import has {{members}} members including you, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per public project. If you would like to increase that limit please contact the administrator.", + "ACCOUNT_ALLOW_MEMBERS": "Your account only allows {{members}} members", "PRIVATE_PROJECTS_SPACE": { "TITLE": "Unfortunately, your current plan does not allow for additional private projects", "DESC": "The project you are trying to import is private. Unfortunately, your current plan does not allow for additional private projects." @@ -961,39 +949,67 @@ "TITLE": "Unfortunately your current plan doesn't allow additional public projects or an increase of more than {{max_memberships}} members per public project", "DESC": "The project that you are trying to import is public and has more than {{members}} members." } - } - }, - "LIKE_BUTTON": { - "LIKE": "Like", - "LIKED": "Liked", - "UNLIKE": "Unlike", - "BUTTON_TITLE": "Like or unlike this project", - "COUNTER_TITLE": "{total, plural, one{one fan} other{# fans}}" - }, - "WATCH_BUTTON": { - "BUTTON_TITLE": "Watch this project and set notification policy", - "WATCH": "Watch", - "WATCHING": "Seuraa", - "COUNTER_TITLE": "{total, plural, one{one watcher} other{# watchers}}", - "OPTIONS": { - "NOTIFY_ALL": "Receive all notifications", - "NOTIFY_ALL_TITLE": "Receive all notifications for this project", - "NOTIFY_INVOLVED": "Only involved", - "NOTIFY_INVOLVED_TITLE": "Recive notificacions only when you are involved", - "UNWATCH": "Unwatch", - "UNWATCH_TITLE": "Unwatch this project" + }, + "IN_PROGRESS": { + "TITLE": "Luetaan sisään projektia", + "DESCRIPTION": "Tämä voi kestää hetken, pidä ikkuna auki." + }, + "WARNING": { + "TITLE": "Some taks will be unassigned", + "DESCRIPTION": "There are still unidentified people. The cards assigned to these people will remain unassigned. Check all the contacts to not lose that information.", + "CHECK": "Check contacts" + }, + "TAIGA": { + "SELECTOR": "Import your Taiga project" + }, + "TRELLO": { + "SELECTOR": "Import your Trello boards into Taiga", + "CHOOSE_PROJECT": "Choose board that you want to import", + "NO_PROJECTS": "It seems you have no boards in Trello" + }, + "GITHUB": { + "SELECTOR": "Import your GitHub project issues", + "CHOOSE_PROJECT": "Find the project you want to import", + "NO_PROJECTS": "It seems you have no porjects in GitHub", + "HOW_DO_YOU_WANT_TO_IMPORT": "How do you want to import your issues into Taiga?", + "KANBAN_PROJECT": "As user stories in a kanban project", + "KANBAN_PROJECT_DESCRIPTION": "After that you can enable scrum with backlog.", + "SCRUM_PROJECT": "As user stories in a scrum project", + "SCRUM_PROJECT_DESCRIPTION": "After that you can enable kanban mode.", + "ISSUES_PROJECT": "As issues", + "ISSUES_PROJECT_DESCRIPTION": "You will not be able to use your issues in kanban or scrum mode. You will be able to enable kanban or scrum for new user stories" + }, + "ASANA": { + "SELECTOR": "Import your Asana project and choose how to manage it", + "CHOOSE_PROJECT": "Choose project that you want to import", + "NO_PROJECTS": "It seems you have no porjects in Asana", + "KANBAN_PROJECT": "Kanban", + "SCRUM_PROJECT": "Scrum", + "CREATE_AS_SCRUM_DESCRIPTION": "The tasks and sub-tasks of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_KANBAN_DESCRIPTION": "The tasks and sub-tasks of your project will be created as Taiga user stories and tasks." + }, + "JIRA": { + "SELECTOR": "Import your Jira project and choose how to manage it", + "CHOOSE_PROJECT": "Choose project or board that you want to import", + "NO_PROJECTS": "It seems you have no porjects or boards in Jira", + "URL": "Your Jira URL", + "KANBAN_PROJECT": "Kanban", + "SCRUM_PROJECT": "Scrum", + "ISSUES_PROJECT": "Pyynnöt", + "CREATE_AS_SCRUM_DESCRIPTION": "The issues and sub-issues of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_KANBAN_DESCRIPTION": "The issues and sub-issues of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_ISSUES_DESCRIPTION": "What do you want to do with sub-issues from the Jira project? (Taiga doesn't allow sub-issues)", + "CREATE_NEW_ISSUES": "Convert sub-issues to new Taiga issues", + "NOT_CREATE_NEW_ISSUES": "Do not import sub-issues" } } }, "LIGHTBOX": { "DELETE_ACCOUNT": { - "SECTION_NAME": "Poista Taiga-tunnus", "CONFIRM": "Haluatko varmasti poistaa Taiga-tunnuksesi?", - "NEWSLETTER_LABEL_TEXT": "En halua uutiskirjettä enää", "CANCEL": "Back to settings", "ACCEPT": "Delete account", - "BLOCK_PROJECT": "Note that all the projects you own projects will be blocked after you delete your account. If you do want a project blocked, transfer ownership to another member of each project prior to deleting your account.", - "SUBTITLE": "Sorry to see you go. We'll be here if you should ever consider us again! :(" + "BLOCK_PROJECT": "Note that all the projects you own projects will be blocked after you delete your account. If you do want a project blocked, transfer ownership to another member of each project prior to deleting your account." }, "DELETE_PROJECT": { "TITLE": "Poista projekti", @@ -1007,6 +1023,12 @@ }, "ADD_MEMBER": { "TITLE": "Uusi jäsen", + "PLACEHOLDER": "Filter users or write an email to invite", + "ADD_EMAIL": "Add email", + "REMOVE": "Remove", + "INVITE": "Invite", + "CHOOSE_ROLE": "Choose a role", + "PLACEHOLDER_INVITATION_TEXT": "(Vapaaehtoinen) Lisää oma kuvaus kutsuusi uusille jäsenille ;-)", "HELP_TEXT": "Taigan käyttäjät lisätään automaattisesti, muille lähetetään kutsu." }, "CREATE_ISSUE": { @@ -1068,6 +1090,12 @@ "TITLE": "Who do you want to be the new project owner?", "ADD_COMMENT": "Add comment", "BUTTON": "Ask this project member to become the new project owner" + }, + "CONTACT_PROJECT": { + "TITLE": "Send an email to", + "WARNING": "The email will be received by the project admins", + "PLACEHOLDER": "Write your message", + "SEND": "Send" } }, "EPIC": { @@ -1101,15 +1129,9 @@ "ADD_BULK": "Lisää monta käyttäjätarinaa", "PROMOTED": "Tämä Kt on liitetty pyyntöön:", "TITLE_LINK_GO_TO_ISSUE": "Siirry pyyntöön", - "EXTERNAL_REFERENCE": "Tämä Kt oon luotu täältä: ", - "GO_TO_EXTERNAL_REFERENCE": "Palaa alkuun", - "BLOCKED": "Tämä käyttäjätarina on suljettu", "TITLE_DELETE_ACTION": "Poista käyttäjätarina", "LIGHTBOX_TITLE_BLOKING_US": "Meitä estää", - "TASK_COMPLETED": "{{totalClosedTasks}}/{{totalTasks}} tehtyä tehtävää", - "ASSIGN": "Käyttäjätarinan tekijä", "NOT_ESTIMATED": "Ei arvioitu", - "TOTAL_US_POINTS": "Kt pisteet yhteensä", "TRIBE": { "PUBLISH": "Publish as Gig in Taiga Tribe", "PUBLISH_INFO": "More info", @@ -1119,23 +1141,19 @@ "CLOSE": "Close", "SYNCHRONIZE_LINK": "synchronize with Taiga Tribe", "PUBLISH_MORE_INFO_TITLE": "Do you need somebody for this task?", - "PUBLISH_MORE_INFO_TEXT": "

If you need help with a particular piece of work you can easily create gigs on Taiga Tribe and receive help from all over the world. You will be able to control and manage the gig enjoying a great community eager to contribute.

TaigaTribe was born as a Taiga sibling. Both platforms can live separately but we believe that there is much power in using them combined so we are making sure the integration works like a charm.

" + "PUBLISH_MORE_INFO_TEXT": "

If you need help with a particular piece of work you can easily create gigs on Taiga Tribe and receive help from all over the world. You will be able to control and manage the gig enjoying a great community eager to contribute.

TaigaTribe was born as a Taiga sibling. Both platforms can live separately but we believe that there is much power in using them combined so we are making sure the integration works like a charm.

" }, "FIELDS": { "TEAM_REQUIREMENT": "Tiimin vaatimus", - "CLIENT_REQUIREMENT": "Asiakkaan vaatimus", - "FINISH_DATE": "Loppupvm" + "CLIENT_REQUIREMENT": "Asiakkaan vaatimus" } }, "COMMENTS": { "DELETED_INFO": "Comment deleted by {{user}}", - "TITLE": "Kommentit", "COMMENTS_COUNT": "{{comments}} Comments", - "ORDER": "Order", "OLDER_FIRST": "Older first", "RECENT_FIRST": "Recent first", "COMMENT": "Kommentti", - "EDIT_COMMENT": "Edit comment", "EDITED_COMMENT": "Edited:", "SHOW_HISTORY": "View historic", "TYPE_NEW_COMMENT": "Lisää uusi kommentti tässä", @@ -1148,13 +1166,8 @@ } }, "ACTIVITY": { - "SHOW_ACTIVITY": "Näytä tapahtumat", - "DATETIME": "DD.MM.YY - HH:mm", - "SHOW_MORE": "+ Näytä edelliset rivit ({{showMore}} lisää)", "TITLE": "Aktiivisuus", "ACTIVITIES_COUNT": "{{activities}} Activities", - "REMOVED": "poistettu", - "ADDED": "lisätty", "TAGS_ADDED": "tags added:", "TAGS_REMOVED": "tags removed:", "US_POINTS": "{{role}} points", @@ -1163,50 +1176,21 @@ "UPDATED_ATTACHMENT": "updated attachment ({{filename}}):", "CREATED_CUSTOM_ATTRIBUTE": "created custom attribute", "UPDATED_CUSTOM_ATTRIBUTE": "updated custom attribute", - "SIZE_CHANGE": "Tehty {size, plural, one{muutos} other{# muutosta}}", "BECAME_DEPRECATED": "became deprecated", "BECAME_UNDEPRECATED": "became undeprecated", "TEAM_REQUIREMENT": "Tiimin vaatimus", "CLIENT_REQUIREMENT": "Asiakkaan vaatimus", "BLOCKED": "Suljettu", "VALUES": { - "YES": "Kyllä", - "NO": "ei", - "EMPTY": "tyhjä", "UNASSIGNED": "ilman tekijää" }, "FIELDS": { "SUBJECT": "aihe", - "NAME": "nimi", "DESCRIPTION": "kuvaus", - "CONTENT": "sisältö", "STATUS": "tila", - "IS_CLOSED": "on suljettu", - "FINISH_DATE": "loppupvm", "TYPE": "tyyppi", - "PRIORITY": "tärkeys", - "SEVERITY": "vakavuus", "ASSIGNED_TO": "tekijä on", - "WATCHERS": "vahdit", "MILESTONE": "kierros", - "USER_STORY": "käyttäjätarina", - "PROJECT": "projekti", - "IS_BLOCKED": "on estetty", - "BLOCKED_NOTE": "estetty muistiinpano", - "POINTS": "pisteet", - "CLIENT_REQUIREMENT": "asiakkaan vaatimus", - "TEAM_REQUIREMENT": "tiimin vaatimus", - "IS_IOCAINE": "myrkyllinen", - "TAGS": "avainsanat", - "ATTACHMENTS": "liitteet", - "IS_DEPRECATED": "on vanhentunut", - "IS_NOT_DEPRECATED": "is not deprecated", - "ORDER": "järjestys", - "BACKLOG_ORDER": "odottavien järjestys", - "SPRINT_ORDER": "kierroksen järjestys", - "KANBAN_ORDER": "kanban järjestys", - "TASKBOARD_ORDER": "Tehtävätaulun järjestys", - "US_ORDER": "kt järjestys", "COLOR": "väri" } }, @@ -1220,8 +1204,6 @@ "CUSTOMIZE_GRAPH_TITLE": "Set up the points and sprints through the Admin", "MOVE_US_TO_CURRENT_SPRINT": "Siirrä nykyiseen kierrokseen", "MOVE_US_TO_LATEST_SPRINT": "Move to latest Sprint", - "SHOW_FILTERS": "Näytä suodattimet", - "SHOW_TAGS": "Näytä avainsanat", "EMPTY": "The backlog is empty!", "CREATE_NEW_US": "Luo uusi Kt", "CREATE_NEW_US_EMPTY_HELP": "Voit haluta lisätä uuden käyttäjätarinan", @@ -1248,6 +1230,12 @@ "SHOW": "Näytä avainsanat", "HIDE": "Piilota avainsanat" }, + "FORECASTING": { + "TITLE": "Velocity forecasting", + "BACKLOG": "Display backlog", + "NEW_SPRINT": "Candidate User Stories for your next sprint based on your velocity. Click to create a new sprint.", + "CURRENT_SPRINT": "Candidate User Stories for your sprint based on your velocity. Click to add to current sprint." + }, "TABLE": { "COLUMN_US": "Käyttäjätarinat", "TITLE_COLUMN_POINTS": "Valitse näkymä roolille" @@ -1270,8 +1258,6 @@ }, "FILTERS": { "TOGGLE": "Vaihda suodattimien näkyvyyttä", - "TITLE": "Suodattimet", - "REMOVE": "Poista suodattimet", "HIDE": "Piilota suodattimet", "SHOW": "Näytä suodattimet" }, @@ -1280,7 +1266,6 @@ "DATE": "DD.MM.YY", "LINK_TASKBOARD": "Kierroksien tehtävätaulu", "TITLE_LINK_TASKBOARD": "Siirry tehtävätauluun {{name}}", - "NUMBER_SPRINTS": "
kierroksia", "EMPTY": "There are no sprints yet", "WARNING_EMPTY_SPRINT_ANONYMOUS": "This sprint has no User Stories", "WARNING_EMPTY_SPRINT": "Drop here Stories from your backlog to start a new sprint", @@ -1305,7 +1290,6 @@ "TITLE_ACTION_ADD": "Lisää uusi tehtävä", "TITLE_ACTION_ADD_BULK": "Lisää monta tehtävää", "TITLE_ACTION_ASSIGN": "Valitse tekijä", - "TITLE_ACTION_EDIT": "Muokkaa tehtävää", "PLACEHOLDER_CARD_TITLE": "This could be a task", "PLACEHOLDER_CARD_TEXT": "Split Stories into tasks to track them separately", "TABLE": { @@ -1335,17 +1319,11 @@ "TITLE_SELECT_STATUS": "Tilan nimi", "OWNER_US": "Tehtävä kuuluu käyttäjälle ", "TITLE_LINK_GO_OWNER": "Siirry käyttäjätarinaan", - "ORIGIN_US": "Tämä tehtävä on luotu", - "TITLE_LINK_GO_ORIGIN": "Siirry käyttäjätarinaan", - "BLOCKED": "Tämä tehtävä on suljettu", "TITLE_DELETE_ACTION": "Poista tehtävä", "LIGHTBOX_TITLE_BLOKING_TASK": "Estävä tehtävä", "FIELDS": { - "MILESTONE": "Kierros", - "USER_STORY": "Käyttäjätarina", "IS_IOCAINE": "Myrkyllinen" }, - "ACTION_IOCAINE": "Myrkky", "TITLE_ACTION_IOCAINE": "Rasittaako tehtävä? Kerro muillekin klikkaamalla myrkyn kuvaketta. Sattaa myös helpottaa jatkossa jos nautit vähitellen." }, "NOTIFICATION": { @@ -1374,14 +1352,12 @@ "ISSUES": { "PAGE_TITLE": "Issues - {{projectName}}", "PAGE_DESCRIPTION": "The issues list panel of the project {{projectName}}: {{projectDescription}}", - "LIST_SECTION_NAME": "Pyynnöt", "SECTION_NAME": "Issue", "ACTION_NEW_ISSUE": "+ UUSI PYYNTÖ", "ACTION_PROMOTE_TO_US": "Liitä käyttäjätarinaan", "PROMOTED": "Tämä pyyntö on liitetty Kthen:", "EXTERNAL_REFERENCE": "Tämä pyyntö on luotu täältä:", "GO_TO_EXTERNAL_REFERENCE": "Palaa alkuun", - "BLOCKED": "Tämä pyyntö on estetty", "ACTION_DELETE": "Poista pyyntö", "LIGHTBOX_TITLE_BLOKING_ISSUE": "Estävä pyyntö", "FIELDS": { @@ -1423,15 +1399,11 @@ "SECTION_NAME": "Kanban", "TITLE_ACTION_FOLD": "Kavenna sarake", "TITLE_ACTION_UNFOLD": "Laajenna sarake", - "TITLE_ACTION_FOLD_CARDS": "Kavenna kortit", - "TITLE_ACTION_UNFOLD_CARDS": "Laajenna kortit", "TITLE_ACTION_ADD_US": "Lisää uusi käyttäjätarina", "TITLE_ACTION_ADD_BULK": "Lisää monta", "ACTION_SHOW_ARCHIVED": "Näytä arkisto", "ACTION_HIDE_ARCHIVED": "Piilota arkisto", "HIDDEN_USER_STORIES": "Käyttäjätarinat tällä alueella ovat oletuksena piilotettuna", - "ARCHIVED": "Olet arkistoitu", - "UNDO_ARCHIVED": "Raahaa ja pudota uudelleen peruaksesi", "PLACEHOLDER_CARD_TITLE": "These are your User Stories", "PLACEHOLDER_CARD_TEXT": "Stories might also have subtasks to separate requirements" }, @@ -1452,7 +1424,6 @@ "PAGE_TITLE": "Team - {{projectName}}", "PAGE_DESCRIPTION": "The team panel to show all the members of the project {{projectName}}: {{projectDescription}}", "SECTION_NAME": "Tiimi", - "APP_TITLE": "TIIMI - {{projectName}}", "PLACEHOLDER_INPUT_SEARCH": "Etsi koko nimellä...", "COLUMN_MR_WOLF": "Mr. Wolf", "EXPLANATION_COLUMN_MR_WOLF": "Suljetut pyynnöt", @@ -1488,18 +1459,9 @@ "OPTION_ALL": "Kaikki", "OPTION_INVOLVED": "Osallisena", "OPTION_NONE": "Ei yhtään" - }, - "POPOVER": { - "USER_PROFILE": "Käyttäjäprofiili", - "CHANGE_PASSWORD": "Muuta salasanaa", - "NOTIFICATIONS": "Ilmoitukset", - "FEEDBACK": "Palaute", - "TITLE_AVATAR": "Käyttäjän asetukset" } }, "USER_PROFILE": { - "IMAGE_HELP": "The image will be scaled to 80x80px.", - "ACTION_CHANGE_IMAGE": "Muuta", "ACTION_USE_GRAVATAR": "Use default image", "ACTION_DELETE_ACCOUNT": "Poista Taiga-tunnus", "CHANGE_EMAIL_SUCCESS": "Tarkista sähköpostisi!
Lähetimme ohjeet
{{email}}
uuden osoitteen asettamiseen", @@ -1517,25 +1479,10 @@ "THEME_DEFAULT": "-- use default theme --" } }, - "WIZARD": { - "SECTION_TITLE_CREATE_PROJECT": "Luo projekti", - "CREATE_PROJECT_TEXT": "Täysin koskematon. Jännittävää!", - "CHOOSE_TEMPLATE": "Which template fits your project best?", - "CHOOSE_TEMPLATE_TITLE": "More info about project templates", - "CHOOSE_TEMPLATE_INFO": "More info", - "PROJECT_DETAILS": "Project Details", - "PUBLIC_PROJECT": "Public Project", - "PRIVATE_PROJECT": "Private Project", - "CREATE_PROJECT": "Luo projekti", - "MAX_PRIVATE_PROJECTS": "You've reached the maximum number of private projects", - "MAX_PUBLIC_PROJECTS": "Unfortunately, you've reached the maximum number of public projects", - "CHANGE_PLANS": "change plans" - }, "WIKI": { "PAGE_TITLE": "{{wikiPageName}} - Wiki - {{projectName}}", "PAGE_DESCRIPTION": "Last edition on {{lastModifiedDate}} ({{totalEditions}} editions in total) Content: {{ wikiPageContent }}", "DATETIME": "DD.MM.YY - HH:mm", - "PLACEHOLDER_PAGE": "Kirjoita wiki-sivu", "REMOVE": "Poista tämä wiki-sivu", "DELETE_LIGHTBOX_TITLE": "Poista wiki-sivu", "DELETE_LINK_TITLE": "Delete Wiki link", @@ -1693,7 +1640,6 @@ "MOST_LIKED": "Most liked", "MOST_LIKED_EMPTY": "There are no LIKED projects yet", "VIEW_MORE": "View more", - "RECRUITING": "This project is looking for people", "FEATURED": "Featured Projects", "EMPTY": "There are no projects to show with this search criteria.
Try again!", "FILTERS": { diff --git a/app/locales/taiga/locale-fr.json b/app/locales/taiga/locale-fr.json index d0828ad6..7323e9c8 100644 --- a/app/locales/taiga/locale-fr.json +++ b/app/locales/taiga/locale-fr.json @@ -4,7 +4,6 @@ "NO": "Non", "OR": "ou", "LOADING": "Veuillez patienter...", - "LOADING_PROJECT": "Chargement du projet...", "DATE": "DD MMM YYYY", "DATETIME": "DD MMM YYYY HH:mm", "SAVE": "Enregistrer", @@ -27,12 +26,9 @@ "BLOCKED_NOTE": "Pourquoi est-ce bloqué ?", "BLOCKED_REASON": "Veuillez s'il vous plait indiquer la raison", "CREATED_BY": "Créé par {{fullDisplayName}}", - "FROM": "de", - "TO": "à", "CLOSE": "clos", "GO_HOME": "Retour à l'accueil", "PLUGINS": "Plugins", - "BETA": "Version beta !", "ONE_ITEM_LINE": "Un élément par ligne...", "NEW_BULK": "Nouvel ajout en bloc", "RELATED_TASKS": "Tâches associées", @@ -41,7 +37,7 @@ "LOGOUT": "Déconnexion", "EXTERNAL_USER": "un utilisateur externe", "GENERIC_ERROR": "L'un de nos Oompa Loompas dit {{error}}.", - "IOCAINE_TEXT": "Vous vous sentez un peu submergé(e) par une tâche ? Soyez certains d'en informer les autres en cliquant sur Iocaine lors de la modification de la tâche. Il est possible de s'immuniser contre ce poison (fictif) en consommant de petites quantités en heures supplémentaires, tout comme il est possible de s'améliorer en acceptant parfois de nouveaux défis !", + "IOCAINE_TEXT": "Ce membre se sent un peu dépassé par cette tâche. Deviendra immunisé contre le poison iocane au fil du temps avec votre aide. Pour l'instant, il peut avoir besoin d'une étreinte.", "CLIENT_REQUIREMENT": "Une exigence client est une nouvelle exigence exprimée par le client, qui n'était pas prévue dans le projet initial, et qu'il est nécessaire d'intégrer", "TEAM_REQUIREMENT": "Une exigence équipe est une exigence exprimée par l'équipe qui doit être rajoutée au projet, sans que cela n'ait d'impact pour le client", "OWNER": "Propriétaire du Projet", @@ -148,7 +144,6 @@ "PRIORITY": "Priorité", "ASSIGNED_TO": "Affecté à", "POINTS": "Points", - "BLOCKED_NOTE": "note bloquée", "IS_BLOCKED": "est bloqué", "REF": "Réf.", "VOTES": "Votes", @@ -187,10 +182,6 @@ "COUNTER_TITLE": "{total, plural, one{un observateur} other{# observateurs}}" }, "VOTE_BUTTON": { - "UPVOTE": "Vote positif", - "UPVOTED": "Voté positivement", - "DOWNVOTE": "Vote négatif", - "VOTERS": "Votants", "BUTTON_TITLE": "Vote positif/négatif pour cet élément", "COUNTER_TITLE": "{total, plural, one{un vote} other{# votes}}" }, @@ -202,10 +193,9 @@ "CONFIRM_DELETE": "Souvenez-vous que toutes les valeurs de ce champ personnalisé vont être effacées.\nEtes-vous sûr de vouloir continuer ?" }, "FILTERS": { - "TITLE": "Filtres", "INPUT_PLACEHOLDER": "Objet ou référence", "TITLE_ACTION_FILTER_BUTTON": "recherche", - "INPUT_SEARCH_PLACEHOLDER": "Objet ou réf.", + "TITLE": "Filtres", "TITLE_ACTION_SEARCH": "Rechercher", "ACTION_SAVE_CUSTOM_FILTER": "sauvegarder en tant que filtre personnalisé", "PLACEHOLDER_FILTER_NAME": "Écrivez le nom du filtre et appuyez sur \"Entrée\"", @@ -220,41 +210,10 @@ "CREATED_BY": "Créé par", "CUSTOM_FILTERS": "Filtres personnalisés", "EPIC": "Épopée" - }, - "CONFIRM_DELETE": { - "TITLE": "Supprime le filtre personnalisé", - "MESSAGE": "le filtre personnalisé '{{customFilterName}}'" } }, "WYSIWYG": { - "H1_BUTTON": "Premier niveau de titre", - "H1_SAMPLE_TEXT": "Votre titre ici…", - "H2_BUTTON": "Deuxième niveau de titre", - "H2_SAMPLE_TEXT": "Votre titre ici…", - "H3_BUTTON": "Troisième niveau de titre", - "H3_SAMPLE_TEXT": "Votre titre ici…", - "BOLD_BUTTON": "Gras", - "BOLD_BUTTON_SAMPLE_TEXT": "Votre texte ici…", - "ITALIC_BUTTON": "Italique", - "ITALIC_SAMPLE_TEXT": "Votre texte ici…", - "STRIKE_BUTTON": "Barré", - "STRIKE_SAMPLE_TEXT": "Votre texte ici…", - "BULLETED_LIST_BUTTON": "Liste à puces", - "BULLETED_LIST_SAMPLE_TEXT": "Votre texte ici…", - "NUMERIC_LIST_BUTTON": "Liste numérotée", - "NUMERIC_LIST_SAMPLE_TEXT": "Votre texte ici…", - "PICTURE_BUTTON": "Image", - "PICTURE_SAMPLE_TEXT": "Votre texte alternatif à l'image ici…", - "LINK_BUTTON": "Lien", - "LINK_SAMPLE_TEXT": "Votre texte de lien ici…", - "QUOTE_BLOCK_BUTTON": "Bloc de citation", - "QUOTE_BLOCK_SAMPLE_TEXT": "Votre texte ici…", - "CODE_BLOCK_BUTTON": "Bloc de code", - "CODE_BLOCK_SAMPLE_TEXT": "Votre texte ici…", - "PREVIEW_BUTTON": "Aperçu", - "EDIT_BUTTON": "Modifier", - "ATTACH_FILE_HELP": "Joindre des fichiers en glissant et déposant ceux-ci sur la zone de texte ci-dessus.", - "ATTACH_FILE_HELP_SAVE_FIRST": "Enregistrez d'abord si vous voulez joindre des fichiers en glissant et déposant ceux-ci sur la zone de texte ci-dessus.", + "OUTDATED": "Une autre personne a apportée des modifications lors de l'édition. Vérifiez la nouvelle version dans l'onglet Activité avant d'enregistrer vos modifications.", "MARKDOWN_HELP": "Aide sur la syntaxe Markdown" }, "PERMISIONS_CATEGORIES": { @@ -307,10 +266,6 @@ "ADD_WIKI_LINKS": "Ajouter des liens wiki", "DELETE_WIKI_LINKS": "Supprimer des liens wiki" } - }, - "META": { - "PAGE_TITLE": "Taiga", - "PAGE_DESCRIPTION": "Taiga est une plateforme de gestion de projets pour les startups, les développeurs et les designers agiles qui veulent un outil simple, beau et qui rend le travail vraiment agréable." } }, "LOGIN": { @@ -366,7 +321,6 @@ }, "CHANGE_PASSWORD": { "PAGE_TITLE": "Modifier votre mot de passe - Taiga", - "PAGE_DESCRIPTION": "Paramètrez un nouveau mot de passe pour votre compte Taiga et, au fait, vous devriez manger de la nourriture plus riche en fer, c'est bon pour votre cerveau :P", "SECTION_NAME": "Modifier le mot de passe", "FIELD_CURRENT_PASSWORD": "Mot de passe actuel", "PLACEHOLDER_CURRENT_PASSWORD": "Votre mot de passe actuel (vide si vous n'avez pas encore de mot de passe)", @@ -391,8 +345,7 @@ }, "INVITATION_LOGIN_FORM": { "NOT_FOUND": "Nos Oompa Loompas n'ont pas trouvé votre invitation.", - "SUCCESS": "Vous avez rejoint ce projet, Bienvenue sur {{project_name}}", - "ERROR": "D'après nos Oompa Loompas, vous n'êtes pas encore enregistrés ou vous avez saisi un mot de passe incorrect." + "SUCCESS": "Vous avez rejoint ce projet, Bienvenue sur {{project_name}}" }, "HOME": { "PAGE_TITLE": "Accueil - Taiga", @@ -463,10 +416,7 @@ "TITLE_LIGHTBOX_DELETE_ATTACHMENT": "Supprimer la pièce jointe...", "MSG_LIGHTBOX_DELETE_ATTACHMENT": "la pièce jointe \"{{fileName}}\"", "ERROR_DELETE_ATTACHMENT": "Nous n'avons pas été capable de supprimer {{errorMessage}}.", - "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) est un peu trop lourd pour nos Oompa Loompas, réessayez avec un fichier d'une taille inférieure à ({{maxFileSize}})", - "FIELDS": { - "IS_DEPRECATED": "est obsolète" - } + "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) est un peu trop lourd pour nos Oompa Loompas, réessayez avec un fichier d'une taille inférieure à ({{maxFileSize}})" }, "PAGINATION": { "PREVIOUS": "Précédent", @@ -502,13 +452,10 @@ "ASYNC_MESSAGE": "Nous vous enverrons un courriel lorsque ce sera prêt.", "SYNC_MESSAGE": "Si le téléchargement ne commence pas automatiquement, cliquez ici.", "ERROR": "Nos Oompa Loompas ont des problèmes à générer le fichier de vidage. S'il vous plait, essayez de nouveau.", - "ERROR_BUSY": "Nous sommes désolés, nos Oompa Loompas sont très occupés en ce moment. Veuillez réessayer dans quelques minutes.", - "ERROR_MESSAGE": "Nos Oompa Loompas ont des problèmes à générer votre fichier de vidage : {{message}}" + "ERROR_BUSY": "Nous sommes désolés, nos Oompa Loompas sont très occupés en ce moment. Veuillez réessayer dans quelques minutes." }, "MODULES": { "TITLE": "Modules", - "ENABLE": "Activer", - "DISABLE": "Désactiver", "EPICS": "Épopées", "EPICS_DESCRIPTION": "Visualiser et gérer les aspects les plus stratégiques de votre projet", "BACKLOG": "Backlog", @@ -537,17 +484,16 @@ "PAGE_TITLE": "{{sectionName}} - Profil projet - {{projectName}}", "PROJECT_DETAILS": "Détails du projet", "PROJECT_NAME": "Nom du projet", - "PROJECT_SLUG": "Label du projet", "TAGS": "Mots-clés", "DESCRIPTION": "Description", "RECRUITING": "Est-ce que ce projet recherche des membres ?", "RECRUITING_MESSAGE": "Qui cherchez-vous ?", "RECRUITING_PLACEHOLDER": "Définissez le profil que vous recherchez", + "FEEDBACK": "Recevoir les commentaires des utilisateurs de Taiga?", "PUBLIC_PROJECT": "Projet public", "PRIVATE_PROJECT": "Projet privé", "PRIVATE_OR_PUBLIC": "Quelle est la différence entre les projets publics et privés ?", "DELETE": "Supprimer ce projet", - "LOGO_HELP": "L'image va être agrandie à 80x80px", "CHANGE_LOGO": "Changer le logo", "ACTION_USE_DEFAULT_LOGO": "Utiliser l'image par défaut", "MAX_PRIVATE_PROJECTS": "Vous avez atteint le nombre maximum autorisé de projets privés accordé par votre souscription actuelle.", @@ -595,6 +541,7 @@ "ISSUE_DESCRIPTION": "Champs personnalisés des tickets", "ISSUE_ADD": "Ajouter un champ personnalisé dans les tickets", "FIELD_TYPE_TEXT": "Texte", + "FIELD_TYPE_RICHTEXT": "Texte riche", "FIELD_TYPE_MULTI": "Multiligne", "FIELD_TYPE_DATE": "Date", "FIELD_TYPE_URL": "Url" @@ -623,7 +570,7 @@ "ACTION_ADD": "Ajouter un niveau de gravité" }, "PROJECT_VALUES_STATUS": { - "TITLE": "Statut", + "TITLE": "Statuses", "SUBTITLE": "Spécifiez les statuts que vont prendre vos récits utilisateur, tâches et tickets", "EPIC_TITLE": "Statuts d'épopée", "US_TITLE": "Statuts de récit utilisateur", @@ -676,8 +623,8 @@ "INFO_VERIFYING_IP": "Les requêtes Gitlab ne sont pas signées, donc le meilleur moyen de vérifier l'origine est par l'adresse IP. Si le champ est vide il n'y aura pas de validation de l'IP." }, "GITHUB": { - "SECTION_NAME": "Github", - "PAGE_TITLE": "Github - {{projectName}}" + "SECTION_NAME": "GitHub", + "PAGE_TITLE": "GitHub - {{projectName}}" }, "GOGS": { "SECTION_NAME": "Gogs", @@ -686,7 +633,6 @@ "WEBHOOKS": { "PAGE_TITLE": "Webhooks - {{projectName}}", "SECTION_NAME": "Webhooks", - "SUBTITLE": "Les Webhooks informent des services extérieurs à Taiga d'événements interne à Taiga, tel que les nouveaux commentaires ou les récits utilisateur…", "ADD_NEW": "Ajouter une nouvelle dérivation", "TYPE_NAME": "Entrez le nom du service", "TYPE_PAYLOAD_URL": "Entrez l'URL de payload du service", @@ -732,7 +678,6 @@ "DELETE_MEMBER": "Supprimer un membre", "RESEND": "Renvoyer", "SUCCESS_SEND_INVITATION": "Nous avons envoyé une autre invitation à '{{email}}'.", - "ERROR_SEND_INVITATION": "Nous n'avons pas envoyé l'invitation", "SUCCESS_DELETE": "Nous avons supprimé {{message}}.", "ERROR_DELETE": "Nous n'avons pas été capable de supprimer {{message}}.", "DEFAULT_DELETE_MESSAGE": "l'invitation à {{email}}" @@ -761,16 +706,11 @@ "PLACEHOLDER_WRITE_NAME": "Donnez un nom au nouvel statut" }, "MENU": { - "TITLE": "Admin", "PROJECT": "Projet", "ATTRIBUTES": "Attributs", "MEMBERS": "Membres", "PERMISSIONS": "Permissions", - "INTEGRATIONS": "Intégrations", - "PLUGINS": "Plugins" - }, - "SUBMENU_PROJECT_ATTRIBUTES": { - "TITLE": "Attributs" + "INTEGRATIONS": "Intégrations" }, "SUBMENU_PROJECT_VALUES": { "STATUS": "Status", @@ -781,17 +721,11 @@ "CUSTOM_FIELDS": "Champs personnalisés", "TAGS": "Mots-clés" }, - "SUBMENU_PROJECT_PROFILE": { - "TITLE": "Profil projet" - }, "SUBMENU_ROLES": { "TITLE": "Rôles", "ACTION_NEW_ROLE": "+ Nouveau rôle", "TITLE_ACTION_NEW_ROLE": "Ajouter un nouveau rôle" }, - "SUBMENU_THIDPARTIES": { - "TITLE": "Services" - }, "PROJECT_TRANSFER": { "DO_YOU_ACCEPT_PROJECT_OWNERNSHIP": "Voudriez-vous devenir le nouveau propriétaire du projet ?", "PRIVATE": "Privé", @@ -806,15 +740,13 @@ "PRIVATE": "Gardez en mémoire que vous pouvez posséder jusqu'à {{maxProjects}} projets privés. Vous possédez actuellement {{currentProjects}} projets privés.", "PUBLIC": "Gardez en mémoire que vous pouvez posséder jusqu'à {{maxProjects}} projets publics. Vous possédez actuellement {{currentProjects}} projets publics." }, - "CANT_BE_OWNED": "Pour le moment, vous ne pouvez devenir propriétaire d'un projet de ce type. Si vous voulez devenir propriétaire de ce projet, merci de contacter l'administrateur afin qu'il puisse modifier les paramètres de votre compte pour autoriser la propriété de projet.", - "CHANGE_MY_PLAN": "Changer ma souscription actuelle" + "CANT_BE_OWNED": "Pour le moment, vous ne pouvez devenir propriétaire d'un projet de ce type. Si vous voulez devenir propriétaire de ce projet, merci de contacter l'administrateur afin qu'il puisse modifier les paramètres de votre compte pour autoriser la propriété de projet." } }, "USER": { "PROFILE": { "PAGE_TITLE": "{{userFullName}} (@{{userUsername}})", "EDIT": "Modifier le profil", - "FOLLOW": "Suivre", "CLOSED_US": "Récit utilisateur fermé", "PROJECTS": "Projets", "PROJECTS_EMPTY": "{{username}} n'a aucun projet pour l'instant", @@ -822,7 +754,6 @@ "CONTACTS_EMPTY": "{{username}} n'a aucun contact pour l'instant", "CURRENT_USER_CONTACTS_EMPTY": "Vous n'avez aucun contact pour l'instant", "CURRENT_USER_CONTACTS_EMPTY_EXPLAIN": "Les personnes avec qui vous travaillez à Taiga seront vos contacts automatiquement", - "REPORT": "Signaler un abus", "TABS": { "ACTIVITY_TAB": "Chronologie", "ACTIVITY_TAB_TITLE": "Voir toutes les activités de cet utilisateur", @@ -848,13 +779,13 @@ "FILTER_TYPE_ALL": "Toutes", "FILTER_TYPE_ALL_TITLE": "Voir tous", "FILTER_TYPE_PROJECTS": "Projets", - "FILTER_TYPE_PROJECT_TITLES": "Voir uniquement les projets", + "FILTER_TYPE_PROJECTS_TITLE": "Voir uniquement les projets", "FILTER_TYPE_EPICS": "Épopées", - "FILTER_TYPE_EPIC_TITLES": "N'afficher que les épopées", + "FILTER_TYPE_EPICS_TITLE": "N'afficher que les épopées", "FILTER_TYPE_USER_STORIES": "Récits", - "FILTER_TYPE_USER_STORIES_TITLES": "Voir uniquement les user stories", + "FILTER_TYPE_USER_STORIES_TITLE": "Voir uniquement les user stories", "FILTER_TYPE_TASKS": "Tâches", - "FILTER_TYPE_TASK_TITLES": "Voir uniquement les tâches", + "FILTER_TYPE_TASKS_TITLE": "Voir uniquement les tâches", "FILTER_TYPE_ISSUES": "Tickets", "FILTER_TYPE_ISSUES_TITLE": "Voir uniquement les tickets", "EMPTY_TITLE": "Il n'y a rien à afficher ici." @@ -862,8 +793,6 @@ }, "PROJECT": { "PAGE_TITLE": "{{projectName}}", - "WELCOME": "Bienvenue", - "SECTION_PROJECTS": "Projets", "HELP": "Réorganisez vos projets pour placer les plus utilisés en premier.
Les 10 premiers projets apparaitront dans la liste des projets de la barre de navigation supérieure", "PRIVATE": "Projet privé", "LOOKING_FOR_PEOPLE": "Est-ce que ce projet recherche des membres ?", @@ -875,12 +804,6 @@ "THIS_PROJECT_IS_BLOCKED": "Ce projet est temporairement verrouillé", "TO_UNBLOCK_CONTACT_THE_ADMIN_STAFF": "Pour débloquer vos projets, merci de contacter l'administrateur." }, - "STATS": { - "PROJECT": "points
projet", - "DEFINED": "points
définis", - "ASSIGNED": "points
affectés", - "CLOSED": "points
fermés" - }, "SECTION": { "SEARCH": "Rechercher", "TIMELINE": "Chronologie", @@ -893,15 +816,9 @@ "ADMIN": "Admin" }, "NAVIGATION": { - "SECTION_TITLE": "Vos projets", - "PLACEHOLDER_SEARCH": "Rechercher dans...", "ACTION_CREATE_PROJECT": "Créer un projet", - "ACTION_IMPORT_PROJECT": "Importer un projet", "MANAGE_PROJECTS": "Gérer les projets", "TITLE_CREATE_PROJECT": "Créer un projet", - "TITLE_IMPORT_PROJECT": "Importer un projet", - "TITLE_PRVIOUS_PROJECT": "Montrer les projets précédents", - "TITLE_NEXT_PROJECT": "Montrer les projets suivants", "HELP_TITLE": "Page d'assistance Taiga", "HELP": "Aide", "HOMEPAGE": "Page d'accueil", @@ -909,10 +826,6 @@ "FEEDBACK": "Feedback", "NOTIFICATIONS_TITLE": "Modifier vos réglages de notification", "NOTIFICATIONS": "Notifications", - "ORGANIZATIONS_TITLE": "Modifier vos organisations", - "ORGANIZATIONS": "Modifier les organisations", - "SETTINGS_TITLE": "Modifier vos réglages", - "SETTINGS": "Réglages", "VIEW_PROFILE_TITLE": "Afficher le profil", "VIEW_PROFILE": "Afficher le profil", "EDIT_PROFILE_TITLE": "Modifier votre profil", @@ -921,14 +834,68 @@ "CHANGE_PASSWORD": "Modifier le mot de passe", "DASHBOARD_TITLE": "Tableau de bord", "DISCOVER_TITLE": "Découvrir les projets populaires", - "NEW_ITEM": "Nouveau", - "DISCOVER": "Découvrir", - "ACTION_REORDER": "Glisser-déposer pour réorganiser" + "DISCOVER": "Découvrir" + }, + "LIKE_BUTTON": { + "LIKE": "J'aime", + "LIKED": "J'aime", + "UNLIKE": "Je n'aime plus", + "BUTTON_TITLE": "Aimer ou ne plus aimer ce projet", + "COUNTER_TITLE": "{total, plural, one{un fan} other{# fans}}" + }, + "WATCH_BUTTON": { + "BUTTON_TITLE": "Suivre ce projet et définir une politique de notification", + "WATCH": "Suivre", + "WATCHING": "Suivi", + "COUNTER_TITLE": "{total, plural, one{un observateur} other{# observateurs}}", + "OPTIONS": { + "NOTIFY_ALL": "Recevoir toutes les notifications", + "NOTIFY_ALL_TITLE": "Recevoir toutes les notifications pour ce projet", + "NOTIFY_INVOLVED": "Uniquement si impliqué", + "NOTIFY_INVOLVED_TITLE": "Recevoir des notifications uniquement si vous êtes impliqué", + "UNWATCH": "Ne plus suivre", + "UNWATCH_TITLE": "Ne plus suivre ce projet" + } + }, + "CONTACT_BUTTON": { + "CONTACT_TITLE": "Contactez l'équipe du projet", + "CONTACT_BUTTON": "Contactez le projet" + }, + "CREATE": { + "TITLE": "Créer un projet", + "CHOOSE_TEMPLATE": "Quel template correspond le mieux à votre projet ?", + "TEMPLATE_SCRUM": "Scrum", + "TEMPLATE_SCRUM_DESC": "Prioritize and solve your tasks in short time cycles.", + "TEMPLATE_SCRUM_LONGDESC": "Scrum is an iterative and incremental agile software development methodology for managing product development.\nThe product backlog is what will ultimately be delivered, ordered into the sequence in which it should be delivered. Product Backlogs are broken into manageable, executable chunks named sprints. Every certain amount of time the team initiates a new sprint and commits to deliver a certain number of user stories from the backlog, in accordance with their skills, abilities and resources. The project advances as the backlog becomes depleted.", + "TEMPLATE_KANBAN": "Kanban", + "TEMPLATE_KANBAN_DESC": "Garder un flux de travail constant sur les tâches indépendantes", + "TEMPLATE_KANBAN_LONGDESC": "The Kanban methodology is used to divide project development (any sort of project) into stages.\nA kanban card is like an index card or post-it note that details every task (or user story) in a project that needs to be completed. The Kanban board is used to move each card from one state of completion to the next and in so doing, helps track progress.", + "DUPLICATE": "Dupliquer le projet", + "DUPLICATE_DESC": "Start clean and keep your configuration", + "IMPORT": "Importer un projet", + "IMPORT_DESC": "Import your project from multiple platforms into Taiga", + "INVITE": "Invite to the project", + "SOLO_PROJECT": "Vous allez être seul sur ce projet", + "INVITE_LATER": "(Vous pourrez inviter d'autres membres plus tard)", + "BACK": "Back", + "MAX_PRIVATE_PROJECTS": "Malheureusement vous avez atteint le nombre maximum de projets privés. Si vous voulez augmenter la limite, contactez votre administrateur.", + "MAX_PUBLIC_PROJECTS": "Unfortunately, You've reached the maximum number of public projects.\nIf you would like to increase the current limit please contact the administrator.", + "PUBLIC_PROJECT": "Projet public", + "PRIVATE_PROJECT": "Projet privé" + }, + "COMMON": { + "DETAILS": "Détails du nouveau projet", + "PROJECT_TITLE": "Nom du projet", + "PROJECT_DESCRIPTION": "Description du projet" + }, + "DUPLICATE": { + "TITLE": "Dupliquer le projet", + "DESCRIPTION": "Start clean and keep your configuration", + "SELECT_PLACEHOLDER": "Choissisez un projet existant à dupliquer" }, "IMPORT": { - "TITLE": "Importation du projet en cours", - "UPLOADING_FILE": "Dépôt du fichier de vidage", - "DESCRIPTION": "Ce processus peut prendre du temps, veuillez garder cette fenêtre ouverte.", + "TITLE": "Import un projet", + "DESCRIPTION": "Import your project from multiple platforms into Taiga", "ASYNC_IN_PROGRESS_TITLE": "Nos Oompa Loompas sont en train d'importer votre projet", "ASYNC_IN_PROGRESS_MESSAGE": "Ce processus pourrait durer plusieurs minutes
Nous vous enverrons un courriel quand ce sera prêt", "UPLOAD_IN_PROGRESS_MESSAGE": "{{uploadedSize}} de {{totalSize}} déposés", @@ -937,8 +904,29 @@ "ERROR_MESSAGE": "Nos Oompa Loompas ont des problèmes pour importer vos données de vidage : {{error_message}}", "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) est un peu trop lourd pour nos Oompa Loompas, réessayez avec un fichier d'une taille inférieure à ({{maxFileSize}})", "SYNC_SUCCESS": "Votre projet a été importé avec succès", + "IMPORT": "Importer", + "WHO_IS": "Ces tâches seront assignées à ...", + "WRITE_EMAIL": "Or if you want, write the email that this user uses in Taiga", + "SEARCH_CONTACT": "Or if you want, search in your contacts", + "WRITE_EMAIL_LABEL": "Write the email that this user uses in Taiga", + "ACCEEDE": "Acceede", + "PROJECT_MEMBERS": "Membres du projet", + "PROCESS_DESCRIPTION": "Tell us who from Taiga you want to assign the tasks of {{platform}}", + "MATCH": "Is {{user_external}} the same person as {{user_internal}}?", + "CHOOSE": "Select user", + "LINKS": "Links with {{platform}}", + "LINKS_DESCRIPTION": "Do you want to keep the link of each item with the original {{platform}} card?", + "WARNING_MAIL_USER": "Note that if the user does not have a Taiga account we will not be able to assign the tasks to him.", + "ASSIGN": "Affecter", + "PROJECT_SELECTOR": { + "NO_RESULTS": "Il semble qu'aucun résultat ne correspond à vos critères de recherche", + "ACTION_SEARCH": "recherche", + "ACTION_BACK": "Back" + }, "PROJECT_RESTRICTIONS": { - "PROJECT_MEMBERS_DESC": "Le projet que vous voulez importer a {{members}} membres. Votre souscription actuelle vous permet un maximum de {{max_memberships}} membres par projet. Si vous désirez augmenter cette limite, merci de contacter un administrateur.", + "PROJECT_MEMBERS_DESC_PRIVATE": "The project you are trying to import has {{members}} members including you, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per private project. If you would like to increase that limit please contact the administrator.", + "PROJECT_MEMBERS_DESC_PUBLIC": "The project you are trying to import has {{members}} members including you, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per public project. If you would like to increase that limit please contact the administrator.", + "ACCOUNT_ALLOW_MEMBERS": "Your account only allows {{members}} members", "PRIVATE_PROJECTS_SPACE": { "TITLE": "Malheureusement, votre souscription actuelle ne vous permet pas d'ajouter un projet privé supplémentaire.", "DESC": "Le projet que vous voulez importer est privé. Votre souscription actuelle ne vous permet pas d'ajouter un projet privé supplémentaire." @@ -961,39 +949,67 @@ "TITLE": "Désolé, votre souscription actuelle ne permet ni d'ajouter des projets publics supplémentaire, ni d'avoir plus de {{max_memberships}} membres par projet public.", "DESC": "Le projet que vous voulez importer est public et a {{members}} membres." } - } - }, - "LIKE_BUTTON": { - "LIKE": "J'aime", - "LIKED": "J'aime", - "UNLIKE": "Je n'aime plus", - "BUTTON_TITLE": "Aimer ou ne plus aimer ce projet", - "COUNTER_TITLE": "{total, plural, one{un fan} other{# fans}}" - }, - "WATCH_BUTTON": { - "BUTTON_TITLE": "Suivre ce projet et définir une politique de notification", - "WATCH": "Suivre", - "WATCHING": "Suivi", - "COUNTER_TITLE": "{total, plural, one{un observateur} other{# observateurs}}", - "OPTIONS": { - "NOTIFY_ALL": "Recevoir toutes les notifications", - "NOTIFY_ALL_TITLE": "Recevoir toutes les notifications pour ce projet", - "NOTIFY_INVOLVED": "Uniquement si impliqué", - "NOTIFY_INVOLVED_TITLE": "Recevoir des notifications uniquement si vous êtes impliqué", - "UNWATCH": "Ne plus suivre", - "UNWATCH_TITLE": "Ne plus suivre ce projet" + }, + "IN_PROGRESS": { + "TITLE": "Importation du projet en cours", + "DESCRIPTION": "Ce processus peut prendre du temps, veuillez garder cette fenêtre ouverte." + }, + "WARNING": { + "TITLE": "Some taks will be unassigned", + "DESCRIPTION": "There are still unidentified people. The cards assigned to these people will remain unassigned. Check all the contacts to not lose that information.", + "CHECK": "Check contacts" + }, + "TAIGA": { + "SELECTOR": "Import your Taiga project" + }, + "TRELLO": { + "SELECTOR": "Import your Trello boards into Taiga", + "CHOOSE_PROJECT": "Choose board that you want to import", + "NO_PROJECTS": "It seems you have no boards in Trello" + }, + "GITHUB": { + "SELECTOR": "Import your GitHub project issues", + "CHOOSE_PROJECT": "Find the project you want to import", + "NO_PROJECTS": "It seems you have no porjects in GitHub", + "HOW_DO_YOU_WANT_TO_IMPORT": "How do you want to import your issues into Taiga?", + "KANBAN_PROJECT": "As user stories in a kanban project", + "KANBAN_PROJECT_DESCRIPTION": "After that you can enable scrum with backlog.", + "SCRUM_PROJECT": "As user stories in a scrum project", + "SCRUM_PROJECT_DESCRIPTION": "After that you can enable kanban mode.", + "ISSUES_PROJECT": "As issues", + "ISSUES_PROJECT_DESCRIPTION": "You will not be able to use your issues in kanban or scrum mode. You will be able to enable kanban or scrum for new user stories" + }, + "ASANA": { + "SELECTOR": "Import your Asana project and choose how to manage it", + "CHOOSE_PROJECT": "Choose project that you want to import", + "NO_PROJECTS": "It seems you have no porjects in Asana", + "KANBAN_PROJECT": "Kanban", + "SCRUM_PROJECT": "Scrum", + "CREATE_AS_SCRUM_DESCRIPTION": "The tasks and sub-tasks of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_KANBAN_DESCRIPTION": "The tasks and sub-tasks of your project will be created as Taiga user stories and tasks." + }, + "JIRA": { + "SELECTOR": "Import your Jira project and choose how to manage it", + "CHOOSE_PROJECT": "Choose project or board that you want to import", + "NO_PROJECTS": "It seems you have no porjects or boards in Jira", + "URL": "Your Jira URL", + "KANBAN_PROJECT": "Kanban", + "SCRUM_PROJECT": "Scrum", + "ISSUES_PROJECT": "Tickets", + "CREATE_AS_SCRUM_DESCRIPTION": "The issues and sub-issues of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_KANBAN_DESCRIPTION": "The issues and sub-issues of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_ISSUES_DESCRIPTION": "What do you want to do with sub-issues from the Jira project? (Taiga doesn't allow sub-issues)", + "CREATE_NEW_ISSUES": "Convert sub-issues to new Taiga issues", + "NOT_CREATE_NEW_ISSUES": "Do not import sub-issues" } } }, "LIGHTBOX": { "DELETE_ACCOUNT": { - "SECTION_NAME": "Supprimer le compte Taiga", "CONFIRM": "Etes-vous sûr de vouloir supprimer votre compte Taiga ?", - "NEWSLETTER_LABEL_TEXT": "Je ne veux plus recevoir votre bulletin d'information", "CANCEL": "Retour aux réglages", "ACCEPT": "Supprimer le compte", - "BLOCK_PROJECT": "Notez que tous les projets dont vous avez la propriété seront bloqués après que vous ayez supprimé votre compte. Si vous souhaitez pas qu'un projet soit bloqué, merci d'en transférer la propriété auprès d'un autre membre avant la suppression de votre compte.", - "SUBTITLE": "Vous partez déjà ? Nous serons toujours là si jamais vous changez d'avis ! :(" + "BLOCK_PROJECT": "Notez que tous les projets dont vous avez la propriété seront bloqués après que vous ayez supprimé votre compte. Si vous souhaitez pas qu'un projet soit bloqué, merci d'en transférer la propriété auprès d'un autre membre avant la suppression de votre compte." }, "DELETE_PROJECT": { "TITLE": "Supprimer le projet", @@ -1007,6 +1023,12 @@ }, "ADD_MEMBER": { "TITLE": "Nouveau membre", + "PLACEHOLDER": "Filtrer les utilisateurs ou écrire un courriel pour inviter un utilisateur", + "ADD_EMAIL": "Ajouter une adresse courriel", + "REMOVE": "Supprimer", + "INVITE": "Inviter", + "CHOOSE_ROLE": "Choissisez un rôle", + "PLACEHOLDER_INVITATION_TEXT": "(Optionnel) Ajoutez un texte personnalisé à l'invitation. Dites quelque chose de gentil à vos nouveaux membres ;-)", "HELP_TEXT": "Si vos utilisateurs sont déjà inscrits sur Taiga, ils seront automatiquement ajoutés. Sinon, ils recevront une invitation." }, "CREATE_ISSUE": { @@ -1068,6 +1090,12 @@ "TITLE": "Qui voulez-vous désigner comme le nouveau propriétaire du projet ?", "ADD_COMMENT": "Ajouter un commentaire", "BUTTON": "Demander à ce membre du projet de devenir le nouveau propriétaire" + }, + "CONTACT_PROJECT": { + "TITLE": "Envoyer un email à", + "WARNING": "L'email sera reçu par les administrateurs du projet", + "PLACEHOLDER": "Ecrire votre message", + "SEND": "Envoyer" } }, "EPIC": { @@ -1101,41 +1129,31 @@ "ADD_BULK": "Ajouter de nouveaux récits utilisateur en lot", "PROMOTED": "Ce récit utilisateur a été promue à partir d'un ticket :", "TITLE_LINK_GO_TO_ISSUE": "Aller vers ce ticket", - "EXTERNAL_REFERENCE": "Ce récit utilisateur a été créé depuis", - "GO_TO_EXTERNAL_REFERENCE": "Allez à l'origine", - "BLOCKED": "Ce récit utilisateur est bloqué", "TITLE_DELETE_ACTION": "Supprimer le récit utilisateur", "LIGHTBOX_TITLE_BLOKING_US": "Bloque le RU", - "TASK_COMPLETED": "{{totalClosedTasks}}/{{totalTasks}} tâches complétées", - "ASSIGN": "Affecter le récit utilisateur", "NOT_ESTIMATED": "Non estimé", - "TOTAL_US_POINTS": "Total des points RU", "TRIBE": { - "PUBLISH": "Publish as Gig in Taiga Tribe", + "PUBLISH": "Publier en tant que Gig sur Taiga Tribe ", "PUBLISH_INFO": "Plus d'informations", - "PUBLISH_TITLE": "More info on publishing in Taiga Tribe", - "PUBLISHED_AS_GIG": "Story published as Gig in Taiga Tribe", + "PUBLISH_TITLE": "Plus d'informations sur la publication dans Taiga Tribe", + "PUBLISHED_AS_GIG": "Histoire publiée comme Gig dans Taiga Tribe", "EDIT_LINK": "Modifier le lien", "CLOSE": "Fermer", - "SYNCHRONIZE_LINK": "synchronize with Taiga Tribe", + "SYNCHRONIZE_LINK": "se synchroniser avec Taiga Tribe", "PUBLISH_MORE_INFO_TITLE": "Avez-vous besoin de quelqu'un pour cette tâche ?", - "PUBLISH_MORE_INFO_TEXT": "

If you need help with a particular piece of work you can easily create gigs on Taiga Tribe and receive help from all over the world. You will be able to control and manage the gig enjoying a great community eager to contribute.

TaigaTribe was born as a Taiga sibling. Both platforms can live separately but we believe that there is much power in using them combined so we are making sure the integration works like a charm.

" + "PUBLISH_MORE_INFO_TEXT": "

If you need help with a particular piece of work you can easily create gigs on Taiga Tribe and receive help from all over the world. You will be able to control and manage the gig enjoying a great community eager to contribute.

TaigaTribe was born as a Taiga sibling. Both platforms can live separately but we believe that there is much power in using them combined so we are making sure the integration works like a charm.

" }, "FIELDS": { "TEAM_REQUIREMENT": "Exigence équipe", - "CLIENT_REQUIREMENT": "Exigence client", - "FINISH_DATE": "Date de fin" + "CLIENT_REQUIREMENT": "Exigence client" } }, "COMMENTS": { "DELETED_INFO": "Commentaire supprimé par {{user}}", - "TITLE": "Commentaires", "COMMENTS_COUNT": "{{comments}} commentaires", - "ORDER": "Trier", "OLDER_FIRST": "Plus ancien d'abord", "RECENT_FIRST": "Plus récent d'abord", "COMMENT": "Commentaire", - "EDIT_COMMENT": "Modifier le commentaire", "EDITED_COMMENT": "Modifié :", "SHOW_HISTORY": "Voir l'historique", "TYPE_NEW_COMMENT": "Entrez un nouveau commentaire ici", @@ -1148,13 +1166,8 @@ } }, "ACTIVITY": { - "SHOW_ACTIVITY": "Afficher l'activité", - "DATETIME": "DD MMM YYYY HH:mm", - "SHOW_MORE": "+ Montrer les entrées précédentes ({{showMore}} plus)", "TITLE": "Activité", "ACTIVITIES_COUNT": "{{activities}} activités", - "REMOVED": "supprimé", - "ADDED": "ajouté", "TAGS_ADDED": "Mots-clés ajoutés :", "TAGS_REMOVED": "Mots-clés supprimés", "US_POINTS": "{{role}} points", @@ -1163,50 +1176,21 @@ "UPDATED_ATTACHMENT": "Pièces jointes mises à jour ({{filename}}) :", "CREATED_CUSTOM_ATTRIBUTE": "Attribut personnalisé créé", "UPDATED_CUSTOM_ATTRIBUTE": "Attribut personnalisé mis à jour", - "SIZE_CHANGE": "A fait {size, plural, one{une modification} other{# modifications}}", "BECAME_DEPRECATED": "devenu obsolète", "BECAME_UNDEPRECATED": "n'est plus obsolète", "TEAM_REQUIREMENT": "Exigence équipe", "CLIENT_REQUIREMENT": "Exigence client", "BLOCKED": "Bloqué", "VALUES": { - "YES": "oui", - "NO": "no", - "EMPTY": "vide", "UNASSIGNED": "non affecté" }, "FIELDS": { "SUBJECT": "objet", - "NAME": "nom", "DESCRIPTION": "description", - "CONTENT": "contenu", "STATUS": "statut", - "IS_CLOSED": "est fermé", - "FINISH_DATE": "date de fin", "TYPE": "type", - "PRIORITY": "priorité", - "SEVERITY": "gravité", "ASSIGNED_TO": "affecté à", - "WATCHERS": "observateurs", "MILESTONE": "sprint", - "USER_STORY": "récit utilisateur", - "PROJECT": "projet", - "IS_BLOCKED": "est bloqué", - "BLOCKED_NOTE": "note bloquée", - "POINTS": "points", - "CLIENT_REQUIREMENT": "exigence client", - "TEAM_REQUIREMENT": "exigence équipe", - "IS_IOCAINE": "est sous iocaine", - "TAGS": "mots-clés", - "ATTACHMENTS": "pièces jointes", - "IS_DEPRECATED": "est obsolète", - "IS_NOT_DEPRECATED": "n'est pas obsolète", - "ORDER": "classement", - "BACKLOG_ORDER": "classement du backlog", - "SPRINT_ORDER": "classement du sprint", - "KANBAN_ORDER": "Classement du Kanban", - "TASKBOARD_ORDER": "trier le tableau des tâches", - "US_ORDER": "classement des récits utilisateur", "COLOR": "couleur" } }, @@ -1220,8 +1204,6 @@ "CUSTOMIZE_GRAPH_TITLE": "Définissez les points et les sprints via l'admin", "MOVE_US_TO_CURRENT_SPRINT": "Déplacer vers le sprint actuel", "MOVE_US_TO_LATEST_SPRINT": "Déplacer vers le dernier sprint", - "SHOW_FILTERS": "Afficher les filtres", - "SHOW_TAGS": "Afficher les mots-clés", "EMPTY": "Le backlog est vide !", "CREATE_NEW_US": "Créer un nouveau récit utilisateur", "CREATE_NEW_US_EMPTY_HELP": "Vous pouvez envisager de créer un récit utilisateur", @@ -1248,6 +1230,12 @@ "SHOW": "Montrer les mots-clés", "HIDE": "Cacher les mots-clés" }, + "FORECASTING": { + "TITLE": "Prévision de la vitesse", + "BACKLOG": "Afficher le carnet de commandes", + "NEW_SPRINT": "Histoires d'utilisateurs pour votre prochain sprint en fonction de votre vitesse. Cliquez ici pour créer un nouveau sprint.", + "CURRENT_SPRINT": "Histoires d'utilisateur candidat pour votre sprint basé sur votre vitesse. Cliquez ici pour ajouter au sprint actuel." + }, "TABLE": { "COLUMN_US": "Récits utilisateur", "TITLE_COLUMN_POINTS": "Sélectionnez la vue par rôle" @@ -1270,8 +1258,6 @@ }, "FILTERS": { "TOGGLE": "Afficher/Cacher les filtres", - "TITLE": "Filtres", - "REMOVE": "Supprimer les filtres", "HIDE": "Cacher les filtres", "SHOW": "Afficher les filtres" }, @@ -1280,7 +1266,6 @@ "DATE": "DD MMM YYYY", "LINK_TASKBOARD": "Tableau des tâches", "TITLE_LINK_TASKBOARD": "Aller au tableau des tâches de \"{{name}}\"", - "NUMBER_SPRINTS": "
sprints", "EMPTY": "Il n'y a pas encore de sprint", "WARNING_EMPTY_SPRINT_ANONYMOUS": "Ce sprint n'a pas de \"User Stories\"", "WARNING_EMPTY_SPRINT": "Déposez ici les récits depuis votre backlog pour démarrer un nouveau sprint", @@ -1305,7 +1290,6 @@ "TITLE_ACTION_ADD": "Ajouter une nouvelle tâche", "TITLE_ACTION_ADD_BULK": "Ajouter un nouveau lot de tâches", "TITLE_ACTION_ASSIGN": "Affecter une tâche", - "TITLE_ACTION_EDIT": "Modifier la tâche", "PLACEHOLDER_CARD_TITLE": "Cela pourrait être une tâche", "PLACEHOLDER_CARD_TEXT": "Éclater les récits en tâches pour les suivre séparément", "TABLE": { @@ -1335,17 +1319,11 @@ "TITLE_SELECT_STATUS": "Nom du statut", "OWNER_US": "La tâche appartient à", "TITLE_LINK_GO_OWNER": "Aller au récit utilisateur", - "ORIGIN_US": "Cette tâche a été créée par", - "TITLE_LINK_GO_ORIGIN": "Aller au récit utilisateur", - "BLOCKED": "Cette tâche est bloquée", "TITLE_DELETE_ACTION": "Supprimer une tâche", "LIGHTBOX_TITLE_BLOKING_TASK": "Tâche bloquante", "FIELDS": { - "MILESTONE": "Sprint", - "USER_STORY": "Récit utilisateur", "IS_IOCAINE": "est sous iocaine" }, - "ACTION_IOCAINE": "locaine", "TITLE_ACTION_IOCAINE": "Vous vous sentez un peu dépassé(e) par une tâche ? Assurez-vous que les autres le savent en cliquant sur locaine en éditant une tâche. Il est possible de s'immuniser contre ce poison (fictif) en en consommant de faibles doses pendant un moment tout comme il est possible de devenir meilleur à ce que vous faîtes en relevant quelques défis à l'occasion !" }, "NOTIFICATION": { @@ -1374,14 +1352,12 @@ "ISSUES": { "PAGE_TITLE": "Tickets - {{projectName}}", "PAGE_DESCRIPTION": "Le panneau de la liste des tickets du projet {{projectName}} : {{projectDescription}}", - "LIST_SECTION_NAME": "Tickets", "SECTION_NAME": "Ticket", "ACTION_NEW_ISSUE": "+ NOUVEAU TICKET", "ACTION_PROMOTE_TO_US": "Promouvoir en récit utilisateur", "PROMOTED": "Le ticket a été promu en récit utilisateur", "EXTERNAL_REFERENCE": "Ce ticket a été créé à partir de", "GO_TO_EXTERNAL_REFERENCE": "Aller à l'origine", - "BLOCKED": "Ce bug est bloqué", "ACTION_DELETE": "Supprimer le ticket", "LIGHTBOX_TITLE_BLOKING_ISSUE": "Ticket bloquant", "FIELDS": { @@ -1423,15 +1399,11 @@ "SECTION_NAME": "Kanban", "TITLE_ACTION_FOLD": "Replier la colonne", "TITLE_ACTION_UNFOLD": "Déplier la colonne", - "TITLE_ACTION_FOLD_CARDS": "Replier les cartes", - "TITLE_ACTION_UNFOLD_CARDS": "Déplier les cartes", "TITLE_ACTION_ADD_US": "Ajouter un nouveau récit utilisateur", "TITLE_ACTION_ADD_BULK": "Ajout en masse", "ACTION_SHOW_ARCHIVED": "Montrer les éléments archivés", "ACTION_HIDE_ARCHIVED": "Cacher les éléments archivés", "HIDDEN_USER_STORIES": "Les récits utilisateur avec ce statut sont masqués par défaut", - "ARCHIVED": "Vous avez archivé", - "UNDO_ARCHIVED": "Refaites glisser pour annuler", "PLACEHOLDER_CARD_TITLE": "Ce sont vos récits utilisateurs", "PLACEHOLDER_CARD_TEXT": "Les récits peuvent avoir des sous-tâches pour séparer les exigences" }, @@ -1452,7 +1424,6 @@ "PAGE_TITLE": "ÉQUIPE - {{projectName}}", "PAGE_DESCRIPTION": "Le panneau équipe montre la liste des membres du projet {{projectName}} : {{projectDescription}}", "SECTION_NAME": "Équipe", - "APP_TITLE": "ÉQUIPE - {{projectName}}", "PLACEHOLDER_INPUT_SEARCH": "Rechercher par nom...", "COLUMN_MR_WOLF": "M. Wolf", "EXPLANATION_COLUMN_MR_WOLF": "Tickets fermés", @@ -1488,18 +1459,9 @@ "OPTION_ALL": "Toutes", "OPTION_INVOLVED": "Impliqué", "OPTION_NONE": "Aucune" - }, - "POPOVER": { - "USER_PROFILE": "Profil utilisateur", - "CHANGE_PASSWORD": "Changer de mot de passe", - "NOTIFICATIONS": "Notifications", - "FEEDBACK": "Feedback", - "TITLE_AVATAR": "Préférences utilisateur" } }, "USER_PROFILE": { - "IMAGE_HELP": "L'image va être agrandie à 80x80px", - "ACTION_CHANGE_IMAGE": "Modifier", "ACTION_USE_GRAVATAR": "Utiliser l'image par défaut", "ACTION_DELETE_ACCOUNT": "Supprime le compte Taiga", "CHANGE_EMAIL_SUCCESS": "Consultez votre messagerie !
Nous vous avons envoyé un courriel
avec les instructions à suivre pour saisir votre nouvelle adresse", @@ -1517,25 +1479,10 @@ "THEME_DEFAULT": "-- utiliser le thème par défaut --" } }, - "WIZARD": { - "SECTION_TITLE_CREATE_PROJECT": "Créer un projet", - "CREATE_PROJECT_TEXT": "Tout beau, tout nouveau !", - "CHOOSE_TEMPLATE": "Quel modèle convient mieux à votre projet ?", - "CHOOSE_TEMPLATE_TITLE": "Plus d'information sur les templates de projets", - "CHOOSE_TEMPLATE_INFO": "Plus d'informations", - "PROJECT_DETAILS": "Détails du projet", - "PUBLIC_PROJECT": "Projet public", - "PRIVATE_PROJECT": "Projet privé", - "CREATE_PROJECT": "Créer un projet", - "MAX_PRIVATE_PROJECTS": "Vous avez atteint le nombre maximum de projets privés", - "MAX_PUBLIC_PROJECTS": "Désolé, vous avez atteint le nombre maximal de projet public.", - "CHANGE_PLANS": "changer de souscription" - }, "WIKI": { "PAGE_TITLE": "{{wikiPageName}} - Wiki - {{projectName}}", "PAGE_DESCRIPTION": "Dernière modification le {{lastModifiedDate}} ({{totalEditions}} modifications en tout) Contenu : {{ wikiPageContent }}", "DATETIME": "DD MMM YYYY HH:mm", - "PLACEHOLDER_PAGE": "Ecrivez votre page wiki", "REMOVE": "Supprimer cette page wiki", "DELETE_LIGHTBOX_TITLE": "Supprimer la page Wiki", "DELETE_LINK_TITLE": "Supprimer un lien Wiki", @@ -1693,7 +1640,6 @@ "MOST_LIKED": "Les plus « aimés »", "MOST_LIKED_EMPTY": "Il n'y a pas encore de projet « aimé »", "VIEW_MORE": "Voir plus", - "RECRUITING": "Ce projet recherche des membres", "FEATURED": "Projets mis en avant", "EMPTY": "Aucun projet ne correspond à ce critère de recherche.
Essayez encore !", "FILTERS": { diff --git a/app/locales/taiga/locale-it.json b/app/locales/taiga/locale-it.json index 1cb4430c..4d76c6c4 100644 --- a/app/locales/taiga/locale-it.json +++ b/app/locales/taiga/locale-it.json @@ -4,7 +4,6 @@ "NO": "No", "OR": "o", "LOADING": "Caricamento...", - "LOADING_PROJECT": "Stiamo caricando il progetto...", "DATE": "DD MMM YYYY", "DATETIME": "DD MMM YYYY HH:mm", "SAVE": "Salva", @@ -27,12 +26,9 @@ "BLOCKED_NOTE": "Perché questo compito è bloccato?", "BLOCKED_REASON": "Spiega il motivo", "CREATED_BY": "Creato da {{fullDisplayName}}", - "FROM": "da", - "TO": "a", "CLOSE": "chiudi", "GO_HOME": "Ritorna all'inizio", "PLUGINS": "Plugin", - "BETA": "Siamo in beta!", "ONE_ITEM_LINE": "Un elemento per riga...", "NEW_BULK": "Nuovo inserimento nel carico", "RELATED_TASKS": "Compiti correlati", @@ -41,7 +37,7 @@ "LOGOUT": "Esci", "EXTERNAL_USER": "un utente esterno", "GENERIC_ERROR": "C'é uno dei nostri Oompa Loompa che dice {{error}}.", - "IOCAINE_TEXT": "Sei stremato? Assicurati che gli altri lo sappiano cliccando su 'aspirina' quando stai lavorando su un compito che ti affatica. Ma non demordere, ricordati: si può migliorare solo se di tanto in tanto si accettano sfide extra!", + "IOCAINE_TEXT": "Questo membro si sente un po' sopraffatto da questo compito. In futuro diventerà immune a tutto questo, ma per ora, potrebbe sentire il bisogno di un abbraccio.", "CLIENT_REQUIREMENT": "Requisito del Cliente è un nuovo requisito che non era stato previsto ed ora è stato richiesto come requisito del progetto", "TEAM_REQUIREMENT": "Requisito del Team è un requisito che deve esistere nel progetto ma non deve avere costi per il cliente", "OWNER": "Proprietario Progetto", @@ -148,7 +144,6 @@ "PRIORITY": "Priorità", "ASSIGNED_TO": "Assegnato a", "POINTS": "Punti", - "BLOCKED_NOTE": "nota bloccata", "IS_BLOCKED": "è bloccato", "REF": "Riferimento", "VOTES": "Voti", @@ -187,10 +182,6 @@ "COUNTER_TITLE": "{total, plural, one{un osservatore} other{# osservatori}}" }, "VOTE_BUTTON": { - "UPVOTE": "vota positivamente", - "UPVOTED": "votato positivamente", - "DOWNVOTE": "vota negativamente", - "VOTERS": "Votanti", "BUTTON_TITLE": "vota positivamente o negativamente questo elemento", "COUNTER_TITLE": "{total, plural, one{un voto} other{# voti}}" }, @@ -202,10 +193,9 @@ "CONFIRM_DELETE": "Ricorda che tutti i valori in questo campo custom andranno persi.\nSei sicuro di voler continuare?" }, "FILTERS": { - "TITLE": "Filtri", "INPUT_PLACEHOLDER": "Soggetto o referenza", "TITLE_ACTION_FILTER_BUTTON": "cerca", - "INPUT_SEARCH_PLACEHOLDER": "Soggetto o referenza", + "TITLE": "Filtri", "TITLE_ACTION_SEARCH": "Cerca", "ACTION_SAVE_CUSTOM_FILTER": "salva come filtro personalizzato", "PLACEHOLDER_FILTER_NAME": "Scrivi il nome del filtro e premi invio", @@ -220,41 +210,10 @@ "CREATED_BY": "Creato da", "CUSTOM_FILTERS": "Filtri personalizzati", "EPIC": "Epic" - }, - "CONFIRM_DELETE": { - "TITLE": "Elimina il filtro personalizzato", - "MESSAGE": "Il filtro personalizzato '{{customFilterName}}'" } }, "WYSIWYG": { - "H1_BUTTON": "Intestazione di primo livello", - "H1_SAMPLE_TEXT": "Il titolo qui...", - "H2_BUTTON": "Intestazione di secondo livello", - "H2_SAMPLE_TEXT": "Il titolo qui...", - "H3_BUTTON": "Intestazione die terzo livello", - "H3_SAMPLE_TEXT": "Il titolo qui...", - "BOLD_BUTTON": "Grassetto", - "BOLD_BUTTON_SAMPLE_TEXT": "Inserire qui il testo...", - "ITALIC_BUTTON": "Italico", - "ITALIC_SAMPLE_TEXT": "Inserire qui il testo...", - "STRIKE_BUTTON": "Centro", - "STRIKE_SAMPLE_TEXT": "Inserire qui il testo...", - "BULLETED_LIST_BUTTON": "Elenco puntato", - "BULLETED_LIST_SAMPLE_TEXT": "Inserire qui il testo...", - "NUMERIC_LIST_BUTTON": "Elenco numerato", - "NUMERIC_LIST_SAMPLE_TEXT": "Inserire qui il testo...", - "PICTURE_BUTTON": "Foto", - "PICTURE_SAMPLE_TEXT": "Il testo per la tua foto qui...", - "LINK_BUTTON": "Link", - "LINK_SAMPLE_TEXT": "Qui il testo da linkare...", - "QUOTE_BLOCK_BUTTON": "Citazione", - "QUOTE_BLOCK_SAMPLE_TEXT": "Inserire qui il testo...", - "CODE_BLOCK_BUTTON": "Blocco di codice", - "CODE_BLOCK_SAMPLE_TEXT": "Inserire qui il testo...", - "PREVIEW_BUTTON": "Anteprima", - "EDIT_BUTTON": "Modifica", - "ATTACH_FILE_HELP": "Allega file trascinandoli nell'area qui sopra", - "ATTACH_FILE_HELP_SAVE_FIRST": "Se vuoi allegare file trascinandoli nell'area qui sopra, prima salva", + "OUTDATED": "Another person has made changes while you were editing. Check the new version on the activiy tab before you save your changes.", "MARKDOWN_HELP": "Aiuto per la sintassi Markdown" }, "PERMISIONS_CATEGORIES": { @@ -307,10 +266,6 @@ "ADD_WIKI_LINKS": "Aggiungi un wiki links", "DELETE_WIKI_LINKS": "Elimina il link wiki" } - }, - "META": { - "PAGE_TITLE": "Taiga", - "PAGE_DESCRIPTION": "Taiga è una piattaforma di gestione dei progetti per startups e sviluppatori agile, o per designers che vogliono uno strumento semplice ed elegante che renda piacevole lavorare. " } }, "LOGIN": { @@ -366,7 +321,6 @@ }, "CHANGE_PASSWORD": { "PAGE_TITLE": "Cambia la tua password - Taiga", - "PAGE_DESCRIPTION": "Imposta una nuova password per il tuo account Taiga... hey! ti consigliamo di mangiare cibo ricco di ferro, fa bene all'innovazione :P", "SECTION_NAME": "Cambia password", "FIELD_CURRENT_PASSWORD": "Password attuale", "PLACEHOLDER_CURRENT_PASSWORD": "La tua password corrente (o lascia vuoto se non hai ancora una password)", @@ -391,8 +345,7 @@ }, "INVITATION_LOGIN_FORM": { "NOT_FOUND": "I nostri Oompa Loompa non hanno trovato il tuo invito.", - "SUCCESS": "Sei ora un membro di questo progetto. Benvenuto in {{project_name}}", - "ERROR": "Secondo i nostri Oompa Loompa, non sei ancora registrato o hai inserito una password non valida." + "SUCCESS": "Sei ora un membro di questo progetto. Benvenuto in {{project_name}}" }, "HOME": { "PAGE_TITLE": "Home - Taiga", @@ -463,10 +416,7 @@ "TITLE_LIGHTBOX_DELETE_ATTACHMENT": "Cancella l'allegato", "MSG_LIGHTBOX_DELETE_ATTACHMENT": "l'allegato '{{fileName}}'", "ERROR_DELETE_ATTACHMENT": "Non siamo riusciti a cancellare: {{errorMessage}}", - "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) è troppo pesante per i nostri Oompa Loompa; falli contenti, prova con una dimensione minore di ({{maxFileSize}})", - "FIELDS": { - "IS_DEPRECATED": "è deprecato" - } + "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) è troppo pesante per i nostri Oompa Loompa; falli contenti, prova con una dimensione minore di ({{maxFileSize}})" }, "PAGINATION": { "PREVIOUS": "Precedente", @@ -502,13 +452,10 @@ "ASYNC_MESSAGE": "Ti invieremo una mail quando sarà pronto", "SYNC_MESSAGE": "Se il download non parte automaticamente clicca here.", "ERROR": "I nostri Oompa Loompa hanno qualche problema a generare il tuo dump. Prova di nuova.", - "ERROR_BUSY": "Scusali, i nostri Oompa Loompa sono occupati. Riprova di nuovo in qualche minuto.", - "ERROR_MESSAGE": "Accidenti, i nostri Oompa Loompa hanno qualche problema a generare il tuo dump: {{message}}" + "ERROR_BUSY": "Scusali, i nostri Oompa Loompa sono occupati. Riprova di nuovo in qualche minuto." }, "MODULES": { "TITLE": "Moduli", - "ENABLE": "Abilita", - "DISABLE": "Disabilita", "EPICS": "Epici", "EPICS_DESCRIPTION": "Visulaizza e controlla la parte più strategica del tuo progetto", "BACKLOG": "Backlog", @@ -537,17 +484,16 @@ "PAGE_TITLE": "{{sectionName}} - Profilo progetto - {{projectName}}", "PROJECT_DETAILS": "Dettagli progetto", "PROJECT_NAME": "Nome progetto", - "PROJECT_SLUG": "Progetto lumaca", "TAGS": "Tag", "DESCRIPTION": "Descrizione", "RECRUITING": "Il progetto cerca persone?", "RECRUITING_MESSAGE": "Chi stai cercando?", "RECRUITING_PLACEHOLDER": "Definisci il profilo che stai cercando", + "FEEDBACK": "RIcevere opinioni da utenti Taiga?", "PUBLIC_PROJECT": "Progetto pubblico", "PRIVATE_PROJECT": "Progetto privato", "PRIVATE_OR_PUBLIC": "Quale è la differenza tra progetto privato e pubblico?", "DELETE": "Elimina questo progetto", - "LOGO_HELP": "L'immagine sarà scalata a 80x80px.", "CHANGE_LOGO": "Cambia Logo", "ACTION_USE_DEFAULT_LOGO": "Usa l'immagine di default", "MAX_PRIVATE_PROJECTS": "Hai raggiunto il numero massimo di progetti privati per il tuo abbonamento", @@ -595,6 +541,7 @@ "ISSUE_DESCRIPTION": "Campi personalizzati", "ISSUE_ADD": "Aggiungi un campo personalizzato alla criticitá", "FIELD_TYPE_TEXT": "Testo", + "FIELD_TYPE_RICHTEXT": "Testo con formattazione", "FIELD_TYPE_MULTI": "Multilinea", "FIELD_TYPE_DATE": "Data", "FIELD_TYPE_URL": "Url" @@ -623,7 +570,7 @@ "ACTION_ADD": "Aggiungi una nuova criticità." }, "PROJECT_VALUES_STATUS": { - "TITLE": "Stato", + "TITLE": "Statuses", "SUBTITLE": "Specifica lo stato delle storie utente, i compiti e i problemi saranno affrontati", "EPIC_TITLE": "Stati dell'epic", "US_TITLE": "Stati della storia utente", @@ -676,8 +623,8 @@ "INFO_VERIFYING_IP": "Le richieste Gitlab non sono firmate, quindi il miglior modo di verificarle è attraverso l'origine degli IP. Se il campo è vuoto non ci sarà validazione." }, "GITHUB": { - "SECTION_NAME": "Github", - "PAGE_TITLE": "Github - {{projectName}}" + "SECTION_NAME": "GitHub", + "PAGE_TITLE": "GitHub - {{projectName}}" }, "GOGS": { "SECTION_NAME": "Gogs", @@ -686,7 +633,6 @@ "WEBHOOKS": { "PAGE_TITLE": "Webhooks - {{projectName}}", "SECTION_NAME": "Webhooks", - "SUBTITLE": "Webhooks notifica servizi esterni su eventi in Taiga, come i commenti, le storie utente....", "ADD_NEW": "Aggiungi un nuovo Webhook", "TYPE_NAME": "Digita il nome del servizio", "TYPE_PAYLOAD_URL": "Digita l'URL del servizio in carico", @@ -732,7 +678,6 @@ "DELETE_MEMBER": "Elimina membro", "RESEND": "Invia di nuovo", "SUCCESS_SEND_INVITATION": "Abbiamo mandato nuovamente l'invito a '{{email}}'.", - "ERROR_SEND_INVITATION": "Non abbiamo mandato l'invito", "SUCCESS_DELETE": "Abbiamo eliminato {{message}}.", "ERROR_DELETE": "Non siamo riusciti ad eliminare {{message}}.", "DEFAULT_DELETE_MESSAGE": "L'invito a {{email}}" @@ -761,16 +706,11 @@ "PLACEHOLDER_WRITE_NAME": "Scrivi un nome per il nuovo status" }, "MENU": { - "TITLE": "Amministratore", "PROJECT": "Progetto", "ATTRIBUTES": "Attributi", "MEMBERS": "Membri", "PERMISSIONS": "Permessi", - "INTEGRATIONS": "Integrazioni", - "PLUGINS": "Plugin" - }, - "SUBMENU_PROJECT_ATTRIBUTES": { - "TITLE": "Attributi" + "INTEGRATIONS": "Integrazioni" }, "SUBMENU_PROJECT_VALUES": { "STATUS": "Stato", @@ -781,17 +721,11 @@ "CUSTOM_FIELDS": "Campi personalizzati", "TAGS": "Tag" }, - "SUBMENU_PROJECT_PROFILE": { - "TITLE": "Profilo progetto" - }, "SUBMENU_ROLES": { "TITLE": "Ruoli", "ACTION_NEW_ROLE": "+ Nuovo ruolo", "TITLE_ACTION_NEW_ROLE": "Aggiungi nuovo ruolo" }, - "SUBMENU_THIDPARTIES": { - "TITLE": "Servizi" - }, "PROJECT_TRANSFER": { "DO_YOU_ACCEPT_PROJECT_OWNERNSHIP": "Vorresti diventare il nuovo proprietario del progetto?", "PRIVATE": "Privato", @@ -806,15 +740,13 @@ "PRIVATE": "Per favore ricorda che puoi avere al massimo {{maxProjects}} progetti privati. Attualmente hai {{currentProjects}} progetti privati", "PUBLIC": "Per favore ricorda che puoi avere al massimo {{maxProjects}} progetti pubblici. Attualmente hai {{currentProjects}} progetti pubblici" }, - "CANT_BE_OWNED": "Attualmente non puoi diventare il proprietario di un progetto di questo tipo. Se vuoi diventare proprietario di questo progetto, per favore contatta l'amministratore così può cambiare le impostazioni del tuo account per permettere la proprietà dei progetti.", - "CHANGE_MY_PLAN": "Cambia il mio abbonamento" + "CANT_BE_OWNED": "Attualmente non puoi diventare il proprietario di un progetto di questo tipo. Se vuoi diventare proprietario di questo progetto, per favore contatta l'amministratore così può cambiare le impostazioni del tuo account per permettere la proprietà dei progetti." } }, "USER": { "PROFILE": { "PAGE_TITLE": "{{userFullName}} (@{{userUsername}})", "EDIT": "Modifica profilo", - "FOLLOW": "Segui", "CLOSED_US": "US chiusa", "PROJECTS": "Progetti", "PROJECTS_EMPTY": "{{username}} non ha ancora nessun progetto", @@ -822,7 +754,6 @@ "CONTACTS_EMPTY": "{{username}} non ha ancora nessun contatto", "CURRENT_USER_CONTACTS_EMPTY": "Non hai ancora contatti", "CURRENT_USER_CONTACTS_EMPTY_EXPLAIN": "Le persone con cui lavori in Taiga saranno automaticamente tra tuoi contatti", - "REPORT": "Segnala abuso", "TABS": { "ACTIVITY_TAB": "Cronologia", "ACTIVITY_TAB_TITLE": "Mostra tutte le attività dell'utente", @@ -848,13 +779,13 @@ "FILTER_TYPE_ALL": "Tutti", "FILTER_TYPE_ALL_TITLE": "Mostra tutto", "FILTER_TYPE_PROJECTS": "Progetti", - "FILTER_TYPE_PROJECT_TITLES": "Mostra solo i progetti", + "FILTER_TYPE_PROJECTS_TITLE": "Mostra solo i progetti", "FILTER_TYPE_EPICS": "Epici", - "FILTER_TYPE_EPIC_TITLES": "Mostra solo gli epici", + "FILTER_TYPE_EPICS_TITLE": "Mostra solo gli epici", "FILTER_TYPE_USER_STORIES": "Resoconti", - "FILTER_TYPE_USER_STORIES_TITLES": "Mostra solo resoconti utente", + "FILTER_TYPE_USER_STORIES_TITLE": "Mostra solo resoconti utente", "FILTER_TYPE_TASKS": "Compiti", - "FILTER_TYPE_TASK_TITLES": "Mostra solo attività", + "FILTER_TYPE_TASKS_TITLE": "Mostra solo attività", "FILTER_TYPE_ISSUES": "problemi", "FILTER_TYPE_ISSUES_TITLE": "Mostra solo i problemi", "EMPTY_TITLE": "Sembra che qui non ci sia nulla" @@ -862,8 +793,6 @@ }, "PROJECT": { "PAGE_TITLE": "TEAM - {{projectName}}", - "WELCOME": "Benvenuto", - "SECTION_PROJECTS": "Progetti", "HELP": "Riordina i tuoi progetti per avere in alto i più usati.
I primi 10 progetti compariranno nella lista dei progetti della barra di navigazione, su in alto", "PRIVATE": "Progetto privato", "LOOKING_FOR_PEOPLE": "Il progetto cerca persone", @@ -875,12 +804,6 @@ "THIS_PROJECT_IS_BLOCKED": "Questo progetto è temporaneamente bloccato", "TO_UNBLOCK_CONTACT_THE_ADMIN_STAFF": "Per sbloccare i tuoi progetti, contatta l'amministratore" }, - "STATS": { - "PROJECT": "progetto
punti", - "DEFINED": "Definiti
punti", - "ASSIGNED": "assegnati
punti", - "CLOSED": "chiusi
punti" - }, "SECTION": { "SEARCH": "Cerca", "TIMELINE": "Cronologia", @@ -893,15 +816,9 @@ "ADMIN": "Amministratore" }, "NAVIGATION": { - "SECTION_TITLE": "Tuoi progetti", - "PLACEHOLDER_SEARCH": "Cerca in...", "ACTION_CREATE_PROJECT": "Crea progetto", - "ACTION_IMPORT_PROJECT": "Importa progetto", "MANAGE_PROJECTS": "Gestisci Progetti", "TITLE_CREATE_PROJECT": "Crea progetto", - "TITLE_IMPORT_PROJECT": "Importa progetto", - "TITLE_PRVIOUS_PROJECT": "Mostra i progetti precedenti", - "TITLE_NEXT_PROJECT": "Progetto successivo", "HELP_TITLE": "Pagina di supporto Taiga", "HELP": "Aiuto", "HOMEPAGE": "Homepage", @@ -909,10 +826,6 @@ "FEEDBACK": "Feedback", "NOTIFICATIONS_TITLE": "Modifica le impostazioni delle notifiche", "NOTIFICATIONS": "Notifiche", - "ORGANIZATIONS_TITLE": "Modifica la tua organizzazione", - "ORGANIZATIONS": "Modifica organizzazioni", - "SETTINGS_TITLE": "Modifica le tue impostazioni", - "SETTINGS": "Impostazioni", "VIEW_PROFILE_TITLE": "Mostra profilo", "VIEW_PROFILE": "Mostra profilo", "EDIT_PROFILE_TITLE": "Modifica il tuo profilo", @@ -921,14 +834,68 @@ "CHANGE_PASSWORD": "Cambia password", "DASHBOARD_TITLE": "Dashboard", "DISCOVER_TITLE": "Scopri i progetti più seguiti", - "NEW_ITEM": "Nuovo", - "DISCOVER": "Scopri", - "ACTION_REORDER": "Usa drag & drop per riordinare" + "DISCOVER": "Scopri" + }, + "LIKE_BUTTON": { + "LIKE": "Mi piace", + "LIKED": "Piaciuto", + "UNLIKE": "Non mi piace", + "BUTTON_TITLE": "Vota a favore o a sfavore di questo progetto", + "COUNTER_TITLE": "{total, plural, one{un follower} other{# followers}}" + }, + "WATCH_BUTTON": { + "BUTTON_TITLE": "Osserva questo progetto ed imposta la politica di notifica", + "WATCH": "Osserva", + "WATCHING": "In osservazione", + "COUNTER_TITLE": "{total, plural, one{un osservatore} other{# osservatori}} ", + "OPTIONS": { + "NOTIFY_ALL": "Ricevi tutte le notifiche", + "NOTIFY_ALL_TITLE": "Ricevi tutte le notifiche per questo progetto", + "NOTIFY_INVOLVED": "Solo se conivolti", + "NOTIFY_INVOLVED_TITLE": "Ricevi notifiche solo quando coinvolto", + "UNWATCH": "Non osservare", + "UNWATCH_TITLE": "Non osservare il progetto" + } + }, + "CONTACT_BUTTON": { + "CONTACT_TITLE": "Contatta il team di progetto", + "CONTACT_BUTTON": "Contatta il progetto" + }, + "CREATE": { + "TITLE": "Crea Progetto", + "CHOOSE_TEMPLATE": "Which template fits your project better?", + "TEMPLATE_SCRUM": "Scrum", + "TEMPLATE_SCRUM_DESC": "Prioritize and solve your tasks in short time cycles.", + "TEMPLATE_SCRUM_LONGDESC": "Scrum is an iterative and incremental agile software development methodology for managing product development.\nThe product backlog is what will ultimately be delivered, ordered into the sequence in which it should be delivered. Product Backlogs are broken into manageable, executable chunks named sprints. Every certain amount of time the team initiates a new sprint and commits to deliver a certain number of user stories from the backlog, in accordance with their skills, abilities and resources. The project advances as the backlog becomes depleted.", + "TEMPLATE_KANBAN": "Kanban", + "TEMPLATE_KANBAN_DESC": "Keep a constant workflow on independent tasks", + "TEMPLATE_KANBAN_LONGDESC": "The Kanban methodology is used to divide project development (any sort of project) into stages.\nA kanban card is like an index card or post-it note that details every task (or user story) in a project that needs to be completed. The Kanban board is used to move each card from one state of completion to the next and in so doing, helps track progress.", + "DUPLICATE": "Duplicate project", + "DUPLICATE_DESC": "Start clean and keep your configuration", + "IMPORT": "Importa progetto", + "IMPORT_DESC": "Import your project from multiple platforms into Taiga", + "INVITE": "Invite to the project", + "SOLO_PROJECT": "You'll be alone in this project", + "INVITE_LATER": "(You'll be able to invite more members later)", + "BACK": "Back", + "MAX_PRIVATE_PROJECTS": "Unfortunately, You've reached the maximum number of private projects.\nIf you would like to increase the current limit please contact the administrator.", + "MAX_PUBLIC_PROJECTS": "Unfortunately, You've reached the maximum number of public projects.\nIf you would like to increase the current limit please contact the administrator.", + "PUBLIC_PROJECT": "Progetto Pubblico", + "PRIVATE_PROJECT": "Progetto Privato" + }, + "COMMON": { + "DETAILS": "New project details", + "PROJECT_TITLE": "Project Name", + "PROJECT_DESCRIPTION": "Project Description" + }, + "DUPLICATE": { + "TITLE": "Duplicate Project", + "DESCRIPTION": "Start clean and keep your configuration", + "SELECT_PLACEHOLDER": "Choose an existing project to duplicate" }, "IMPORT": { - "TITLE": "Importazione Progetto", - "UPLOADING_FILE": "Carico il file di dump", - "DESCRIPTION": "Questo processo puó durare un po', nel frattempo lasciare questa finestra aperta.", + "TITLE": "Import Project", + "DESCRIPTION": "Import your project from multiple platforms into Taiga", "ASYNC_IN_PROGRESS_TITLE": "I nostri Oompa Loompa stanno lavorando per importare il tuo progetto!", "ASYNC_IN_PROGRESS_MESSAGE": "Questo processo puó durare minuti.
Verrá inviata una mail al suo completamento", "UPLOAD_IN_PROGRESS_MESSAGE": "Caricati {{uploadedSize}} di {{totalSize}}", @@ -937,8 +904,29 @@ "ERROR_MESSAGE": "I nostri Oompa Loompa hanno qualche problema ad importare il dump dei tuoi dati: {{error_message}}", "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) è troppo pesante per i nostri Oompa Loompa; falli contenti, prova con una dimensione minore di ({{maxFileSize}})", "SYNC_SUCCESS": "Il tuo progetto è stato importato con successo", + "IMPORT": "Import", + "WHO_IS": "Their tasks will be assigned to ...", + "WRITE_EMAIL": "Or if you want, write the email that this user uses in Taiga", + "SEARCH_CONTACT": "Or if you want, search in your contacts", + "WRITE_EMAIL_LABEL": "Write the email that this user uses in Taiga", + "ACCEEDE": "Acceede", + "PROJECT_MEMBERS": "Project Members", + "PROCESS_DESCRIPTION": "Tell us who from Taiga you want to assign the tasks of {{platform}}", + "MATCH": "Is {{user_external}} the same person as {{user_internal}}?", + "CHOOSE": "Select user", + "LINKS": "Links with {{platform}}", + "LINKS_DESCRIPTION": "Do you want to keep the link of each item with the original {{platform}} card?", + "WARNING_MAIL_USER": "Note that if the user does not have a Taiga account we will not be able to assign the tasks to him.", + "ASSIGN": "Assegna", + "PROJECT_SELECTOR": { + "NO_RESULTS": "Sembra che non ci sia nulla che corrisponda ai criteri ricerca", + "ACTION_SEARCH": "cerca", + "ACTION_BACK": "Back" + }, "PROJECT_RESTRICTIONS": { - "PROJECT_MEMBERS_DESC": "Il progetto che stai provando a importare ha {{members}} membri, sfortunatamente, il tuo attuale abbonamento consente un massimo di {{max_membership}} membri per progetto. Se vuoi aumentare questo limite per favore contatta l'amministratore", + "PROJECT_MEMBERS_DESC_PRIVATE": "The project you are trying to import has {{members}} members including you, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per private project. If you would like to increase that limit please contact the administrator.", + "PROJECT_MEMBERS_DESC_PUBLIC": "The project you are trying to import has {{members}} members including you, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per public project. If you would like to increase that limit please contact the administrator.", + "ACCOUNT_ALLOW_MEMBERS": "Your account only allows {{members}} members", "PRIVATE_PROJECTS_SPACE": { "TITLE": "Sfortunatamente, il tuo attuale abbonamento non permette altri progetti privati", "DESC": "Il progetto che stai tentando di importare è privato. Sfortunatamente, il tuo attuale abbonamento non permette altri progetti privati" @@ -961,39 +949,67 @@ "TITLE": "Sfortunatamente il tuo attuale abbonamento non permette altri progetti pubblici o un aumento dii più di {{max_memberships}} membri per progetto pubblico", "DESC": "Il progetto che stai cercando di importare è pubblico e ha più di {{members}} membri." } - } - }, - "LIKE_BUTTON": { - "LIKE": "Mi piace", - "LIKED": "Piaciuto", - "UNLIKE": "Non mi piace", - "BUTTON_TITLE": "Vota a favore o a sfavore di questo progetto", - "COUNTER_TITLE": "{total, plural, one{un follower} other{# followers}}" - }, - "WATCH_BUTTON": { - "BUTTON_TITLE": "Osserva questo progetto ed imposta la politica di notifica", - "WATCH": "Osserva", - "WATCHING": "In osservazione", - "COUNTER_TITLE": "{total, plural, one{un osservatore} other{# osservatori}} ", - "OPTIONS": { - "NOTIFY_ALL": "Ricevi tutte le notifiche", - "NOTIFY_ALL_TITLE": "Ricevi tutte le notifiche per questo progetto", - "NOTIFY_INVOLVED": "Solo se conivolti", - "NOTIFY_INVOLVED_TITLE": "Ricevi notifiche solo quando coinvolto", - "UNWATCH": "Non osservare", - "UNWATCH_TITLE": "Non osservare il progetto" + }, + "IN_PROGRESS": { + "TITLE": "Importazione Progetto", + "DESCRIPTION": "Questo processo puó durare un po', nel frattempo lasciare questa finestra aperta." + }, + "WARNING": { + "TITLE": "Some taks will be unassigned", + "DESCRIPTION": "There are still unidentified people. The cards assigned to these people will remain unassigned. Check all the contacts to not lose that information.", + "CHECK": "Check contacts" + }, + "TAIGA": { + "SELECTOR": "Import your Taiga project" + }, + "TRELLO": { + "SELECTOR": "Import your Trello boards into Taiga", + "CHOOSE_PROJECT": "Choose board that you want to import", + "NO_PROJECTS": "It seems you have no boards in Trello" + }, + "GITHUB": { + "SELECTOR": "Import your GitHub project issues", + "CHOOSE_PROJECT": "Find the project you want to import", + "NO_PROJECTS": "It seems you have no porjects in GitHub", + "HOW_DO_YOU_WANT_TO_IMPORT": "How do you want to import your issues into Taiga?", + "KANBAN_PROJECT": "As user stories in a kanban project", + "KANBAN_PROJECT_DESCRIPTION": "After that you can enable scrum with backlog.", + "SCRUM_PROJECT": "As user stories in a scrum project", + "SCRUM_PROJECT_DESCRIPTION": "After that you can enable kanban mode.", + "ISSUES_PROJECT": "As issues", + "ISSUES_PROJECT_DESCRIPTION": "You will not be able to use your issues in kanban or scrum mode. You will be able to enable kanban or scrum for new user stories" + }, + "ASANA": { + "SELECTOR": "Import your Asana project and choose how to manage it", + "CHOOSE_PROJECT": "Choose project that you want to import", + "NO_PROJECTS": "It seems you have no porjects in Asana", + "KANBAN_PROJECT": "Kanban", + "SCRUM_PROJECT": "Scrum", + "CREATE_AS_SCRUM_DESCRIPTION": "The tasks and sub-tasks of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_KANBAN_DESCRIPTION": "The tasks and sub-tasks of your project will be created as Taiga user stories and tasks." + }, + "JIRA": { + "SELECTOR": "Import your Jira project and choose how to manage it", + "CHOOSE_PROJECT": "Choose project or board that you want to import", + "NO_PROJECTS": "It seems you have no porjects or boards in Jira", + "URL": "Your Jira URL", + "KANBAN_PROJECT": "Kanban", + "SCRUM_PROJECT": "Scrum", + "ISSUES_PROJECT": "problemi", + "CREATE_AS_SCRUM_DESCRIPTION": "The issues and sub-issues of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_KANBAN_DESCRIPTION": "The issues and sub-issues of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_ISSUES_DESCRIPTION": "What do you want to do with sub-issues from the Jira project? (Taiga doesn't allow sub-issues)", + "CREATE_NEW_ISSUES": "Convert sub-issues to new Taiga issues", + "NOT_CREATE_NEW_ISSUES": "Do not import sub-issues" } } }, "LIGHTBOX": { "DELETE_ACCOUNT": { - "SECTION_NAME": "Elimina Account Taiga", "CONFIRM": "Sei sicuro di voler eliminare il tuo account Taiga?", - "NEWSLETTER_LABEL_TEXT": "Non voglio più ricevere le vostre newsletter", "CANCEL": "Torna alle impostazioni", "ACCEPT": "Cancella account", - "BLOCK_PROJECT": "Ricorda che tutti i progetti che possiedi saranno bloccati quando cancellerai il tuo account. Se vuoi continuare a utilizzare un progetto bloccato, trasferisci la proprietà del progetto a un membro di ciascun progetto prima di cancellare il tuo account.", - "SUBTITLE": "Ci dispiace vederti andare via. Saremo qui se considererai ancora ! :(" + "BLOCK_PROJECT": "Ricorda che tutti i progetti che possiedi saranno bloccati quando cancellerai il tuo account. Se vuoi continuare a utilizzare un progetto bloccato, trasferisci la proprietà del progetto a un membro di ciascun progetto prima di cancellare il tuo account." }, "DELETE_PROJECT": { "TITLE": "Elimina progetto", @@ -1007,6 +1023,12 @@ }, "ADD_MEMBER": { "TITLE": "Nuovo Membro", + "PLACEHOLDER": "Filter users or write an email to invite", + "ADD_EMAIL": "Add email", + "REMOVE": "Remove", + "INVITE": "Invite", + "CHOOSE_ROLE": "Choose a role", + "PLACEHOLDER_INVITATION_TEXT": "(facoltativo) aggiungi un testo personalizzato all'invito. Di qualcosa di simpatico ai tuoi nuovi membri ;-)", "HELP_TEXT": "Se gli utenti sono già registrati su Taiga, verranno aggiunti automaticamente. In caso contrario, riceveranno un invito." }, "CREATE_ISSUE": { @@ -1068,6 +1090,12 @@ "TITLE": "Chi vuoi che sia il nuovo proprietario del progetto?", "ADD_COMMENT": "Aggiungi commento", "BUTTON": "Chiedi a questo membro di diventare il nuovo proprietario del progetto" + }, + "CONTACT_PROJECT": { + "TITLE": "Inviare un'email a", + "WARNING": "Questa email sarà ricevuta dagli amministratori di progetto", + "PLACEHOLDER": "Scrivi il tuo messaggio", + "SEND": "Invia" } }, "EPIC": { @@ -1101,15 +1129,9 @@ "ADD_BULK": "Aggiungere qualche nuova User Storie al carico", "PROMOTED": "Questa storia utente è stata promossa da problema:", "TITLE_LINK_GO_TO_ISSUE": "Vai al problema", - "EXTERNAL_REFERENCE": "Questo US é stato creato da", - "GO_TO_EXTERNAL_REFERENCE": "Ritorna all'inizio", - "BLOCKED": "Questa storia utente è bloccata", "TITLE_DELETE_ACTION": "Elimina la storia utente", "LIGHTBOX_TITLE_BLOKING_US": "Blocco la storia utente", - "TASK_COMPLETED": "{{totalClosedTasks}}/{{totalTasks}} compiti completati", - "ASSIGN": "Assegna la storia utente", "NOT_ESTIMATED": "Non stimato", - "TOTAL_US_POINTS": "Totale punti della storia utente", "TRIBE": { "PUBLISH": "Pubblica come Gig in Taiga Tribe", "PUBLISH_INFO": "Più info", @@ -1119,23 +1141,19 @@ "CLOSE": "Chiudi", "SYNCHRONIZE_LINK": "sincronizza con Taiga Tribe", "PUBLISH_MORE_INFO_TITLE": "Hai bisogno di qualcuno per questo task?", - "PUBLISH_MORE_INFO_TEXT": "

Se hai bisogno di aiuto per un particolare lavoro puoi creare facilmente annunci on Taiga Tribe e ricevere aiuto da tutto il mondo. Sarai in grado di controllare e gestire l'annuncio godendo di una fantastica comunità vogliosa di contribuire.

Taiga Tribe è nato come fratello di Taiga. Entrambe le piattaforme posso vivere separatamente, ma noi crediamo sia molto potente usarle insieme e vogliamo essere certi che l'integrazione funziona senza problemi.

" + "PUBLISH_MORE_INFO_TEXT": "

If you need help with a particular piece of work you can easily create gigs on Taiga Tribe and receive help from all over the world. You will be able to control and manage the gig enjoying a great community eager to contribute.

TaigaTribe was born as a Taiga sibling. Both platforms can live separately but we believe that there is much power in using them combined so we are making sure the integration works like a charm.

" }, "FIELDS": { "TEAM_REQUIREMENT": "Requisito del team", - "CLIENT_REQUIREMENT": "Requisito del client", - "FINISH_DATE": "Data di conclusione" + "CLIENT_REQUIREMENT": "Requisito del client" } }, "COMMENTS": { "DELETED_INFO": "Commento eliminato da {{user}}", - "TITLE": "Commenti", "COMMENTS_COUNT": "{{comments}} Commenti", - "ORDER": "Ordine", "OLDER_FIRST": "I più vecchi prima", "RECENT_FIRST": "I più recenti prima", "COMMENT": "Commento", - "EDIT_COMMENT": "Modifica commento", "EDITED_COMMENT": "Modificato:", "SHOW_HISTORY": "Vai alla cronologia", "TYPE_NEW_COMMENT": "Scrivi un nuovo commento qui", @@ -1148,13 +1166,8 @@ } }, "ACTIVITY": { - "SHOW_ACTIVITY": "Mostra attività", - "DATETIME": "DD MMM YYYY HH:mm", - "SHOW_MORE": "Mostra gli inserimenti precedenti ({{showMore}} more)", "TITLE": "Attività", "ACTIVITIES_COUNT": "{{Activities}} Attività", - "REMOVED": "rimosso", - "ADDED": "aggiunto", "TAGS_ADDED": "Tag aggiunti:", "TAGS_REMOVED": "tag rimossi:", "US_POINTS": "{{role}} punti", @@ -1163,50 +1176,21 @@ "UPDATED_ATTACHMENT": "Aggiorna allegato ({{filename}}):", "CREATED_CUSTOM_ATTRIBUTE": "crea un attributo personalizzato", "UPDATED_CUSTOM_ATTRIBUTE": "attributo personalizzato aggiornato", - "SIZE_CHANGE": "Fatto {size, plural, one{un cambiamento} other{# cambiamenti}}", "BECAME_DEPRECATED": "diventa deprecato", "BECAME_UNDEPRECATED": "diventa accettato", "TEAM_REQUIREMENT": "Requisito del team", "CLIENT_REQUIREMENT": "Requisito del client", "BLOCKED": "Bloccato", "VALUES": { - "YES": "si", - "NO": "no", - "EMPTY": "vuoto", "UNASSIGNED": "non assegnato" }, "FIELDS": { "SUBJECT": "oggetto", - "NAME": "nome", "DESCRIPTION": "descrizione", - "CONTENT": "contenuto", "STATUS": "stato", - "IS_CLOSED": "è chiuso?", - "FINISH_DATE": "Data di fine", "TYPE": "tipo", - "PRIORITY": "priorità", - "SEVERITY": "criticità", "ASSIGNED_TO": "assegnato a", - "WATCHERS": "Osservatori", "MILESTONE": "sprint", - "USER_STORY": "storia utente", - "PROJECT": "progetto", - "IS_BLOCKED": "è bloccato", - "BLOCKED_NOTE": "nota bloccata", - "POINTS": "punti", - "CLIENT_REQUIREMENT": "Requisito del client", - "TEAM_REQUIREMENT": "Requisiti del team", - "IS_IOCAINE": "è un'aspirina", - "TAGS": "tag", - "ATTACHMENTS": "allegati", - "IS_DEPRECATED": "è deprecato", - "IS_NOT_DEPRECATED": "non è deprecato", - "ORDER": "ordine", - "BACKLOG_ORDER": "Ordine di backlog", - "SPRINT_ORDER": "Ordine dello sprint", - "KANBAN_ORDER": "ordina kanban", - "TASKBOARD_ORDER": "Ordine del pannello dei compiti", - "US_ORDER": "Ordine delle storie utente", "COLOR": "colore" } }, @@ -1220,8 +1204,6 @@ "CUSTOMIZE_GRAPH_TITLE": "Imposta i punti e gli sprint come Amministratore", "MOVE_US_TO_CURRENT_SPRINT": "Spostati allo sprint attuale", "MOVE_US_TO_LATEST_SPRINT": "Vai allo Sprint più recente", - "SHOW_FILTERS": "Mostra filtri", - "SHOW_TAGS": "Mostra tag", "EMPTY": "OMG..Il backlog é vuoto!!", "CREATE_NEW_US": "Crea una nuova Storia Utente", "CREATE_NEW_US_EMPTY_HELP": "Potresti voler creare una nuova storia utente", @@ -1248,6 +1230,12 @@ "SHOW": "Mostra tag", "HIDE": "Nascondi tag" }, + "FORECASTING": { + "TITLE": "Previsione di velocità", + "BACKLOG": "Display backlog", + "NEW_SPRINT": "Candidate User Stories for your next sprint based on your velocity. Click to create a new sprint.", + "CURRENT_SPRINT": "Candidate User Stories for your sprint based on your velocity. Click to add to current sprint." + }, "TABLE": { "COLUMN_US": "Storie Utente", "TITLE_COLUMN_POINTS": "Seleziona vista per Ruolo" @@ -1270,8 +1258,6 @@ }, "FILTERS": { "TOGGLE": "Premi i filtri visibilità", - "TITLE": "Filtri", - "REMOVE": "Rimuovi filtri", "HIDE": "Nascondi Filtri", "SHOW": "Mostra Filtri" }, @@ -1280,7 +1266,6 @@ "DATE": "DD MMM YYYY", "LINK_TASKBOARD": "Pannello dei compiti dello sprint", "TITLE_LINK_TASKBOARD": "Vai al pannello dei compiti di \"{{name}}\"", - "NUMBER_SPRINTS": "
sprints", "EMPTY": "Non ci sono ancora sprints disponibili", "WARNING_EMPTY_SPRINT_ANONYMOUS": "Lo Sprint non ha Storie Utente", "WARNING_EMPTY_SPRINT": "Metti qui le storie del tuo backlog che iniziare in nuovo sprint", @@ -1305,7 +1290,6 @@ "TITLE_ACTION_ADD": "Aggiungi un nuovo compito", "TITLE_ACTION_ADD_BULK": "Aggiungi qualche nuovo Compito nel carico", "TITLE_ACTION_ASSIGN": "Compito assegnato", - "TITLE_ACTION_EDIT": "Modifica compito", "PLACEHOLDER_CARD_TITLE": "Questo potrebbe essere un compito", "PLACEHOLDER_CARD_TEXT": "Dividi le storie in compiti per tenerne traccia separatamente", "TABLE": { @@ -1335,17 +1319,11 @@ "TITLE_SELECT_STATUS": "Nome dello status", "OWNER_US": "Questo compito appartiene a", "TITLE_LINK_GO_OWNER": "Vai alla storia utente", - "ORIGIN_US": "Questo compito è stato creato da", - "TITLE_LINK_GO_ORIGIN": "Vai alla storia utente", - "BLOCKED": "Questo compito è bloccato", "TITLE_DELETE_ACTION": "Rimuovi compito", "LIGHTBOX_TITLE_BLOKING_TASK": "Sto bloccando il compito", "FIELDS": { - "MILESTONE": "Sprint", - "USER_STORY": "Storia utente", "IS_IOCAINE": "E' un'aspirina" }, - "ACTION_IOCAINE": "aspirina", "TITLE_ACTION_IOCAINE": "Sei stremato? Assicurati che gli altri lo sappiano cliccando su 'aspirina' quando stai lavorando su compito che ti affatica. Ma non demordere, ricordati: si può migliorare solo se di tanto in tanto si accettano sfide extra!" }, "NOTIFICATION": { @@ -1374,14 +1352,12 @@ "ISSUES": { "PAGE_TITLE": "Criticitá - {{projectName}}", "PAGE_DESCRIPTION": "Il pannello con la lista dei problemi del progetto {{projectName}}: {{projectDescription}}", - "LIST_SECTION_NAME": "problemi", "SECTION_NAME": "Problema", "ACTION_NEW_ISSUE": "+ NUOVA CRITICITÁ", "ACTION_PROMOTE_TO_US": "Promuovi la storia utente", "PROMOTED": "Il problema è stato promosso a storia utente", "EXTERNAL_REFERENCE": "Questo problema è stato creato da ", "GO_TO_EXTERNAL_REFERENCE": "Ritorna all'inizio", - "BLOCKED": "Questo problema è bloccato", "ACTION_DELETE": "Elimina problema", "LIGHTBOX_TITLE_BLOKING_ISSUE": "Issue bloccante", "FIELDS": { @@ -1423,15 +1399,11 @@ "SECTION_NAME": "Kanban", "TITLE_ACTION_FOLD": "Ripiega la colonna", "TITLE_ACTION_UNFOLD": "Riapri la colonna", - "TITLE_ACTION_FOLD_CARDS": "ripiega la scheda", - "TITLE_ACTION_UNFOLD_CARDS": "Apri le carte", "TITLE_ACTION_ADD_US": "Aggiungi una nuova storia utente", "TITLE_ACTION_ADD_BULK": "Aggiungi un nuovo carico", "ACTION_SHOW_ARCHIVED": "Mostra archivio", "ACTION_HIDE_ARCHIVED": "Nascondi archivio", "HIDDEN_USER_STORIES": "Le storie utente in questo status sono nascoste by default", - "ARCHIVED": "Hai archiviato", - "UNDO_ARCHIVED": "Trascina e lascia di nuovo per annullare", "PLACEHOLDER_CARD_TITLE": "Queste sono le tue storie utente.", "PLACEHOLDER_CARD_TEXT": "Le storie possono anche avere dei sotto-compiti che separano i requisiti" }, @@ -1452,7 +1424,6 @@ "PAGE_TITLE": "Team - {{projectName}}", "PAGE_DESCRIPTION": "Il pannello del team da mostrare a tutti i membri del progetto {{projectName}}: {{projectDescription}}", "SECTION_NAME": "Squadra", - "APP_TITLE": "TEAM - {{projectName}}", "PLACEHOLDER_INPUT_SEARCH": "Cerca con il nome completo", "COLUMN_MR_WOLF": "Mr. Wolf", "EXPLANATION_COLUMN_MR_WOLF": "Problema chiuso", @@ -1488,18 +1459,9 @@ "OPTION_ALL": "Tutti", "OPTION_INVOLVED": "Coinvolto", "OPTION_NONE": "Nessuno" - }, - "POPOVER": { - "USER_PROFILE": "Profilo utente", - "CHANGE_PASSWORD": "Cambia Password", - "NOTIFICATIONS": "Notifiche", - "FEEDBACK": "Feedback", - "TITLE_AVATAR": "Preferenze utente" } }, "USER_PROFILE": { - "IMAGE_HELP": "L'immagine sarà scalata a 80x80px.", - "ACTION_CHANGE_IMAGE": "Cambia", "ACTION_USE_GRAVATAR": "Usa l'immagine di default", "ACTION_DELETE_ACCOUNT": "Elimina l'account Taiga", "CHANGE_EMAIL_SUCCESS": "Controlla la tua casella di posta
abbiamo mandato una mail al tuo account
con le istruzioni per impostare un nuovo indirizzo", @@ -1517,25 +1479,10 @@ "THEME_DEFAULT": "-- usa tema predefinito --" } }, - "WIZARD": { - "SECTION_TITLE_CREATE_PROJECT": "Crea Progetto", - "CREATE_PROJECT_TEXT": "Nuovo di zecca. Vai così!", - "CHOOSE_TEMPLATE": "Quale template si adatta meglio al tuo progetto?", - "CHOOSE_TEMPLATE_TITLE": "Più info sui template di progetto", - "CHOOSE_TEMPLATE_INFO": "Più info", - "PROJECT_DETAILS": "Dettagli Progetto", - "PUBLIC_PROJECT": "Progetto Pubblico", - "PRIVATE_PROJECT": "Progetto Privato", - "CREATE_PROJECT": "Crea progetto", - "MAX_PRIVATE_PROJECTS": "Hai raggiunto il numero massimo di progetti privati", - "MAX_PUBLIC_PROJECTS": "Sfortunatamente. hai raggiunto il numero massimo di progetti pubblici", - "CHANGE_PLANS": "cambia abbonamento" - }, "WIKI": { "PAGE_TITLE": "{{wikiPageName}} - Wiki - {{projectName}}", "PAGE_DESCRIPTION": "L'ultima versione su {{lastModifiedDate}} ({{totalEditions}} versioni in totale) Contenuto: {{ wikiPageContent }}", "DATETIME": "DD MMM YYYY HH:mm", - "PLACEHOLDER_PAGE": "Crea la tua pagina wiki", "REMOVE": "Rimuovi questa pagina wiki", "DELETE_LIGHTBOX_TITLE": "Elimina Pagina Wiki", "DELETE_LINK_TITLE": "Cancella collegamento Wiki", @@ -1693,7 +1640,6 @@ "MOST_LIKED": "Preferiti", "MOST_LIKED_EMPTY": "Non ci sono ancora progetti PREFERITI", "VIEW_MORE": "Vedi altro", - "RECRUITING": "Il progetto cerca persone", "FEATURED": "Progetti in Vetrina", "EMPTY": "Non ci sono progetti da mostrare con questi criteri.
Prova ancora!", "FILTERS": { diff --git a/app/locales/taiga/locale-ja.json b/app/locales/taiga/locale-ja.json new file mode 100644 index 00000000..78e40617 --- /dev/null +++ b/app/locales/taiga/locale-ja.json @@ -0,0 +1,1664 @@ +{ + "COMMON": { + "YES": "はい", + "NO": "いいえ", + "OR": "または", + "LOADING": "ロード中...", + "DATE": "YYYY年MM月DD日", + "DATETIME": "YYYY年MM月DD日 HH時mm分", + "SAVE": "保存", + "CANCEL": "キャンセル", + "ACCEPT": "はい", + "DELETE": "削除", + "UNLINK": "リンク解除", + "CREATE": "作成", + "ADD": "追加", + "COPY_TO_CLIPBOARD": "クリップボードにコピー: Ctrl+C", + "EDIT": "編集", + "DRAG": "ドラッグ", + "TAG_LINE": "あなたのアジャイルでフリーでオープンソースなマネジメントツールです", + "TAG_LINE_2": "LOVE YOUR PROJECT", + "BLOCK": "ブロック", + "BLOCK_TITLE": "Block this item for example if it has a dependency that can not be satisfied", + "BLOCKED": "ブロック中", + "UNBLOCK": "ブロック解除", + "UNBLOCK_TITLE": "ブロックを解除する", + "BLOCKED_NOTE": "なぜこれはブロックされているのか?", + "BLOCKED_REASON": "理由を説明してください", + "CREATED_BY": "{{fullDisplayName}} によって作成", + "CLOSE": "閉じる", + "GO_HOME": "ホームに戻る", + "PLUGINS": "プラグイン", + "ONE_ITEM_LINE": "1行に1アイテム", + "NEW_BULK": "一括登録", + "RELATED_TASKS": "関連タスク", + "PREVIOUS": "前", + "NEXT": "次へ", + "LOGOUT": "ログアウト", + "EXTERNAL_USER": "外部ユーザー", + "GENERIC_ERROR": "ウンパルンパのひとりが「{{error}}」と言っています。", + "IOCAINE_TEXT": "This member is feeling a bit overwhelmed by this task. Will become immune to the iocaine poison over time with your help. For now, may need a hug.", + "CLIENT_REQUIREMENT": "Client requirement is new requirement that was not previously expected and it is required to be part of the project", + "TEAM_REQUIREMENT": "Team requirement is a requirement that must exist in the project but should have no cost for the client", + "OWNER": "プロジェクトオーナー", + "CAPSLOCK_WARNING": "Be careful! You are using capital letters in an input field that is case sensitive.", + "CONFIRM_CLOSE_EDIT_MODE_TITLE": "本当にこの編集画面を閉じてもよろしいですか?", + "CONFIRM_CLOSE_EDIT_MODE_MESSAGE": "保存せずに編集画面を閉じた場合、すべての変更が失われます。", + "RELATED_USERSTORIES": "関連するユーザーストーリー", + "CARD": { + "ASSIGN_TO": "アサイン", + "EDIT": "編集" + }, + "FORM_ERRORS": { + "DEFAULT_MESSAGE": "無効な値です", + "TYPE_EMAIL": "有効なメールアドレスでなければいけません", + "TYPE_URL": "有効なURLでなければいけません", + "TYPE_URLSTRICT": "有効なURLでなければいけません", + "TYPE_NUMBER": "有効な数字でなければいけません", + "TYPE_DIGITS": "アラビア数字でなければいけません", + "TYPE_DATEISO": "YYYY-MM-DD の形式でなければいけません (例: 2038年01月23日)", + "TYPE_ALPHANUM": "半角英数字でなければなりません", + "TYPE_PHONE": "有効な電話番号でなければいけません", + "NOTNULL": "null以外でなければいけません", + "NOT_BLANK": "空欄にできません", + "REQUIRED": "必須です", + "REGEXP": "無効な値です", + "MIN": "この値は %s 以上でなければいけません", + "MAX": "この値は %s 以下でなければいけません", + "RANGE": "この値は %s と %s の間でなければいけません", + "MIN_LENGTH": "文字数が短すぎます。%s 文字以上にしてください。", + "MAX_LENGTH": "入力した値が長すぎます。%s 文字以下にしてください。", + "RANGE_LENGTH": "文字数が無効です。%s から %s 文字の間でなければいけません ", + "MIN_CHECK": "%s 以上選択してください。", + "MAX_CHECK": "選択できるのは %s までです", + "RANGE_CHECK": "選択できるのは %s から %s までです", + "EQUAL_TO": "この値は同じでなければいけません", + "LINEWIDTH": "行がおそらく長すぎます。%s文字以内におさえてください。", + "PIKADAY": "無効なデータフォーマットです。DD MMM YYYYの形式で入力してください。(例:23 Mar 1984)" + }, + "PICKERDATE": { + "FORMAT": "YYYY年MM月DD日", + "IS_RTL": "false", + "FIRST_DAY_OF_WEEK": "1", + "PREV_MONTH": "先月", + "NEXT_MONTH": "翌月", + "MONTHS": { + "JAN": "1月", + "FEB": "2月", + "MAR": "3月", + "APR": "4月", + "MAY": "5月", + "JUN": "6月", + "JUL": "7月", + "AUG": "8月", + "SEP": "9月", + "OCT": "10月", + "NOV": "11月", + "DEC": "12月" + }, + "WEEK_DAYS": { + "SUN": "日曜", + "MON": "月曜", + "TUE": "火曜", + "WED": "水曜", + "THU": "木曜日", + "FRI": "金曜", + "SAT": "土曜" + }, + "WEEK_DAYS_SHORT": { + "SUN": "日", + "MON": "月", + "TUE": "火", + "WED": "水", + "THU": "木", + "FRI": "金", + "SAT": "土" + } + }, + "SEE_USER_PROFILE": "{{username }} のプロフィールを見る", + "USER_STORY": "User story", + "TASK": "タスク", + "ISSUE": "課題", + "EPIC": "エピック", + "TAGS": { + "PLACEHOLDER": "タグを入力", + "DELETE": "タグを削除", + "ADD": "タグを追加" + }, + "DESCRIPTION": { + "EMPTY": "空欄だと退屈です…。説明を追加してください。", + "NO_DESCRIPTION": "説明はありません" + }, + "FIELDS": { + "SUBJECT": "題名", + "NAME": "名前", + "URL": "URL", + "DESCRIPTION": "説明", + "VALUE": "値", + "SLUG": "スラッグ", + "COLOR": "色", + "IS_CLOSED": "クローズ", + "STATUS": "ステータス", + "TYPE": "タイプ", + "SEVERITY": "深刻度", + "PRIORITY": "優先度", + "ASSIGNED_TO": "担当者", + "POINTS": "ポイント", + "IS_BLOCKED": "はブロックされています。", + "REF": "参照", + "VOTES": "投票", + "SPRINT": "スプリント" + }, + "ROLES": { + "ALL": "すべて" + }, + "ASSIGNED_TO": { + "NOT_ASSIGNED": "未アサイン", + "ASSIGN": "アサイン", + "DELETE_ASSIGNMENT": "アサインを解除", + "REMOVE_ASSIGNED": "Remove assigned", + "TOO_MANY": "…ユーザーが多すぎます。フィルタを継続してください。", + "CONFIRM_UNASSIGNED": "本当にこのアサインから外れてもよろしいですか?", + "TITLE_ACTION_EDIT_ASSIGNMENT": "アサインを編集", + "SELF": "自分が担当する" + }, + "STATUS": { + "CLOSED": "終了", + "OPEN": "オープン" + }, + "WATCHERS": { + "WATCHERS": "ウォッチャー", + "ADD": "ウォッチャー追加", + "TITLE_ADD": "プロジェクトメンバーをウォッチャーリストへ追加", + "DELETE": "ウォッチャーを削除", + "TITLE_LIGHTBOX_DELETE_WARTCHER": "ウォッチャーの削除..." + }, + "WATCH_BUTTON": { + "WATCH": "フォロー", + "WATCHING": "フォロー中", + "UNWATCH": "フォローをやめる", + "WATCHERS": "ウォッチャー", + "BUTTON_TITLE": "この項目のフォローを有効/無効にする", + "COUNTER_TITLE": "{total, plural, one{one watcher} other{# 人がフォロー中}}" + }, + "VOTE_BUTTON": { + "BUTTON_TITLE": "賛成/反対の投票を行う", + "COUNTER_TITLE": "{total, plural, one{one vote} other{# 人が賛成}}" + }, + "CUSTOM_ATTRIBUTES": { + "CUSTOM_FIELDS": "カスタムフィールド", + "SAVE": "カスタムフィールドを保存", + "EDIT": "カスタムフィールドを編集", + "DELETE": "カスタム属性を削除", + "CONFIRM_DELETE": "このカスタムフィールドのすべての値が削除されることになります。\n本当にこのまま続行してもよろしいですか?" + }, + "FILTERS": { + "INPUT_PLACEHOLDER": "Subject or reference", + "TITLE_ACTION_FILTER_BUTTON": "検索", + "TITLE": "フィルター", + "TITLE_ACTION_SEARCH": "検索", + "ACTION_SAVE_CUSTOM_FILTER": "カスタムフィルターとして保存する", + "PLACEHOLDER_FILTER_NAME": "フィルター名を入力しエンターキーを押してください。", + "APPLIED_FILTERS_NUM": "フィルター適用中", + "CATEGORIES": { + "TYPE": "タイプ", + "STATUS": "ステータス", + "SEVERITY": "深刻度", + "PRIORITIES": "優先度", + "TAGS": "タグ", + "ASSIGNED_TO": "担当者", + "CREATED_BY": "作成者", + "CUSTOM_FILTERS": "カスタムフィルター", + "EPIC": "エピック" + } + }, + "WYSIWYG": { + "OUTDATED": "あなたが編集中に別のユーザーが変更を加えました。あなたの変更点を保存する前に、アクティビティタブで新しいバージョンを確認してください。", + "MARKDOWN_HELP": "Markdown記法のヘルプ" + }, + "PERMISIONS_CATEGORIES": { + "EPICS": { + "NAME": "エピック", + "VIEW_EPICS": "エピックの表示", + "ADD_EPICS": "エピックを追加", + "MODIFY_EPICS": "エピックの変更", + "COMMENT_EPICS": "複数のエピックにコメントする", + "DELETE_EPICS": "エピックの削除" + }, + "SPRINTS": { + "NAME": "スプリント", + "VIEW_SPRINTS": "スプリントの表示", + "ADD_SPRINTS": "スプリントを追加", + "MODIFY_SPRINTS": "スプリントの変更", + "DELETE_SPRINTS": "スプリントの削除" + }, + "USER_STORIES": { + "NAME": "ユーザーストーリー", + "VIEW_USER_STORIES": "ユーザーストーリーの表示", + "ADD_USER_STORIES": "ユーザーストーリーを追加", + "MODIFY_USER_STORIES": "ユーザーストーリーの変更", + "COMMENT_USER_STORIES": "複数のユーザーストーリーにコメントする", + "DELETE_USER_STORIES": "ユーザーストーリーの削除" + }, + "TASKS": { + "NAME": "タスク", + "VIEW_TASKS": "タスクの表示", + "ADD_TASKS": "タスクを追加", + "MODIFY_TASKS": "タスクの変更", + "COMMENT_TASKS": "複数のタスクにコメントする", + "DELETE_TASKS": "タスクの削除" + }, + "ISSUES": { + "NAME": "課題", + "VIEW_ISSUES": "課題の表示", + "ADD_ISSUES": "課題を追加", + "MODIFY_ISSUES": "課題の変更", + "COMMENT_ISSUES": "複数の課題にコメントする", + "DELETE_ISSUES": "課題の削除" + }, + "WIKI": { + "NAME": "Wiki", + "VIEW_WIKI_PAGES": "Wikiページの表示", + "ADD_WIKI_PAGES": "Wikiページを追加", + "MODIFY_WIKI_PAGES": "Wikiページの変更", + "DELETE_WIKI_PAGES": "Wikiページの削除", + "VIEW_WIKI_LINKS": "Wikiリンクの表示", + "ADD_WIKI_LINKS": "Wikiリンクを追加", + "DELETE_WIKI_LINKS": "Wikiリンクの削除" + } + } + }, + "LOGIN": { + "PAGE_TITLE": "ログイン - Taiga", + "PAGE_DESCRIPTION": "仕事を本当に楽しくする美しくてシンプルなツールを求めている、スタートアップやアジャイル開発者及びデザイナーのためのプロジェクトマネジメント基盤、Taigaにログインしましょう。" + }, + "AUTH": { + "INVITED_YOU": "があなたをプロジェクトに参加するよう招待しています", + "NOT_REGISTERED_YET": "未登録ですか?", + "REGISTER": "登録", + "CREATE_ACCOUNT": "こちらから無料でアカウントを作成" + }, + "LOGIN_COMMON": { + "HEADER": "すでにログインしたことがあります", + "PLACEHOLDER_AUTH_NAME": "ユーザー名 または メールアドレス", + "LINK_FORGOT_PASSWORD": "忘れましたか?", + "TITLE_LINK_FORGOT_PASSWORD": "パスワードを忘れましたか?", + "ACTION_ENTER": "決定", + "ACTION_SIGN_IN": "ログイン", + "PLACEHOLDER_AUTH_PASSWORD": "パスワード" + }, + "LOGIN_FORM": { + "ERROR_AUTH_INCORRECT": "「あなたのユーザー名/メールアドレス または パスワードが間違っている」とウンパルンパたちが言っています。", + "SUCCESS": "ウンパルンパたちは嬉しいみたいですよ。Taigaへようこそ。" + }, + "REGISTER": { + "PAGE_TITLE": "登録 - Taiga", + "PAGE_DESCRIPTION": "仕事を本当に楽しくする美しくてシンプルなツールを求めるスタートアップや、アジャイル開発者及びデザイナーのためのプロジェクトマネジメントプラットフォーム、Taigaにあなたのアカウントを作成しましょう。" + }, + "REGISTER_FORM": { + "TITLE": "新しいTaigaアカウントを登録する (無料)", + "PLACEHOLDER_NAME": "ユーザー名を記入", + "PLACEHOLDER_FULL_NAME": "フルネームを記入", + "PLACEHOLDER_EMAIL": "メールアドレスを記入", + "PLACEHOLDER_PASSWORD": "パスワードを設定 (大文字・小文字を区別)", + "ACTION_SIGN_UP": "サインアップ", + "TITLE_LINK_LOGIN": "ログイン", + "LINK_LOGIN": "登録の準備は整いましたか? ログイン" + }, + "FORGOT_PASSWORD": { + "PAGE_TITLE": "パスワードを忘れました - Taiga", + "PAGE_DESCRIPTION": "新しいパスワードを取得するためにユーザー名 または メールアドレスを記入することで、Taigaに再びアクセスできます。" + }, + "FORGOT_PASSWORD_FORM": { + "TITLE": "おっと、パスワードを忘れてしまいましたか?", + "SUBTITLE": "新しく始めるためにユーザー名 または メールアドレスを入力", + "PLACEHOLDER_FIELD": "ユーザー名 または メールアドレス", + "ACTION_RESET_PASSWORD": "パスワードをリセット", + "LINK_CANCEL": "いいえ、戻ります。私はそれを覚えていると思います。", + "SUCCESS_TITLE": "Inboxを確認してください", + "SUCCESS_TEXT": "新しいパスワードを設定するための指示を記載したメールを送信しました", + "ERROR": "「あなたのアカウントはまだ登録されていない」とウンパルンパたちが言っています。" + }, + "CHANGE_PASSWORD": { + "PAGE_TITLE": "パスワードの変更 - Taiga", + "SECTION_NAME": "パスワード変更", + "FIELD_CURRENT_PASSWORD": "現在のパスワード", + "PLACEHOLDER_CURRENT_PASSWORD": "現在のパスワード (パスワードが未設定の場合は空)", + "FIELD_NEW_PASSWORD": "新しいパスワード", + "PLACEHOLDER_NEW_PASSWORD": "新しいパスワードを入力", + "FIELD_RETYPE_PASSWORD": "新しいパスワードを再入力", + "PLACEHOLDER_RETYPE_PASSWORD": "新しいパスワードを再入力", + "ERROR_PASSWORD_MATCH": "パスワードが一致しません。" + }, + "CHANGE_PASSWORD_RECOVERY_FORM": { + "TITLE": "新しいTaigaのパスを作成", + "SUBTITLE": "そして、いくつかの鉄分豊富な食品を摂取しましょう!脳にとって良いことです :-P", + "PLACEHOLDER_NEW_PASSWORD": "新しいパスワード", + "PLACEHOLDER_RE_TYPE_NEW_PASSWORD": "新しいパスワードを再入力", + "ACTION_RESET_PASSWORD": "パスワードをリセット", + "ERROR": "ウンパルンパたちはあなたのパスワード復元依頼を見つけられないようです。もう一度お試しください。", + "SUCCESS": "ウンパルンパたちはあなたの新しいパスワードを保存しました。
新しい方のパスワードでサインイン してみてください。" + }, + "INVITATION": { + "PAGE_TITLE": "招待を受諾する - Taiga", + "PAGE_DESCRIPTION": "仕事を本当に楽しくする美しくてシンプルなツールを求めるスタートアップや、アジャイル開発者及びデザイナーのためのプロジェクトマネジメントプラットフォーム、Taigaのプロジェクトへの招待を受諾" + }, + "INVITATION_LOGIN_FORM": { + "NOT_FOUND": "「あなたの招待を確認できなかった」とウンパルンパたちが言っています。", + "SUCCESS": "プロジェクトへの参加に成功しました, {{project_name}}へようこそ" + }, + "HOME": { + "PAGE_TITLE": "ホーム - Taiga", + "PAGE_DESCRIPTION": "The Taiga home page with your main projects and all your assigned and watched user stories, tasks and issues", + "EMPTY_WORKING_ON": "何も表示されていませんか? Taigaで作業を始めると、ここにあなたが取り組んでいるユーザーストーリー、タスク、課題が表示されます。", + "EMPTY_WATCHING": "ユーザーストーリー、タスク、課題をフォローして変更が発生した際に通知を受け取りましょう。", + "EMPTY_PROJECT_LIST": "参加中のプロジェクトがありません", + "WORKING_ON_SECTION": "取り組んでいる作業", + "WATCHING_SECTION": "フォロー中", + "DASHBOARD": "プロジェクトのダッシュボート" + }, + "EPICS": { + "TITLE": "エピック", + "SECTION_NAME": "エピック", + "EPIC": "エピック", + "PAGE_TITLE": "エピック - {{projectName}}", + "PAGE_DESCRIPTION": "エピックの一覧 {{projectName}}: {{projectDescription}}", + "DASHBOARD": { + "ADD": "エピックを追加", + "UNASSIGNED": "未アサイン" + }, + "EMPTY": { + "TITLE": "まだエピックが無いようです", + "EXPLANATION": "エピックはユーザーストーリーを包含する、より上の階層のものです。
階級のトップにあり、ユーザーストーリーをグループ化してまとめるのにも用いられます。", + "HELP": "エピックについて" + }, + "TABLE": { + "VOTES": "投票", + "NAME": "名前", + "PROJECT": "プロジェクト", + "SPRINT": "スプリント", + "ASSIGNED_TO": "アサイン済", + "STATUS": "ステータス", + "PROGRESS": "進捗", + "VIEW_OPTIONS": "オプションの表示" + }, + "CREATE": { + "TITLE": "新しいエピック", + "PLACEHOLDER_DESCRIPTION": "このエピックを他の人が理解できるように説明を加えて下さい", + "TEAM_REQUIREMENT": "チームからの要求", + "CLIENT_REQUIREMENT": "お客様からの要求", + "BLOCKED": "ブロック中", + "BLOCKED_NOTE_PLACEHOLDER": "なぜこのエピックはブロックされているのか?", + "CREATE_EPIC": "エピックを作成" + } + }, + "PROJECTS": { + "PAGE_TITLE": "マイ プロジェクト - Taiga", + "PAGE_DESCRIPTION": "A list with all your projects, you can reorder or create a new one.", + "MY_PROJECTS": "マイ プロジェクト" + }, + "ATTACHMENT": { + "SECTION_NAME": "添付ファイル", + "TITLE": "{{ fileName }} が {{ date }} にアップロードされました", + "LIST_VIEW_MODE": "ライブビューモード", + "GALLERY_VIEW_MODE": "ギャラリービューモード", + "DESCRIPTION": "要約を入力", + "DEPRECATED": "(非推奨)", + "DEPRECATED_FILE": "推奨されませんか?", + "ADD": "新しい添付ファイルを追加する。 {{maxFileSizeMsg}}", + "DROP": "添付ファイルをここにドロップ!", + "SHOW_DEPRECATED": "+ 非推奨のアタッチメントを表示する", + "HIDE_DEPRECATED": "- 非推奨のアタッチメントを隠す", + "COUNT_DEPRECATED": "({{ counter }} deprecated)", + "MAX_UPLOAD_SIZE": "アップロード上限サイズは {{maxFileSize}} です", + "DATE": "YYYY年MM月DD日 hh時mm分", + "ERROR_UPLOAD_ATTACHMENT": "'{{fileName}}'のアップロードに失敗. {{errorMessage}}", + "TITLE_LIGHTBOX_DELETE_ATTACHMENT": "添付ファイルの削除...", + "MSG_LIGHTBOX_DELETE_ATTACHMENT": "添付ファイル '{{fileName}}'", + "ERROR_DELETE_ATTACHMENT": " 削除に失敗: {{errorMessage}}", + "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) はウンパルンパたちには重すぎます。({{maxFileSize}})より少ないもので試してください。" + }, + "PAGINATION": { + "PREVIOUS": "前へ", + "NEXT": "次へ" + }, + "ADMIN": { + "COMMON": { + "TITLE_ACTION_EDIT_VALUE": "値を編集", + "TITLE_ACTION_DELETE_VALUE": "値を削除", + "TITLE_ACTION_DELETE_TAG": "タグを削除" + }, + "HELP": "手助けが必要な場合はサポートページをチェックしてください。", + "PROJECT_DEFAULT_VALUES": { + "TITLE": "初期値設定", + "SUBTITLE": "プルダウン項目の初期値を設定してください。" + }, + "MEMBERSHIPS": { + "TITLE": "メンバー管理", + "PAGE_TITLE": "メンバーシップ - {{projectName}}", + "ADD_BUTTON": "+ 新規メンバー", + "ADD_BUTTON_TITLE": "新規メンバーを追加", + "LIMIT_USERS_WARNING_MESSAGE_FOR_ADMIN": "このプロジェクトは許可されている最大メンバー数({{members}}名)に達しました。", + "LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "このプロジェクトは許可されている最大メンバー数({{members}}名)に達しました。上限を増やしたい場合は管理者にお問い合わせください。" + }, + "PROJECT_EXPORT": { + "TITLE": "エクスポート", + "SUBTITLE": "エクスポートの実行によりプロジェクトのバックアップを作成することができます。
また、バックアップをベースとして新しいプロジェクトを作成することも可能です。", + "EXPORT_BUTTON": "エクスポート", + "EXPORT_BUTTON_TITLE": "プロジェクトをエクスポート", + "LOADING_TITLE": "ダンプファイルを生成中", + "DUMP_READY": "ダンプファイルの用意が出来ました!", + "LOADING_MESSAGE": "このページを閉じないでください。", + "ASYNC_MESSAGE": "準備が出来たらメールで通知します。", + "SYNC_MESSAGE": "ダウンロードが自動で開始されない場合はこちらをクリックしてください。", + "ERROR": "ウンパルンパたちはダンプファイルの生成に手こずっているようです。もう一度お試しください。", + "ERROR_BUSY": "すみません、ウンパルンパたちはとても忙しいようです。しばらくしてからまたお試しください。" + }, + "MODULES": { + "TITLE": "モジュール", + "EPICS": "エピック", + "EPICS_DESCRIPTION": "あなたのプロジェクトの最も戦略的な部分を視覚化し、管理する", + "BACKLOG": "バックログ", + "BACKLOG_DESCRIPTION": "ユーザーストーリーが適切にメンテナンスされるよう管理し、優先順位に基づく作業を行うためのビュー", + "NUMBER_SPRINTS": "予測されるスプリント数", + "NUMBER_SPRINTS_HELP": "0に設定した場合、無制限となります", + "NUMBER_US_POINTS": "予測されるストーリーポイントの合計", + "NUMBER_US_POINTS_HELP": "0に設定した場合、無制限となります", + "KANBAN": "かんばん", + "KANBAN_DESCRIPTION": "このかんばんを利用して、無駄のない方法でプロジェクトを整理しましょう。", + "ISSUES": "課題", + "ISSUES_DESCRIPTION": "プロジェクトのバグ追跡、質問、機能改善に関する議論などが行えるようになります。", + "WIKI": "Wiki", + "WIKI_DESCRIPTION": "他のメンバーと協力してコンテンツを編集することができます。
プロジェクトの情報を文書化するのにぴったりです。", + "MEETUP": "会議", + "MEETUP_DESCRIPTION": "あなたが利用しているビデオ会議システムを選択してください。", + "SELECT_VIDEOCONFERENCE": "ビデオ会議システムを選択", + "SALT_CHAT_ROOM": "チャットルーム名に接頭辞を追加", + "JITSI_CHAT_ROOM": "Jitsi", + "APPEARIN_CHAT_ROOM": "AppearIn", + "TALKY_CHAT_ROOM": "Talky", + "CUSTOM_CHAT_ROOM": "カスタム", + "URL_CHAT_ROOM": "チャットルームのURL" + }, + "PROJECT_PROFILE": { + "PAGE_TITLE": "{{sectionName}} - プロジェクトプロフィール - {{projectName}}", + "PROJECT_DETAILS": "プロジェクト詳細", + "PROJECT_NAME": "プロジェクト名", + "TAGS": "タグ", + "DESCRIPTION": "説明", + "RECRUITING": "プロジェクトメンバーを探していますか?", + "RECRUITING_MESSAGE": "どんな人を探していますか?", + "RECRUITING_PLACEHOLDER": "探している人のプロフィールを記載してください", + "FEEDBACK": "Taigaユーザーからのフィードバックを受け取りますか?", + "PUBLIC_PROJECT": "パブリック プロジェクト", + "PRIVATE_PROJECT": "非公開プロジェクト", + "PRIVATE_OR_PUBLIC": "パブリックプロジェクトとプライベートプロジェクトの違いは何ですか?", + "DELETE": "このプロジェクトを削除", + "CHANGE_LOGO": "ロゴを変更", + "ACTION_USE_DEFAULT_LOGO": "デフォルトのイメージを使用する", + "MAX_PRIVATE_PROJECTS": "あなたの現在のプランで許可されている非公開プロジェクトの上限数に達しました。", + "MAX_PRIVATE_PROJECTS_MEMBERS": "非公開プロジェクトの最大メンバー数を超えました。", + "MAX_PUBLIC_PROJECTS": "あなたの現在のプランで許可されている公開プロジェクトの上限数に達しました。", + "MAX_PUBLIC_PROJECTS_MEMBERS": "The project exceeds your maximum number of members for public projects", + "PROJECT_OWNER": "プロジェクトオーナー", + "REQUEST_OWNERSHIP": "オーナーシップを要求", + "REQUEST_OWNERSHIP_CONFIRMATION_TITLE": "新しいプロジェクトのオーナーになりますか?", + "REQUEST_OWNERSHIP_DESC": "Request that current project owner {{name}} transfer ownership of this project to you.", + "REQUEST_OWNERSHIP_BUTTON": "リクエスト", + "REQUEST_OWNERSHIP_SUCCESS": "プロジェクトオーナーに通知します", + "CHANGE_OWNER": "オーナーを変更", + "CHANGE_OWNER_SUCCESS_TITLE": "あなたのリクエストが送信されました!", + "CHANGE_OWNER_SUCCESS_DESC": "We will notify you by email if the project ownership request is accepted or declined" + }, + "REPORTS": { + "TITLE": "レポート", + "SUBTITLE": "オリジナルのレポートを作成するためにプロジェクトのデータをCSVで出力することができます。", + "DESCRIPTION": "CSVのダウンロードボタンまたは生成されたURLへアクセスしてファイルを入手し、お好みのテキストエディタや表計算ソフトで開いてください。データの可視化や分析を簡単に行うことが可能です。", + "HELP": "このファイルをどうやって表計算ソフトで活用すればいいですか?", + "REGENERATE_TITLE": "URLが変更されます", + "REGENERATE_SUBTITLE": "CSV出力用のURLを変更しようとしています。前回のURLは無効化されます。よろしいですか?" + }, + "CSV": { + "SECTION_TITLE_EPIC": "エピックレポート", + "SECTION_TITLE_US": "ユーザーストーリーを出力する", + "SECTION_TITLE_TASK": "タスクを出力する", + "SECTION_TITLE_ISSUE": "課題を出力する", + "DOWNLOAD": "CSVのダウンロード", + "URL_FIELD_PLACEHOLDER": "CSV出力用のURLを作成してください", + "TITLE_REGENERATE_URL": "CSV出力用のURLを作成", + "ACTION_GENERATE_URL": "URL を生成", + "ACTION_REGENERATE": "再作成" + }, + "CUSTOM_FIELDS": { + "TITLE": "カスタムフィールド", + "SUBTITLE": "ユーザーストーリー、タスク、課題のためのカスタムフィールドを明記してください。", + "EPIC_DESCRIPTION": "エピックカスタムフィールド", + "EPIC_ADD": "複数のエピックにカスタムフィールドを追加", + "US_DESCRIPTION": "ユーザーストーリーのカスタムフィールド", + "US_ADD": "ユーザーストーリーにカスタムフィールドを追加", + "TASK_DESCRIPTION": "タスクカスタムフィールド", + "TASK_ADD": "タスクにカスタムフィールドを追加", + "ISSUE_DESCRIPTION": "課題のカスタムフィールド", + "ISSUE_ADD": "課題にカスタムフィールドを追加", + "FIELD_TYPE_TEXT": "テキスト", + "FIELD_TYPE_RICHTEXT": "リッチテキスト", + "FIELD_TYPE_MULTI": "マルチライン", + "FIELD_TYPE_DATE": "日時", + "FIELD_TYPE_URL": "Url" + }, + "PROJECT_VALUES": { + "PAGE_TITLE": "{{sectionName}} - Project values - {{projectName}}", + "REPLACEMENT": "この値を持つすべてのアイテムはこちらに変更されます:", + "ERROR_DELETE_ALL": "すべての値を削除することはできません。" + }, + "PROJECT_VALUES_POINTS": { + "TITLE": "ポイント", + "SUBTITLE": "予測されるユーザーストーリーのポイントを定義することができます。", + "US_TITLE": "ユーザーストーリーのポイント", + "ACTION_ADD": "新規ポイントを追加" + }, + "PROJECT_VALUES_PRIORITIES": { + "TITLE": "優先度", + "SUBTITLE": "課題の優先度を定義することができます。", + "ISSUE_TITLE": "課題の優先度", + "ACTION_ADD": "新しい優先度を追加" + }, + "PROJECT_VALUES_SEVERITIES": { + "TITLE": "深刻度", + "SUBTITLE": "課題の深刻度を定義することができます。", + "ISSUE_TITLE": "課題の深刻度", + "ACTION_ADD": "新しい深刻度を追加" + }, + "PROJECT_VALUES_STATUS": { + "TITLE": "Statuses", + "SUBTITLE": "ユーザーストーリー、タスク、課題のステータスを定義することができます。", + "EPIC_TITLE": "エピックステータス", + "US_TITLE": "ユーザーストーリーステータス", + "TASK_TITLE": "タスクのステータス", + "ISSUE_TITLE": "課題のステータス" + }, + "PROJECT_VALUES_TYPES": { + "TITLE": "タイプ", + "SUBTITLE": "課題のタイプを定義することができます。", + "ISSUE_TITLE": "課題のタイプ", + "ACTION_ADD": "新しい {{objName}} を追加" + }, + "PROJECT_VALUES_TAGS": { + "TITLE": "タグ", + "SUBTITLE": "タグの色を編集", + "EMPTY": "タグは現在ありません。", + "EMPTY_SEARCH": "検索条件に当てはまるものはありませんでした。", + "ACTION_ADD": "タグを追加", + "NEW_TAG": "新規タグ", + "MIXING_HELP_TEXT": "マージしたいタグを選択してください。", + "MIXING_MERGE": "タグを結合", + "SELECTED": "Selected" + }, + "ROLES": { + "PAGE_TITLE": "役割 - {{projectName}}", + "WARNING_NO_ROLE": "Be careful, no role in your project will be able to estimate the point value for user stories", + "HELP_ROLE_ENABLED": "この設定を有効にするとメンバーがこの役割にアサインされた際、ユーザーストーリーのポイントに反映されます。", + "DISABLE_COMPUTABLE_ALERT_TITLE": "Are you sure you want to disable this role estimations?", + "DISABLE_COMPUTABLE_ALERT_SUBTITLE": "If you disable estimation permissions for role {{roleName}} all previous estimations made by this role will be removed", + "COUNT_MEMBERS": "{{ role.members_count }} members with this role", + "TITLE_DELETE_ROLE": "役割を削除", + "REPLACEMENT_ROLE": "All the users with this role will be moved to", + "WARNING_DELETE_ROLE": "Be careful! All role estimations will be removed", + "ERROR_DELETE_ALL": "すべての値を削除することはできません", + "EXTERNAL_USER": "外部ユーザー" + }, + "THIRD_PARTIES": { + "SECRET_KEY": "シークレットキー", + "PAYLOAD_URL": "Payload URL", + "VALID_IPS": "Valid origin IPs (separated by ,)" + }, + "BITBUCKET": { + "SECTION_NAME": "Bitbucket", + "PAGE_TITLE": "Bitbucket - {{projectName}}", + "INFO_VERIFYING_IP": "Bitbucket requests are not signed so the best way of verifying the origin is by IP. If the field is empty there will be no IP validation." + }, + "GITLAB": { + "SECTION_NAME": "Gitlab", + "PAGE_TITLE": "Gitlab - {{projectName}}", + "INFO_VERIFYING_IP": "Gitlab requests are not signed so the best way of verifying the origin is by IP. If the field is empty there will be no IP validation." + }, + "GITHUB": { + "SECTION_NAME": "Github", + "PAGE_TITLE": "GitHub - {{projectName}}" + }, + "GOGS": { + "SECTION_NAME": "Gogs", + "PAGE_TITLE": "Gogs - {{projectName}}" + }, + "WEBHOOKS": { + "PAGE_TITLE": "Webhooks - {{projectName}}", + "SECTION_NAME": "Webhooks", + "ADD_NEW": "新規Webhookを追加", + "TYPE_NAME": "サービス名を入力", + "TYPE_PAYLOAD_URL": "サービスペイロードのURLを入力", + "TYPE_SERVICE_SECRET": "サービスのシークレットキーを入力", + "SAVE": "Webhookを保存", + "CANCEL": "Webhookをキャンセル", + "SHOW_HISTORY": "(履歴を表示)", + "TEST": "Webhookをテスト", + "EDIT": "Webhookを編集", + "DELETE": "Webhookを削除", + "REQUEST": "リクエスト", + "RESEND_REQUEST": "リクエストを再送", + "HEADERS": "ヘッダー", + "PAYLOAD": "Payload", + "RESPONSE": "レスポンス", + "DATE": "YYYY年MM月DD日 hh時mm分ss秒", + "ACTION_HIDE_HISTORY": "(履歴を非表示)", + "ACTION_HIDE_HISTORY_TITLE": "履歴を非表示", + "ACTION_SHOW_HISTORY": "(履歴を表示)", + "ACTION_SHOW_HISTORY_TITLE": "履歴を表示", + "WEBHOOK_NAME": "Webhook '{{name}}'" + }, + "CUSTOM_ATTRIBUTES": { + "PAGE_TITLE": "{{sectionName}} - カスタム属性 - {{projectName}}", + "ADD": "カスタムフィールドを追加", + "EDIT": "カスタムフィールドを編集", + "DELETE": "カスタムフィールドを削除", + "SAVE_TITLE": "カスタムフィールドを保存", + "CANCEL_TITLE": "作成するのをやめる", + "SET_FIELD_NAME": "カスタムフィールド名を設定", + "SET_FIELD_DESCRIPTION": "カスタムフィールドの説明を設定", + "FIELD_TYPE_DEFAULT": "-- 1つ選択 --", + "ACTION_UPDATE": "カスタムフィールドを更新", + "ACTION_CANCEL_EDITION": "編集をキャンセル" + }, + "MEMBERSHIP": { + "COLUMN_MEMBER": "メンバー", + "COLUMN_ADMIN": "管理", + "COLUMN_ROLE": "役割", + "COLUMN_STATUS": "ステータス", + "STATUS_ACTIVE": "有効", + "STATUS_PENDING": "Pending", + "DELETE_MEMBER": "メンバーを削除", + "RESEND": "再送信", + "SUCCESS_SEND_INVITATION": "招待メールを '{{email}}' へもう一度送りました。", + "SUCCESS_DELETE": "{{message}} を削除しました", + "ERROR_DELETE": "{{message}} を削除できませんでした", + "DEFAULT_DELETE_MESSAGE": "{{email}} への招待メール" + }, + "DEFAULT_VALUES": { + "LABEL_EPIC_STATUS": "エピックステータスの初期値", + "LABEL_US_STATUS": "ユーザーストーリーステータスの初期値", + "LABEL_POINTS": "ポイントの初期値", + "LABEL_TASK_STATUS": "タスクステータスの初期値", + "LABEL_ISSUE_TYPE": "課題タイプの初期値", + "LABEL_ISSUE_STATUS": "課題ステータスの初期値", + "LABEL_PRIORITY": "優先度の初期値", + "LABEL_SEVERITY": "深刻度の初期値" + }, + "STATUS": { + "PLACEHOLDER_WRITE_STATUS_NAME": "新しいステータス名を記入" + }, + "TYPES": { + "PLACEHOLDER_WRITE_NAME": "新しいエレメント名を記入" + }, + "US_STATUS": { + "ACTION_ADD_STATUS": "ステータスを追加", + "IS_ARCHIVED_COLUMN": "アーカイブ", + "IS_CLOSED_COLUMN": "終了", + "WIP_LIMIT_COLUMN": "WIP制限", + "PLACEHOLDER_WRITE_NAME": "新しいステータス名を記入" + }, + "MENU": { + "PROJECT": "プロジェクト", + "ATTRIBUTES": "属性", + "MEMBERS": "メンバー", + "PERMISSIONS": "権限", + "INTEGRATIONS": "インテグレーション" + }, + "SUBMENU_PROJECT_VALUES": { + "STATUS": "ステータス", + "POINTS": "ポイント", + "PRIORITIES": "優先度", + "SEVERITIES": "深刻度", + "TYPES": "タイプ", + "CUSTOM_FIELDS": "カスタムフィールド", + "TAGS": "タグ" + }, + "SUBMENU_ROLES": { + "TITLE": "役割", + "ACTION_NEW_ROLE": "+ 新規役割", + "TITLE_ACTION_NEW_ROLE": "新しい役割を追加" + }, + "PROJECT_TRANSFER": { + "DO_YOU_ACCEPT_PROJECT_OWNERNSHIP": "新しいプロジェクトオーナーとなりますか?", + "PRIVATE": "プライベート", + "ACCEPTED_PROJECT_OWNERNSHIP": "おめでとうございます!あなたが新しいプロジェクトオーナーです。", + "REJECTED_PROJECT_OWNERNSHIP": "OK. We'll contact the current project owner", + "ACCEPT": "はい", + "REJECT": "却下", + "PROPOSE_OWNERSHIP": "プロジェクト {{project}} の現在のプロジェクトオーナー {{owner}} が、あなたに新しいプロジェクトオーナーになるようリクエストしています。", + "ADD_COMMENT": "プロジェクトオーナーにコメントしますか?", + "UNLIMITED_PROJECTS": "無制限", + "OWNER_MESSAGE": { + "PRIVATE": "あなたが持てる非公開プロジェクトは最大{{maxProjects}}個までです。現在{{currentProjects}}個持っています。", + "PUBLIC": "あなたが持てる公開プロジェクトは最大{{maxProjects}}個までです。現在{{currentProjects}}個持っています。" + }, + "CANT_BE_OWNED": "この種類のプロジェクトのオーナーには現在なれません。このプロジェクトのオーナーになりたい場合は管理者に問い合わせて、プロジェクトオーナー権限を変更してもらってください。" + } + }, + "USER": { + "PROFILE": { + "PAGE_TITLE": "{{userFullName}} (@{{userUsername}})", + "EDIT": "プロフィールを編集", + "CLOSED_US": "完了したユーザーストーリー", + "PROJECTS": "プロジェクト", + "PROJECTS_EMPTY": "{{username}} はまだプロジェクトに参加していません", + "CONTACTS": "連絡先", + "CONTACTS_EMPTY": "{{username}} はまだ連絡先を持っていません", + "CURRENT_USER_CONTACTS_EMPTY": "あなたへのコンタクトはまだありません。", + "CURRENT_USER_CONTACTS_EMPTY_EXPLAIN": "Taigaで一緒に仕事をしたメンバーは自動的に連絡先へ追加されます", + "TABS": { + "ACTIVITY_TAB": "タイムライン", + "ACTIVITY_TAB_TITLE": "このユーザのすべてのアクティビティーを表示する", + "PROJECTS_TAB": "プロジェクト", + "PROJECTS_TAB_TITLE": "ユーザーが参加しているプロジェクト", + "LIKES_TAB": "いいね", + "LIKES_TAB_TITLE": "このユーザーが「いいね」と評価したすべての内容を表示", + "VOTES_TAB": "投票", + "VOTES_TAB_TITLE": "このユーザーが「賛成」したすべての内容を表示", + "WATCHED_TAB": "フォロー", + "WATCHED_TAB_TITLE": "このユーザーが「フォロー」したすべての内容を表示", + "CONTACTS_TAB": "連絡先", + "CONTACTS_TAB_TITLE": "このユーザーが「コンタクト」したすべての内容を表示" + } + }, + "PROFILE_SIDEBAR": { + "TITLE": "プロフィール", + "DESCRIPTION": "すべてのメンバーはあなたが完了させた作業、あなたが今取り組んでいる作業を確認することができます。自己紹介を追記してあなたについてもっと知ってもらいましょう!", + "ADD_INFO": "編集する" + }, + "PROFILE_FAVS": { + "FILTER_INPUT_PLACEHOLDER": "入力してください", + "FILTER_TYPE_ALL": "すべて", + "FILTER_TYPE_ALL_TITLE": "すべてを表示", + "FILTER_TYPE_PROJECTS": "プロジェクト", + "FILTER_TYPE_PROJECTS_TITLE": "プロジェクトのみ表示", + "FILTER_TYPE_EPICS": "エピック", + "FILTER_TYPE_EPICS_TITLE": "エピックのみ表示", + "FILTER_TYPE_USER_STORIES": "ストーリー", + "FILTER_TYPE_USER_STORIES_TITLE": "ユーザーストーリーを表示", + "FILTER_TYPE_TASKS": "タスク", + "FILTER_TYPE_TASKS_TITLE": "タスクのみ表示", + "FILTER_TYPE_ISSUES": "課題", + "FILTER_TYPE_ISSUES_TITLE": "課題のみ表示", + "EMPTY_TITLE": "表示するものがありません。" + } + }, + "PROJECT": { + "PAGE_TITLE": "{{projectName}}", + "HELP": "最も良く使うプロジェクトがトップになるように順序を入れ替えてみましょう。
トップ10のプロジェクトが上のナビゲーションバーのプロジェクトリストに現れます。", + "PRIVATE": "プライベート プロジェクト", + "LOOKING_FOR_PEOPLE": "プロジェクトはメンバーを探しています", + "FANS_COUNTER_TITLE": "{total, plural, one{one fan} other{# 人のファン}}", + "WATCHERS_COUNTER_TITLE": "{total, plural, one{one watcher} other{# 人がフォロー中}}", + "MEMBERS_COUNTER_TITLE": "{total, plural, one{one member} other{# 人のメンバー}}", + "BLOCKED_PROJECT": { + "BLOCKED": "ブロックされたプロジェクト", + "THIS_PROJECT_IS_BLOCKED": "このプロジェクトは一時的にブロックされています。", + "TO_UNBLOCK_CONTACT_THE_ADMIN_STAFF": "プロジェクトのブロックを解除したい場合は管理者にお問い合わせください。" + }, + "SECTION": { + "SEARCH": "検索", + "TIMELINE": "タイムライン", + "BACKLOG": "バックログ", + "KANBAN": "かんばん", + "ISSUES": "課題", + "WIKI": "Wiki", + "TEAM": "チーム", + "MEETUP": "会議", + "ADMIN": "管理" + }, + "NAVIGATION": { + "ACTION_CREATE_PROJECT": "プロジェクトを作成", + "MANAGE_PROJECTS": "プロジェクト管理", + "TITLE_CREATE_PROJECT": "プロジェクトを作成", + "HELP_TITLE": "Taiga サポートページ", + "HELP": "ヘルプ", + "HOMEPAGE": "ホームページ", + "FEEDBACK_TITLE": "フィードバックを送る", + "FEEDBACK": "フィードバック", + "NOTIFICATIONS_TITLE": "通知設定を編集", + "NOTIFICATIONS": "通知", + "VIEW_PROFILE_TITLE": "プロフィールを表示", + "VIEW_PROFILE": "プロフィールを表示", + "EDIT_PROFILE_TITLE": "プロフィールを編集", + "EDIT_PROFILE": "プロフィールを編集", + "CHANGE_PASSWORD_TITLE": "パスワード変更", + "CHANGE_PASSWORD": "パスワード変更", + "DASHBOARD_TITLE": "ダッシュボード", + "DISCOVER_TITLE": "トレンドプロジェクトを探す", + "DISCOVER": "探す" + }, + "LIKE_BUTTON": { + "LIKE": "いいね", + "LIKED": "いいね", + "UNLIKE": "「いいね」を取り消す", + "BUTTON_TITLE": "Like or unlike this project", + "COUNTER_TITLE": "{total, plural, one{one fan} other{# 人のファン}}" + }, + "WATCH_BUTTON": { + "BUTTON_TITLE": "このプロジェクトをフォローして通知ポリシーを設定してください", + "WATCH": "フォロー", + "WATCHING": "フォロー中", + "COUNTER_TITLE": "{total, plural, one{one watcher} other{# 人がフォロー中}}", + "OPTIONS": { + "NOTIFY_ALL": "すべての通知を受信する", + "NOTIFY_ALL_TITLE": "このプロジェクトのすべての通知を受信する", + "NOTIFY_INVOLVED": "関連するものだけ", + "NOTIFY_INVOLVED_TITLE": "Recive notificacions only when you are involved", + "UNWATCH": "フォローをやめる", + "UNWATCH_TITLE": "プロジェクトのフォローをやめる" + } + }, + "CONTACT_BUTTON": { + "CONTACT_TITLE": "Contact the project team", + "CONTACT_BUTTON": "Contact the project" + }, + "CREATE": { + "TITLE": "プロジェクトを作成", + "CHOOSE_TEMPLATE": "Which template fits your project better?", + "TEMPLATE_SCRUM": "スクラム", + "TEMPLATE_SCRUM_DESC": "Prioritize and solve your tasks in short time cycles.", + "TEMPLATE_SCRUM_LONGDESC": "Scrum is an iterative and incremental agile software development methodology for managing product development.\nThe product backlog is what will ultimately be delivered, ordered into the sequence in which it should be delivered. Product Backlogs are broken into manageable, executable chunks named sprints. Every certain amount of time the team initiates a new sprint and commits to deliver a certain number of user stories from the backlog, in accordance with their skills, abilities and resources. The project advances as the backlog becomes depleted.", + "TEMPLATE_KANBAN": "かんばん", + "TEMPLATE_KANBAN_DESC": "Keep a constant workflow on independent tasks", + "TEMPLATE_KANBAN_LONGDESC": "The Kanban methodology is used to divide project development (any sort of project) into stages.\nA kanban card is like an index card or post-it note that details every task (or user story) in a project that needs to be completed. The Kanban board is used to move each card from one state of completion to the next and in so doing, helps track progress.", + "DUPLICATE": "Duplicate project", + "DUPLICATE_DESC": "Start clean and keep your configuration", + "IMPORT": "プロジェクトをインポート", + "IMPORT_DESC": "Import your project from multiple platforms into Taiga", + "INVITE": "Invite to the project", + "SOLO_PROJECT": "You'll be alone in this project", + "INVITE_LATER": "(You'll be able to invite more members later)", + "BACK": "バックエンド", + "MAX_PRIVATE_PROJECTS": "Unfortunately, You've reached the maximum number of private projects.\nIf you would like to increase the current limit please contact the administrator.", + "MAX_PUBLIC_PROJECTS": "Unfortunately, You've reached the maximum number of public projects.\nIf you would like to increase the current limit please contact the administrator.", + "PUBLIC_PROJECT": "パブリック プロジェクト", + "PRIVATE_PROJECT": "プライベート プロジェクト" + }, + "COMMON": { + "DETAILS": "New project details", + "PROJECT_TITLE": "プロジェクト名", + "PROJECT_DESCRIPTION": "Project Description" + }, + "DUPLICATE": { + "TITLE": "Duplicate Project", + "DESCRIPTION": "Start clean and keep your configuration", + "SELECT_PLACEHOLDER": "Choose an existing project to duplicate" + }, + "IMPORT": { + "TITLE": "Import Project", + "DESCRIPTION": "Import your project from multiple platforms into Taiga", + "ASYNC_IN_PROGRESS_TITLE": "ウンパルンパたちがあなたのプロジェクトをインポートしています。", + "ASYNC_IN_PROGRESS_MESSAGE": "この処理には時間がかかります。
準備が出来たらメールで通知します。", + "UPLOAD_IN_PROGRESS_MESSAGE": "{{totalSize}} 中 {{uploadedSize}} アップロード済み", + "ERROR": "ウンパルンパたちはダンプファイルのインポートに手こずっているようです。もう一度お試しください。", + "ERROR_TOO_MANY_REQUEST": "すみません、ウンパルンパたちはとても忙しいようです。しばらくしてからまたお試しください。", + "ERROR_MESSAGE": "ウンパルンパたちはダンプファイルのインポートに手こずっているようです。  \n{{error_message}}", + "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) はウンパルンパたちには重すぎます。({{maxFileSize}})より少ないもので試してください。", + "SYNC_SUCCESS": "プロジェクトのインポートに成功しました", + "IMPORT": "Import", + "WHO_IS": "Their tasks will be assigned to ...", + "WRITE_EMAIL": "Or if you want, write the email that this user uses in Taiga", + "SEARCH_CONTACT": "Or if you want, search in your contacts", + "WRITE_EMAIL_LABEL": "Write the email that this user uses in Taiga", + "ACCEEDE": "Acceede", + "PROJECT_MEMBERS": "プロジェクトメンバー", + "PROCESS_DESCRIPTION": "Tell us who from Taiga you want to assign the tasks of {{platform}}", + "MATCH": "Is {{user_external}} the same person as {{user_internal}}?", + "CHOOSE": "Select user", + "LINKS": "Links with {{platform}}", + "LINKS_DESCRIPTION": "Do you want to keep the link of each item with the original {{platform}} card?", + "WARNING_MAIL_USER": "Note that if the user does not have a Taiga account we will not be able to assign the tasks to him.", + "ASSIGN": "アサイン", + "PROJECT_SELECTOR": { + "NO_RESULTS": "検索条件に当てはまるものはありませんでした。", + "ACTION_SEARCH": "検索", + "ACTION_BACK": "バックエンド" + }, + "PROJECT_RESTRICTIONS": { + "PROJECT_MEMBERS_DESC_PRIVATE": "The project you are trying to import has {{members}} members including you, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per private project. If you would like to increase that limit please contact the administrator.", + "PROJECT_MEMBERS_DESC_PUBLIC": "The project you are trying to import has {{members}} members including you, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per public project. If you would like to increase that limit please contact the administrator.", + "ACCOUNT_ALLOW_MEMBERS": "Your account only allows {{members}} members", + "PRIVATE_PROJECTS_SPACE": { + "TITLE": "現在のプランではこれ以上の非公開プロジェクトは許可されていません。", + "DESC": "インポートしようとしているプロジェクトは非公開プロジェクトです。現在のプランではこれ以上の非公開プロジェクトは許可されていません。" + }, + "PUBLIC_PROJECTS_SPACE": { + "TITLE": "現在のプランではこれ以上の公開プロジェクトは許可されていません。", + "DESC": "インポートしようとしているプロジェクトは公開プロジェクトです。現在のプランではこれ以上の公開プロジェクトは許可されていません。" + }, + "PRIVATE_PROJECTS_MEMBERS": { + "TITLE": "現在のプランでは非公開プロジェクトごとに最大{{max_memberships}}名のメンバーが許可されています。" + }, + "PUBLIC_PROJECTS_MEMBERS": { + "TITLE": "現在のプランでは公開プロジェクトごとに最大{{max_memberships}}名のメンバーが許可されています。" + }, + "PRIVATE_PROJECTS_SPACE_MEMBERS": { + "TITLE": "現在のプランではこれ以上の非公開プロジェクトの作成や、一つの非公開プロジェクトに{{max_memberships}}名を超えるメンバーを追加することはできません。", + "DESC": "インポートしようとしているのは非公開プロジェクトで{{members}}名のメンバーがいます。" + }, + "PUBLIC_PROJECTS_SPACE_MEMBERS": { + "TITLE": "現在のプランではこれ以上の公開プロジェクトの作成や、一つの公開プロジェクトに{{max_memberships}}名を超えるメンバーを追加することはできません。", + "DESC": "インポートしようとしているのは公開プロジェクトで{{members}}名以上のメンバーがいます。" + } + }, + "IN_PROGRESS": { + "TITLE": "プロジェクトをインポート中", + "DESCRIPTION": "このプロセスには時間がかかります。ウィンドウを開いたままにしていてください。" + }, + "WARNING": { + "TITLE": "Some taks will be unassigned", + "DESCRIPTION": "There are still unidentified people. The cards assigned to these people will remain unassigned. Check all the contacts to not lose that information.", + "CHECK": "Check contacts" + }, + "TAIGA": { + "SELECTOR": "Import your Taiga project" + }, + "TRELLO": { + "SELECTOR": "Import your Trello boards into Taiga", + "CHOOSE_PROJECT": "Choose board that you want to import", + "NO_PROJECTS": "It seems you have no boards in Trello" + }, + "GITHUB": { + "SELECTOR": "Import your GitHub project issues", + "CHOOSE_PROJECT": "Find the project you want to import", + "NO_PROJECTS": "It seems you have no porjects in GitHub", + "HOW_DO_YOU_WANT_TO_IMPORT": "How do you want to import your issues into Taiga?", + "KANBAN_PROJECT": "As user stories in a kanban project", + "KANBAN_PROJECT_DESCRIPTION": "After that you can enable scrum with backlog.", + "SCRUM_PROJECT": "As user stories in a scrum project", + "SCRUM_PROJECT_DESCRIPTION": "After that you can enable kanban mode.", + "ISSUES_PROJECT": "As issues", + "ISSUES_PROJECT_DESCRIPTION": "You will not be able to use your issues in kanban or scrum mode. You will be able to enable kanban or scrum for new user stories" + }, + "ASANA": { + "SELECTOR": "Import your Asana project and choose how to manage it", + "CHOOSE_PROJECT": "Choose project that you want to import", + "NO_PROJECTS": "It seems you have no porjects in Asana", + "KANBAN_PROJECT": "かんばん", + "SCRUM_PROJECT": "スクラム", + "CREATE_AS_SCRUM_DESCRIPTION": "The tasks and sub-tasks of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_KANBAN_DESCRIPTION": "The tasks and sub-tasks of your project will be created as Taiga user stories and tasks." + }, + "JIRA": { + "SELECTOR": "Import your Jira project and choose how to manage it", + "CHOOSE_PROJECT": "Choose project or board that you want to import", + "NO_PROJECTS": "It seems you have no porjects or boards in Jira", + "URL": "Your Jira URL", + "KANBAN_PROJECT": "かんばん", + "SCRUM_PROJECT": "スクラム", + "ISSUES_PROJECT": "課題", + "CREATE_AS_SCRUM_DESCRIPTION": "The issues and sub-issues of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_KANBAN_DESCRIPTION": "The issues and sub-issues of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_ISSUES_DESCRIPTION": "What do you want to do with sub-issues from the Jira project? (Taiga doesn't allow sub-issues)", + "CREATE_NEW_ISSUES": "Convert sub-issues to new Taiga issues", + "NOT_CREATE_NEW_ISSUES": "Do not import sub-issues" + } + } + }, + "LIGHTBOX": { + "DELETE_ACCOUNT": { + "CONFIRM": "本当にあなたのTaigaアカウントを削除してもよろしいですか?", + "CANCEL": "設定に戻る", + "ACCEPT": "アカウントを削除する", + "BLOCK_PROJECT": "あなたが所有しているプロジェクトは、あなたのアカウント削除後にブロックされることを覚えておいてください。あなたのアカウントが削除されてプロジェクトがブロックされる前にプロジェクトの所有権を他のメンバーに譲渡してください。" + }, + "DELETE_PROJECT": { + "TITLE": "プロジェクトを削除", + "QUESTION": "本当にこのプロジェクトを削除していいですか?", + "SUBTITLE": "プロジェクトのすべてのデータ (ユーザーストーリー、タスク、課題、スプリント、Wikiページ) が失われます! :-(", + "CONFIRM": "はい、問題ありません" + }, + "ASSIGNED_TO": { + "SELECT": "アサインする", + "SEARCH": "ユーザーを検索" + }, + "ADD_MEMBER": { + "TITLE": "新しいメンバー", + "PLACEHOLDER": "ユーザーをフィルターまたは招待メールを書く", + "ADD_EMAIL": "メールを追加", + "REMOVE": "削除", + "INVITE": "招待", + "CHOOSE_ROLE": "役割の選択", + "PLACEHOLDER_INVITATION_TEXT": "(任意) 招待する際のメッセージを追加できます。新メンバーに素敵な言葉を贈りましょう ;-)", + "HELP_TEXT": "ユーザーが既にTaigaに登録されている場合、自動的に追加されます。そうでない場合は招待状が送信されます。" + }, + "CREATE_ISSUE": { + "TITLE": "課題を追加" + }, + "FEEDBACK": { + "TITLE": "我々に教えてください...", + "COMMENT": "...バグ、提案、何かクールなことやTaigaを利用していて発生した悪夢など(英語で記載してください)", + "ACTION_SEND": "フィードバックを送る" + }, + "SEARCH": { + "TITLE": "検索", + "PLACEHOLDER_SEARCH": "何をお探しですか?" + }, + "ADD_EDIT_SPRINT": { + "TITLE": "新しいスプリント", + "PLACEHOLDER_SPRINT_NAME": "スプリント名", + "PLACEHOLDER_SPRINT_START": "見積もり開始", + "PLACEHOLDER_SPRINT_END": "見積もり終了", + "ACTION_DELETE_SPRINT": "このスプリントを削除しますか?", + "TITLE_ACTION_DELETE_SPRINT": "スプリントを削除", + "LAST_SPRINT_NAME": "最後のスプリントは {{lastSprint}}でした ;-) " + }, + "CREATE_EDIT_TASK": { + "TITLE": "新しいタスク", + "PLACEHOLDER_SUBJECT": "タスク名", + "PLACEHOLDER_STATUS": "タスクステータス", + "OPTION_UNASSIGNED": "未アサイン", + "PLACEHOLDER_SHORT_DESCRIPTION": "要約を入力", + "ACTION_EDIT": "タスクを編集" + }, + "CREATE_EDIT_US": { + "TITLE": "新規 US", + "PLACEHOLDER_DESCRIPTION": "このユーザーストーリーを他の人が理解できるように説明を加えてください", + "NEW_US": "新しいユーザーストーリー", + "EDIT_US": "ユーザーストーリーを編集" + }, + "DELETE_SPRINT": { + "TITLE": "スプリントを削除" + }, + "CREATE_MEMBER": { + "PLACEHOLDER_INVITATION_TEXT": "(任意) 招待する際のメッセージを追加できます。新メンバーに素敵な言葉を贈りましょう ;-)", + "PLACEHOLDER_TYPE_EMAIL": "メールアドレスを入力", + "LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "このプロジェクトで許可されている最大メンバー数{{maxMembers}}名に達しようとしています。上限を増やしたい場合は管理者にお問い合わせください。", + "LIMIT_USERS_WARNING_MESSAGE": "このプロジェクトで許可されている最大メンバー数{{maxMembers}}名に達しようとしています。" + }, + "LEAVE_PROJECT_WARNING": { + "TITLE": "オーナーが不在となるため、プロジェクトを離脱することができません。", + "CURRENT_USER_OWNER": { + "DESC": "現在、あなたはこのプロジェクトのオーナーです。プロジェクトを去る前にオーナーの権限を他の誰かに譲渡してください。", + "BUTTON": "プロジェクトのオーナーを変更する" + }, + "OTHER_USER_OWNER": { + "DESC": "現在のプロジェクトのプロジェクトオーナーを削除することはできません。まず新しいプロジェクトオーナーを割り当ててください。", + "BUTTON": "プロジェクトオーナーの変更をリクエストする。" + } + }, + "CHANGE_OWNER": { + "TITLE": "誰を新しいプロジェクトオーナーにしたいですか?", + "ADD_COMMENT": "コメントを追加", + "BUTTON": "このメンバーを新しいプロジェクトオーナーにする。" + }, + "CONTACT_PROJECT": { + "TITLE": "メールを送る", + "WARNING": "プロジェクト管理者がメールを受信します", + "PLACEHOLDER": "メッセージを書いてください", + "SEND": "送信" + } + }, + "EPIC": { + "PAGE_TITLE": "{{epicSubject}} - エピック {{epicRef}} - {{projectName}}", + "PAGE_DESCRIPTION": "ステータス: {{epicStatus }}. 説明: {{epicDescription}}", + "SECTION_NAME": "エピック", + "TITLE_LIGHTBOX_UNLINK_RELATED_USERSTORY": "関連するユーザーストーリーのリンクを削除", + "MSG_LIGHTBOX_UNLINK_RELATED_USERSTORY": "関連するユーザーストーリー '{{subject}}' とのリンクが削除されます。", + "ERROR_UNLINK_RELATED_USERSTORY": "リンクの削除に失敗: {{errorMessage}}", + "CREATE_RELATED_USERSTORIES": "関連付ける", + "NEW_USERSTORY": "新しいユーザーストーリー", + "EXISTING_USERSTORY": "既存のユーザーストーリー", + "CHOOSE_PROJECT_FOR_CREATION": "プロジェクトとは?", + "SUBJECT": "題名", + "SUBJECT_BULK_MODE": "題名 (一括登録)", + "CHOOSE_PROJECT_FROM": "プロジェクトとは?", + "CHOOSE_USERSTORY": "ユーザーストーリーとは?", + "NO_USERSTORIES": "このプロジェクトにはユーザーストーリーがまだありません。別のプロジェクトを選択してください。", + "FILTER_USERSTORIES": "ユーザーストーリーをフィルター", + "LIGHTBOX_TITLE_BLOKING_EPIC": "ブロックしているエピック", + "ACTION_DELETE": "エピックの削除" + }, + "US": { + "PAGE_TITLE": "{{userStorySubject}} - ユーザーストーリー {{userStoryRef}} - {{projectName}}", + "PAGE_DESCRIPTION": "ステータス: {{userStoryStatus }}. 進捗 {{userStoryProgressPercentage}}% ({{userStoryTotalTasks}}中{{userStoryClosedTasks}}タスク完了). ポイント: {{userStoryPoints}}. 説明: {{userStoryDescription}}", + "SECTION_NAME": "ユーザーストーリー", + "LINK_TASKBOARD": "タスクボード", + "TITLE_LINK_TASKBOARD": "タスクボードに移動", + "TOTAL_POINTS": "合計ポイント", + "ADD": "+ 新規ユーザーストーリーを追加する", + "ADD_BULK": "新規ユーザーストーリーを一括で追加する", + "PROMOTED": "このユーザーストーリーはこちらの課題から発展:", + "TITLE_LINK_GO_TO_ISSUE": "課題へ移動", + "TITLE_DELETE_ACTION": "ユーザーストーリーを削除", + "LIGHTBOX_TITLE_BLOKING_US": "Blocking us", + "NOT_ESTIMATED": "見積もりが行われていません", + "TRIBE": { + "PUBLISH": "Publish as Gig in Taiga Tribe", + "PUBLISH_INFO": "詳細表示", + "PUBLISH_TITLE": "More info on publishing in Taiga Tribe", + "PUBLISHED_AS_GIG": "Story published as Gig in Taiga Tribe", + "EDIT_LINK": "リンクを編集", + "CLOSE": "Close", + "SYNCHRONIZE_LINK": "synchronize with Taiga Tribe", + "PUBLISH_MORE_INFO_TITLE": "このタスクに誰か必要ですか?", + "PUBLISH_MORE_INFO_TEXT": "

If you need help with a particular piece of work you can easily create gigs on Taiga Tribe and receive help from all over the world. You will be able to control and manage the gig enjoying a great community eager to contribute.

TaigaTribe was born as a Taiga sibling. Both platforms can live separately but we believe that there is much power in using them combined so we are making sure the integration works like a charm.

" + }, + "FIELDS": { + "TEAM_REQUIREMENT": "チームからの要求", + "CLIENT_REQUIREMENT": "お客様からの要求" + } + }, + "COMMENTS": { + "DELETED_INFO": "{{user}}によってコメントは削除されました。", + "COMMENTS_COUNT": "{{comments}}コメント", + "OLDER_FIRST": "古い順", + "RECENT_FIRST": "新しい順", + "COMMENT": "コメント", + "EDITED_COMMENT": "編集済み:", + "SHOW_HISTORY": "View historic", + "TYPE_NEW_COMMENT": "新しいコメントをここに入力", + "SHOW_DELETED": "削除済コメントを表示", + "HIDE_DELETED": "削除済コメントを隠す", + "DELETE": "コメントを削除", + "RESTORE": "コメントを復元", + "HISTORY": { + "TITLE": "アクティビティ" + } + }, + "ACTIVITY": { + "TITLE": "アクティビティ", + "ACTIVITIES_COUNT": "{{activities}} アクティビティー", + "TAGS_ADDED": "追加したタグ:", + "TAGS_REMOVED": "削除したタグ:", + "US_POINTS": "{{role}} ポイント", + "NEW_ATTACHMENT": "新しい添付ファイル:", + "DELETED_ATTACHMENT": "削除された添付ファイル:", + "UPDATED_ATTACHMENT": "更新された添付ファイル ({{filename}}):", + "CREATED_CUSTOM_ATTRIBUTE": "カスタム属性を作成しました", + "UPDATED_CUSTOM_ATTRIBUTE": "カスタム属性を更新しました", + "BECAME_DEPRECATED": "became deprecated", + "BECAME_UNDEPRECATED": "became undeprecated", + "TEAM_REQUIREMENT": "チームからの要求", + "CLIENT_REQUIREMENT": "お客様からの要求", + "BLOCKED": "ブロック中", + "VALUES": { + "UNASSIGNED": "未割当" + }, + "FIELDS": { + "SUBJECT": "題名", + "DESCRIPTION": "説明", + "STATUS": "ステータス", + "TYPE": "タイプ", + "ASSIGNED_TO": "割り当てる", + "MILESTONE": "スプリント", + "COLOR": "色" + } + }, + "BACKLOG": { + "PAGE_TITLE": "バックログ - {{projectName}}", + "PAGE_DESCRIPTION": "The backlog panel, with user stories and sprints of the project {{projectName}}: {{projectDescription}}", + "SECTION_NAME": "バックログ", + "CUSTOMIZE_GRAPH": "バックロググラフのカスタマイズ", + "CUSTOMIZE_GRAPH_TEXT": "To have a nice graph that helps you follow the evolution of the project you have to set up the points and sprints through the", + "CUSTOMIZE_GRAPH_ADMIN": "管理", + "CUSTOMIZE_GRAPH_TITLE": "管理ユーザーでポイントとスプリントを設定してください。", + "MOVE_US_TO_CURRENT_SPRINT": "現在のスプリントに移動", + "MOVE_US_TO_LATEST_SPRINT": "最新のスプリントに移動", + "EMPTY": "バックログが空です!", + "CREATE_NEW_US": "新規US作成", + "CREATE_NEW_US_EMPTY_HELP": "新しくユーザーストーリーを作成してください。", + "EXCESS_OF_POINTS": "Excess of points", + "PENDING_POINTS": "保留ポイント", + "CLOSED_POINTS": "完了", + "COMPACT_SPRINT": "Compact Sprint", + "GO_TO_TASKBOARD": "タスクボード {{::name}} へ移動", + "EDIT_SPRINT": "スプリントを編集", + "TOTAL_POINTS": "合計", + "STATUS_NAME": "ステータス名", + "SORTABLE_FILTER_ERROR": "You can't drop on backlog when filters are open", + "DOOMLINE": "Project Scope [Doomline]", + "CHART": { + "XAXIS_LABEL": "スプリント", + "YAXIS_LABEL": "ポイント", + "OPTIMAL": "Optimal pending points for sprint \"{{sprintName}}\" should be {{value}}", + "REAL": "スプリント \"{{sprintName}}\" の実際の保留ポイントは {{value}} です", + "INCREMENT_TEAM": "Incremented points by team requirements for sprint \"{{sprintName}}\" is {{value}}", + "INCREMENT_CLIENT": "Incremented points by client requirements for sprint \"{{sprintName}}\" is {{value}}" + }, + "TAGS": { + "TOGGLE": "タグ表示を固定", + "SHOW": "タグを表示", + "HIDE": "タグを非表示" + }, + "FORECASTING": { + "TITLE": "Velocity forecasting", + "BACKLOG": "バックログを表示", + "NEW_SPRINT": "Candidate User Stories for your next sprint based on your velocity. Click to create a new sprint.", + "CURRENT_SPRINT": "あなたの作業速度をもとにしたスプリント向けのユーザーストーリー候補。現在のスプリントに追加するにはクリックしてください。" + }, + "TABLE": { + "COLUMN_US": "User Stories", + "TITLE_COLUMN_POINTS": "役割ごとにビューを選択" + }, + "SPRINT_SUMMARY": { + "TOTAL_POINTS": "合計
ポイント", + "COMPLETED_POINTS": "完了済み
ポイント", + "OPEN_TASKS": "オープン
タスク", + "CLOSED_TASKS": "完了済み
タスク", + "IOCAINE_DOSES": "iocaine
doses", + "SHOW_STATISTICS_TITLE": "統計を表示", + "TOGGLE_BAKLOG_GRAPH": "バーンダウングラフ 表示/非表示", + "POINTS_PER_ROLE": "役割ごとのポイント" + }, + "SUMMARY": { + "PROJECT_POINTS": "プロジェクト
ポイント", + "DEFINED_POINTS": "定義された
ポイント", + "CLOSED_POINTS": "closed
points", + "POINTS_PER_SPRINT": "ポイント /
スプリント" + }, + "FILTERS": { + "TOGGLE": "フィルター表示を固定", + "HIDE": "フィルターを非表示", + "SHOW": "フィルターを表示" + }, + "SPRINTS": { + "TITLE": "スプリント", + "DATE": "YYYY年MM月DD日", + "LINK_TASKBOARD": "スプリントタスクボード", + "TITLE_LINK_TASKBOARD": "タスクボード{{name}}へ移動", + "EMPTY": "まだスプリントはありません", + "WARNING_EMPTY_SPRINT_ANONYMOUS": "This sprint has no User Stories", + "WARNING_EMPTY_SPRINT": "新しいスプリントを始めるために、バックログからストーリーをここにドロップしてください。", + "TITLE_ACTION_NEW_SPRINT": "新しいスプリントを追加", + "TEXT_ACTION_NEW_SPRINT": "新しくスプリントをプロジェクトに作成してください。", + "ACTION_SHOW_CLOSED_SPRINTS": "終了したスプリントを表示", + "ACTION_HIDE_CLOSED_SPRINTS": "終了したスプリントを非表示" + } + }, + "ERROR": { + "TEXT1": "何かよくないことが発生したようですがウンパルンパたちは問題なく作業しています。", + "NOT_FOUND": "見つかりません", + "NOT_FOUND_TEXT": "Error 404. 参照しようとしているページはすでに存在しません。TAIGAホームページに戻って探してみてください。", + "PERMISSION_DENIED": "権限がありません", + "PERMISSION_DENIED_TEXT": "このページへのアクセスが許可されていません。", + "VERSION_ERROR": "以前、Taigaの中の誰かが変更をしたためウンパルンパたちはあなたの変更を適用できません。リロードをしてもう一度適用してみてください。(現在の変更は失われます)" + }, + "TASKBOARD": { + "PAGE_TITLE": "{{sprintName}} - スプリントタスクボード - {{projectName}}", + "PAGE_DESCRIPTION": "スプリント {{sprintName}} ({{startDate}}から{{endDate}}まで) / {{projectName}}。{{completedPercentage}}% ({{totalPoints}}中{{completedPoints}}ポイント) 完了。{{totalTasks}}タスク中{{openTasks}}タスクが未完了。", + "SECTION_NAME": "タスクボード", + "TITLE_ACTION_ADD": "新規タスクを追加", + "TITLE_ACTION_ADD_BULK": "新規タスクを一括で追加する", + "TITLE_ACTION_ASSIGN": "タスクをアサイン", + "PLACEHOLDER_CARD_TITLE": "This could be a task", + "PLACEHOLDER_CARD_TEXT": "ストーリーを分割しタスクとして別管理する。", + "TABLE": { + "COLUMN": "ユーザーストーリー", + "TITLE_ACTION_FOLD": "列をたたむ", + "TITLE_ACTION_UNFOLD": "列をひろげる", + "TITLE_ACTION_FOLD_ROW": "行をたたむ", + "TITLE_ACTION_UNFOLD_ROW": "行をひろげる", + "FIELD_POINTS": "ポイント", + "ROW_UNASSIGED_TASKS_TITLE": "未アサイン タスク" + }, + "CHARTS": { + "XAXIS_LABEL": "日", + "YAXIS_LABEL": "ポイント", + "OPTIMAL": "Optimal pending points for day {{formattedDate}} should be {{roundedValue}}", + "REAL": "{{formattedDate}} の実際の保留ポイントは {{roundedValue}} です", + "DATE": "YYYY年MM月DD日" + } + }, + "TASK": { + "PAGE_TITLE": "{{taskSubject}} - タスク {{taskRef}} - {{projectName}}", + "PAGE_DESCRIPTION": "ステータス: {{taskStatus }}. 説明: {{taskDescription}}", + "SECTION_NAME": "タスク", + "LINK_TASKBOARD": "タスクボード", + "TITLE_LINK_TASKBOARD": "タスクボードに移動", + "PLACEHOLDER_SUBJECT": "新しいタスク名を入力", + "TITLE_SELECT_STATUS": "ステータス名", + "OWNER_US": "このタスクはこちらに属しています。", + "TITLE_LINK_GO_OWNER": "ユーザーストーリーに移動", + "TITLE_DELETE_ACTION": "タスクを削除", + "LIGHTBOX_TITLE_BLOKING_TASK": "Blocking task", + "FIELDS": { + "IS_IOCAINE": "Is iocaine" + }, + "TITLE_ACTION_IOCAINE": "Feeling a bit overwhelmed by a task? Make sure others know about it by clicking on Iocaine when editing a task. It's possible to become immune to this (fictional) deadly poison by consuming small amounts over time just as it's possible to get better at what you do by occasionally taking on extra challenges!" + }, + "NOTIFICATION": { + "OK": "すべてOKです", + "WARNING": "おっと、何か問題があったようです", + "WARNING_TEXT": "あなたの変更がセーブされなかったことにウンパルンパたちは悲しんでいます!", + "SAVED": "ウンパルンパたちがすべての変更を保存しました。", + "CLOSE": "通知を閉じる", + "MAIL": "メールでの通知", + "ASK_DELETE": "本当に削除してもよろしいですか?" + }, + "CANCEL_ACCOUNT": { + "TITLE": "アカウントを解約する", + "SUBTITLE": "Taigaを脱会されてしまうのは残念です。楽しくご利用頂いていたことを祈ります。:)", + "PLACEHOLDER_INPUT_TOKEN": "アカウントトークンをキャンセル", + "ACTION_LEAVING": "はい、離脱します!", + "SUCCESS": "ウンパルンパたちがあなたのアカウントを削除しました。" + }, + "CHANGE_EMAIL_FORM": { + "TITLE": "メール変更", + "SUBTITLE": "あとはクリックだけであなたのメールアドレスが更新されます!", + "PLACEHOLDER_INPUT_TOKEN": "メールトークンを変更", + "ACTION_CHANGE_EMAIL": "メール変更", + "SUCCESS": "ウンパルンパたちがあなたのメールアドレスを更新しました" + }, + "ISSUES": { + "PAGE_TITLE": "課題 - {{projectName}}", + "PAGE_DESCRIPTION": "課題一覧パネル {{projectName}}: {{projectDescription}}", + "SECTION_NAME": "課題", + "ACTION_NEW_ISSUE": "+ 新規 ISSUE", + "ACTION_PROMOTE_TO_US": "ユーザーストーリーに変更する", + "PROMOTED": "この課題はこちらのユーザーストーリーへ発展:", + "EXTERNAL_REFERENCE": "課題の作成元: ", + "GO_TO_EXTERNAL_REFERENCE": "originへ移動", + "ACTION_DELETE": "Issue を削除", + "LIGHTBOX_TITLE_BLOKING_ISSUE": "ブロックしている Issue", + "FIELDS": { + "PRIORITY": "優先度", + "SEVERITY": "深刻度", + "TYPE": "タイプ" + }, + "CONFIRM_PROMOTE": { + "TITLE": "このIssueを新しいユーザーストーリーに変更", + "MESSAGE": "この課題から新しいユーザーストーリーを作成しますか?" + }, + "TABLE": { + "COLUMNS": { + "TYPE": "タイプ", + "SEVERITY": "深刻度", + "PRIORITY": "優先度", + "SUBJECT": "題名", + "VOTES": "投票", + "STATUS": "ステータス", + "CREATED": "作成", + "ASSIGNED_TO": "担当者" + }, + "TITLE_ACTION_CHANGE_STATUS": "ステータスを変更", + "TITLE_ACTION_ASSIGNED_TO": "担当者", + "BLOCKED": "ブロック中", + "EMPTY": { + "TITLE": "レポートが必要な課題はありません :-)", + "SUBTITLE": "課題は見つかりましたか?" + } + } + }, + "ISSUE": { + "PAGE_TITLE": "{{issueSubject}} - 課題 {{issueRef}} - {{projectName}}", + "PAGE_DESCRIPTION": "ステータス: {{issueStatus }}. タイプ: {{issueType}}, 優先度: {{issuePriority}}. 深刻度: {{issueSeverity}}. 説明: {{issueDescription}}" + }, + "KANBAN": { + "PAGE_TITLE": "かんばん - {{projectName}}", + "PAGE_DESCRIPTION": "The kanban panel, with user stories of the project {{projectName}}: {{projectDescription}}", + "SECTION_NAME": "かんばん", + "TITLE_ACTION_FOLD": "列をたたむ", + "TITLE_ACTION_UNFOLD": "列をひろげる", + "TITLE_ACTION_ADD_US": "新規ユーザーストーリーを追加", + "TITLE_ACTION_ADD_BULK": "新規ユーザーストーリーを一括追加", + "ACTION_SHOW_ARCHIVED": "アーカイブ済を表示", + "ACTION_HIDE_ARCHIVED": "アーカイブ済を隠す", + "HIDDEN_USER_STORIES": "The user stories in this status are hidden by default", + "PLACEHOLDER_CARD_TITLE": "These are your User Stories", + "PLACEHOLDER_CARD_TEXT": "Stories might also have subtasks to separate requirements" + }, + "SEARCH": { + "PAGE_TITLE": "検索 - {{projectName}}", + "PAGE_DESCRIPTION": "ユーザーストーリー、課題、タスク、Wikiページ、その他何でもこのプロジェクトを検索 {{projectName}}: {{projectDescription}}", + "FILTER_EPICS": "エピック", + "FILTER_USER_STORIES": "User Stories", + "FILTER_ISSUES": "課題", + "FILTER_TASKS": "タスク", + "FILTER_WIKI": "Wikiページ", + "PLACEHOLDER_SEARCH": "検索...", + "TITLE_ACTION_SEARCH": "検索", + "EMPTY_TITLE": "It looks like nothing was found with your search criteria.", + "EMPTY_DESCRIPTION": "Maybe try one of the tabs above or search again" + }, + "TEAM": { + "PAGE_TITLE": "チーム - {{projectName}}", + "PAGE_DESCRIPTION": "The team panel to show all the members of the project {{projectName}}: {{projectDescription}}", + "SECTION_NAME": "チーム", + "PLACEHOLDER_INPUT_SEARCH": "フルネームで検索する", + "COLUMN_MR_WOLF": "Mr. Wolf", + "EXPLANATION_COLUMN_MR_WOLF": "完了した課題", + "COLUMN_IOCAINE": "Iocaine Drinker", + "EXPLANATION_COLUMN_IOCAINE": "Iocaine doses ingested", + "COLUMN_CERVANTES": "Cervantes", + "EXPLANATION_COLUMN_CERVANTES": "Wiki ページを編集しました", + "COLUMN_BUG_HUNTER": "バグハンター", + "EXPLANATION_COLUMN_BUG_HUNTER": "報告されている課題", + "COLUMN_NIGHT_SHIFT": "Night Shift", + "EXPLANATION_COLUMN_NIGHT_SHIFT": "完了タスク", + "COLUMN_TOTAL_POWER": "Total Power", + "EXPLANATION_COLUMN_TOTAL_POWER": "合計ポイント", + "SECTION_TITLE_TEAM": "チーム >", + "SECTION_FILTER_ALL": "すべて", + "CONFIRM_LEAVE_PROJECT": "本当にこのプロジェクトから脱退していいですか?", + "ACTION_LEAVE_PROJECT": "このプロジェクトから離脱する" + }, + "USER_SETTINGS": { + "AVATAR_MAX_SIZE": "[最大サイズ: {{maxFileSize}}]", + "MENU": { + "SECTION_TITLE": "ユーザー設定", + "USER_PROFILE": "ユーザープロフィール", + "CHANGE_PASSWORD": "パスワード変更", + "EMAIL_NOTIFICATIONS": "メール通知" + }, + "NOTIFICATIONS": { + "SECTION_NAME": "メール通知", + "COLUMN_PROJECT": "プロジェクト", + "COLUMN_RECEIVE_ALL": "すべて受信", + "COLUMN_ONLY_INVOLVED": "関連するものだけ", + "COLUMN_NO_NOTIFICATIONS": "通知なし", + "OPTION_ALL": "すべて", + "OPTION_INVOLVED": "Involved", + "OPTION_NONE": "なし" + } + }, + "USER_PROFILE": { + "ACTION_USE_GRAVATAR": "デフォルトのイメージを使用する", + "ACTION_DELETE_ACCOUNT": "Taigaアカウントを削除", + "CHANGE_EMAIL_SUCCESS": "メールボックスを確認してください!
新しいメールアドレスを設定するための手順を送信しました。", + "CHANGE_PHOTO": "写真を変更", + "FIELD": { + "USERNAME": "ユーザー名", + "EMAIL": "メール", + "FULL_NAME": "フルネーム", + "PLACEHOLDER_FULL_NAME": "Set your full name (ex. Íñigo Montoya)", + "BIO": "自己紹介(最大で全角105文字まで)", + "PLACEHOLDER_BIO": "あなたについて教えてください", + "LANGUAGE": "言語", + "LANGUAGE_DEFAULT": "-- デフォルトの言語を使用 --", + "THEME": "テーマ", + "THEME_DEFAULT": "-- デフォルトのテーマを使用 --" + } + }, + "WIKI": { + "PAGE_TITLE": "{{wikiPageName}} - Wiki - {{projectName}}", + "PAGE_DESCRIPTION": "{{lastModifiedDate}} に最後に編集がありました。(合計 {{totalEditions}} 件) 内容: {{ wikiPageContent }}", + "DATETIME": "YYYY年MM月DD日 HH時mm分", + "REMOVE": "このWikiページを削除", + "DELETE_LIGHTBOX_TITLE": "Wikiページを削除", + "DELETE_LINK_TITLE": "Wikiリンクを削除", + "NAVIGATION": { + "HOME": "メインページ", + "SECTION_NAME": "ブックマーク", + "ACTION_ADD_LINK": "ブックマークを追加する", + "ALL_PAGES": "全Wikiページ" + }, + "SUMMARY": { + "TIMES_EDITED": "編集
回数", + "LAST_EDIT": "最終
編集", + "LAST_MODIFICATION": "最後の変更" + }, + "SECTION_PAGES_LIST": "全ページ", + "PAGES_LIST_COLUMNS": { + "TITLE": "タイトル", + "EDITIONS": "Editions", + "CREATED": "作成", + "MODIFIED": "変更済み", + "CREATOR": "作者", + "LAST_MODIFIER": "最後の変更者" + } + }, + "HINTS": { + "SECTION_NAME": "ヒント", + "LINK": "利用方法を知りたい場合はサポートページを訪れてください", + "LINK_TITLE": "サポートページへ行く", + "HINT1_TITLE": "Did you know you can import and export projects?", + "HINT1_TEXT": "ひとつのTaigaアカウントの全てのデータを抽出し、別のアカウントへ移すことができます。", + "HINT2_TITLE": "カスタムフィールドが作れるのはご存知ですか?", + "HINT2_TEXT": "Teams can now create custom fields as a flexible means to enter specific data useful for their particular workflow.", + "HINT3_TITLE": "Reorder your projects to feature those most relevant to you.", + "HINT3_TEXT": "最上部にあるダイレクトアクセスバーに10プロジェクトまで表示されます。", + "HINT4_TITLE": "Did you forget what were you working on?", + "HINT4_TEXT": "ご心配なさらないでください。ダッシュボードではあなたが取り組んだ順番にオープンなタスク、課題、ユーザーストーリーが表示されます。" + }, + "TIMELINE": { + "UPLOAD_ATTACHMENT": "{{username}} さんが新しい添付ファイル {{obj_name}} をアップロードしました", + "US_CREATED": "{{username}} さんが新しいユーザーストーリー {{obj_name}} を作成しました( {{project_name}} )", + "ISSUE_CREATED": "{{username}} さんが新しい課題 {{obj_name}} を作成しました( {{project_name}} )", + "TASK_CREATED": "{{username}} さんが新しいタスク {{obj_name}} を作成しました( {{project_name}} )", + "TASK_CREATED_WITH_US": "{{username}} さんが新しいタスク {{obj_name}} をユーザーストーリー {{us_name}} に作成しました( {{project_name}} )", + "WIKI_CREATED": "{{username}} さんが新しいwikiページ {{obj_name}} を作成しました( {{project_name}} )", + "MILESTONE_CREATED": "{{username}} さんがスプリント {{obj_name}} を作成しました( {{project_name}} )", + "EPIC_CREATED": "{{username}} さんが {{project_name}} で新しいエピック {{obj_name}} を作成しました", + "EPIC_RELATED_USERSTORY_CREATED": "{{username}} さんが {{project_name}} でユーザーストーリー {{related_us_name}} をエピック {{epic_name}} に関連付けました", + "NEW_PROJECT": "{{username}} がプロジェクト {{project_name}} を作成しました", + "MILESTONE_UPDATED": "{{username}} がスプリント {{obj_name}} を更新しました", + "US_UPDATED": "{{username}} さんがユーザーストーリー {{obj_name}} の属性 \"{{field_name}}\" を更新しました ", + "US_UPDATED_WITH_NEW_VALUE": "{{username}} さんがユーザーストーリー {{obj_name}} の属性 \"{{field_name}}\" を {{new_value}} に更新しました", + "US_UPDATED_POINTS": "{{username}} さんがユーザーストーリー {{obj_name}} における役割 '{{role_name}}' のポイントを {{new_value}} に更新しました", + "ISSUE_UPDATED": "{{username}} さんが課題 {{obj_name}} の属性 \"{{field_name}}\" を更新しました", + "ISSUE_UPDATED_WITH_NEW_VALUE": "{{username}} さんが課題 {{obj_name}} の属性 \"{{field_name}}\" を {{new_value}} に更新しました", + "TASK_UPDATED": "{{username}} が {{obj_name}} の {{field_name}} を {{new_value}} に更新しました", + "TASK_UPDATED_WITH_NEW_VALUE": "{{username}} が {{obj_name}} の {{field_name}} を {{new_value}} に更新しました", + "TASK_UPDATED_WITH_US": "{{username}} さんがユーザーストーリー {{us_name}} のタスク {{obj_name}} の属性 \"{{field_name}}\" を更新しました", + "TASK_UPDATED_WITH_US_NEW_VALUE": "{{username}} さんがユーザーストーリー {{us_name}} のタスク {{obj_name}} における属性 \"{{field_name}}\" を {{new_value}} に更新しました", + "WIKI_UPDATED": "{{username}} さんがWikiページ {{obj_name}} を更新しました", + "EPIC_UPDATED": "{{username}} さんがエピック {{obj_name}} の属性 \"{{field_name}}\" を更新しました", + "EPIC_UPDATED_WITH_NEW_VALUE": "{{username}} さんがエピック {{obj_name}} の属性 \"{{field_name}}\" を {{new_value}} に更新しました", + "EPIC_UPDATED_WITH_NEW_COLOR": "{{username}} さんが エピック {{obj_name}} の \"{{field_name}}\" を に更新しました", + "NEW_COMMENT_US": "{{username}} さんがユーザーストーリー {{obj_name}} にコメントしました", + "NEW_COMMENT_ISSUE": "{{username}} さんが課題 {{obj_name}} にコメントしました", + "NEW_COMMENT_TASK": "{{username}} さんがタスク {{obj_name}} にコメントしました", + "NEW_COMMENT_EPIC": "{{username}} さんがエピック {{obj_name}} にコメントしました", + "NEW_MEMBER": "{{project_name}} に新規メンバーが追加されました", + "US_ADDED_MILESTONE": "{{username}} さんがユーザーストーリー {{obj_name}} に {{sprint_name}} を追加しました", + "US_MOVED": "{{username}} さんがユーザーストーリー {{obj_name}} を移動しました", + "US_REMOVED_FROM_MILESTONE": "{{username}} さんがユーザーストーリー {{obj_name}} をバックログに追加しました", + "BLOCKED": "{{username}} さんが {{obj_name}} をブロックしました", + "UNBLOCKED": "{{username}} さんが {{obj_name}} のブロックを解除しました", + "NEW_USER": "{{username}} さんが Taiga に参加しました" + }, + "LEGAL": { + "TERMS_OF_SERVICE_AND_PRIVACY_POLICY_AD": "When creating a new account, you agree to our
terms of service and privacy policy." + }, + "EXTERNAL_APP": { + "PAGE_TITLE": "An external app requires authentication", + "PAGE_DESCRIPTION": "An external app requires authentication", + "AUTHORIZATION_REQUEST": "{{application}} にあなたのTaigaアカウントを使用することを許可しますか?", + "LOGIN_WITH_ANOTHER_USER": "別のユーザーでログイン", + "AUTHORIZE_APP": "Authorize app", + "CANCEL": "キャンセル" + }, + "JOYRIDE": { + "NAV": { + "NEXT": "次へ", + "BACK": "戻る", + "SKIP": "スキップ", + "DONE": "完了" + }, + "DASHBOARD": { + "STEP1": { + "TITLE": "あなたのプロジェクト", + "TEXT": "Welcome! Here you will find the projects you are involved on." + }, + "STEP2": { + "TITLE": "取り組んでいる作業", + "TEXT": "あなたが取り組んでいるユーザーストーリー、タスク、課題です。" + }, + "STEP3": { + "TITLE": "フォロー中", + "TEXT1": "And right here you will find the ones in your projects that you want to know about.", + "TEXT2": "You are already working with Taiga ;)" + }, + "STEP4": { + "TITLE": "さあ始めましょう", + "TEXT1": "You can start by creating your first Taiga project.", + "TEXT2": "グッドラック!" + } + }, + "BACKLOG": { + "STEP1": { + "TITLE": "プロジェクト概要", + "TEXT1": "Here you will see the state of your project.", + "TEXT2": "管理でプロジェクトの全ての設定を変更できます。" + }, + "STEP2": { + "TITLE": "プロダクト バックログ", + "TEXT": "The backlog is the list of requirements (User Stories) for the project. Here is where you will plan your sprints." + }, + "STEP3": { + "TITLE": "スプリント", + "TEXT": "Sprints are short periods of time (usually 2 weeks) during which specific work has to be completed and delivered." + }, + "STEP4": { + "TITLE": "User Stories", + "TEXT": "Those are the requirements at high level. You can add them to the backlog and drag them to the sprint in which it should be delivered." + } + }, + "KANBAN": { + "STEP1": { + "TITLE": "ワークフローのカスタマイズ", + "TEXT": "Set up the columns you need to map your workflow statuses through the admin." + }, + "STEP2": { + "TITLE": "ユーザーストーリー&タスク", + "TEXT": "User Stories are the requirements at high level. You can drag them to different columns." + }, + "STEP3": { + "TITLE": "ユーザーストーリーを追加中", + "TEXT1": "You may want to add a single User Story (add US icon) or a group of them (bulk icon)", + "TEXT2": "グッドラック!" + } + } + }, + "DISCOVER": { + "PAGE_TITLE": "プロジェクトを探す - Taiga", + "PAGE_DESCRIPTION": "Searchable directory of Public Projects in Taiga. Explore backlogs, timelines, issues, and teams. Check out the most liked or most active projects. Filter by Kanban or Scrum.", + "DISCOVER_TITLE": "プロジェクトを探す", + "DISCOVER_SUBTITLE": "{projects, plural, one{One public project to discover} other{# 件のプロジェクトが見つかりました}}", + "MOST_ACTIVE": "最も活発なプロジェクト", + "MOST_ACTIVE_EMPTY": "アクティブなプロジェクトはまだありません。", + "MOST_LIKED": "最も好まれているプロジェクト", + "MOST_LIKED_EMPTY": "「いいね」されたプロジェクトはまだありません", + "VIEW_MORE": "もっと見る", + "FEATURED": "注目プロジェクト", + "EMPTY": "該当するプロジェクトがありませんでした。
検索条件を変えて再度試してみてください!", + "FILTERS": { + "ALL": "すべて", + "KANBAN": "かんばん", + "SCRUM": "スクラム", + "PEOPLE": "人", + "WEEK": "先週", + "MONTH": "先月", + "YEAR": "昨年", + "ALL_TIME": "すべて", + "CLEAR": "フィルターをクリア" + }, + "SEARCH": { + "PAGE_TITLE": "検索結果 - プロジェクトを探す - Taiga", + "PAGE_DESCRIPTION": "Searchable directory of Public Projects in Taiga. Explore backlogs, timelines, issues, and teams. Check out the most liked or most active projects. Filter by Kanban or Scrum.", + "INPUT_PLACEHOLDER": "入力してください", + "ACTION_TITLE": "検索", + "RESULTS": "検索結果" + } + } +} \ No newline at end of file diff --git a/app/locales/taiga/locale-ko.json b/app/locales/taiga/locale-ko.json new file mode 100644 index 00000000..3f8e1e0b --- /dev/null +++ b/app/locales/taiga/locale-ko.json @@ -0,0 +1,1664 @@ +{ + "COMMON": { + "YES": "예", + "NO": "아니오", + "OR": "또는", + "LOADING": "불러오는 중...", + "DATE": "YYYY MMM DD", + "DATETIME": "YYYY MMM DD HH:mm", + "SAVE": "저장", + "CANCEL": "취소", + "ACCEPT": "확인", + "DELETE": "삭제하기", + "UNLINK": "연결끊기", + "CREATE": "생성하기", + "ADD": "추가하기", + "COPY_TO_CLIPBOARD": "클립보드에 복사하기: Ctrl+C", + "EDIT": "수정하기", + "DRAG": "드래그", + "TAG_LINE": "당신의 프로젝트 관리를 위한 민첩하고 무료인 오픈소스 도구", + "TAG_LINE_2": "프로젝트에 사랑을 담아", + "BLOCK": "차단", + "BLOCK_TITLE": "조건을 만족하지 않는 경우 이 아이템을 차단하세요.", + "BLOCKED": "차단됨", + "UNBLOCK": "차단 해제", + "UNBLOCK_TITLE": "차단 취소", + "BLOCKED_NOTE": "왜 차단되었나요?", + "BLOCKED_REASON": "이유를 적어주시겠어요?", + "CREATED_BY": "{{fullDisplayName}} 님이 생성", + "CLOSE": "완료", + "GO_HOME": "첫 화면으로 가기", + "PLUGINS": "플러그인", + "ONE_ITEM_LINE": "한 줄마다 하나씩...", + "NEW_BULK": "여러개 생성하기", + "RELATED_TASKS": "연관된 태스크", + "PREVIOUS": "이전", + "NEXT": "다음", + "LOGOUT": "로그아웃", + "EXTERNAL_USER": "외부 사용자", + "GENERIC_ERROR": "움파룸파가 {{error}} 라고 합니다.", + "IOCAINE_TEXT": "이 회원은 이 일에 조금 압박감을 ​​느낍니다. 당신의 도움이 필요한 시간이 지나면 아이오케인 독에 면역될 것 입니다. 지금 당장 포옹이 필요할 수도 있어요.", + "CLIENT_REQUIREMENT": "고객 요구 사항은 이전에 예상하지 않았던 새로운 요구 사항이며 프로젝트의 일부가 되어야만 합니다.", + "TEAM_REQUIREMENT": "팀 요구 사항은 프로젝트에 반드시 있어야하지만 클라이언트에게는 비용이 없어야합니다.", + "OWNER": "프로젝트 소유자", + "CAPSLOCK_WARNING": "조심하세요! 대/소문자를 구분하는 입력란에 대문자를 사용하고 있습니다.", + "CONFIRM_CLOSE_EDIT_MODE_TITLE": "정말로 수정 모드를 닫겠습니까?", + "CONFIRM_CLOSE_EDIT_MODE_MESSAGE": "저장하지 않고 편집 모드를 닫으면 모든 변경 사항이 손실됩니다.", + "RELATED_USERSTORIES": "연결된 유저 스토리", + "CARD": { + "ASSIGN_TO": "다음으로 할당", + "EDIT": "카드 수정" + }, + "FORM_ERRORS": { + "DEFAULT_MESSAGE": "값이 유효하지 않습니다", + "TYPE_EMAIL": "정확한 이메일이어야 합니다.", + "TYPE_URL": "정확한 URL이어야 합니다.", + "TYPE_URLSTRICT": "정확한 URL이어야 합니다.", + "TYPE_NUMBER": "정확한 숫자만 적어 주세요", + "TYPE_DIGITS": "숫자만 입력해 주세요", + "TYPE_DATEISO": "유효한 날짜(YYYY-MM-DD)여야 합니다.", + "TYPE_ALPHANUM": "알파벳과 숫자만 써 주세요.", + "TYPE_PHONE": "전화번호를 정확히 적어 주세요.", + "NOTNULL": "이 값은 비워 둘 수 없습니다.", + "NOT_BLANK": "이 값은 비워 둘 수 없습니다.", + "REQUIRED": "필수 항목입니다.", + "REGEXP": "값이 유효하지 않습니다", + "MIN": "이 값은 %s 와 같거나 커야 합니다.", + "MAX": "이 값은 %s 와 같거나 작아야 합니다.", + "RANGE": "이 값은 %와 %s 사이여야 합니다.", + "MIN_LENGTH": "너무 짧습니다. %s 글자 이상 입력해주세요.", + "MAX_LENGTH": "너무 깁니다. %s 글자 이하로 입력해주세요.", + "RANGE_LENGTH": "글자수가 잘못되었습니다. %s와 %s의 사이 글자수여야 합니다.", + "MIN_CHECK": "%s 개 이상 선택해주세요.", + "MAX_CHECK": "%s 개 이하로 선택해주세요.", + "RANGE_CHECK": "%s 값과 %s 값 중에 선택해주세요.", + "EQUAL_TO": "이 값이 일치해야 합니다.", + "LINEWIDTH": "하나 또는 그 이상의 줄들이 너무 깁니다. %s 이하의 문자로 다시 시도해주세요.", + "PIKADAY": "날짜 형식이 올바르지 않습니다. DD MMM YYYY 형식을 사용해주세요. (예, 23 Mar 1984)" + }, + "PICKERDATE": { + "FORMAT": "YYYY MMM DD", + "IS_RTL": "false", + "FIRST_DAY_OF_WEEK": "1", + "PREV_MONTH": "이전 달", + "NEXT_MONTH": "다음 달", + "MONTHS": { + "JAN": "1월", + "FEB": "2월", + "MAR": "3월", + "APR": "4월", + "MAY": "5월", + "JUN": "6월", + "JUL": "7월", + "AUG": "8월", + "SEP": "9월", + "OCT": "10월", + "NOV": "11월", + "DEC": "12월" + }, + "WEEK_DAYS": { + "SUN": "일요일", + "MON": "월요일", + "TUE": "화요일", + "WED": "수요일", + "THU": "목요일", + "FRI": "금요일", + "SAT": "토요일" + }, + "WEEK_DAYS_SHORT": { + "SUN": "일", + "MON": "월", + "TUE": "화", + "WED": "수", + "THU": "목", + "FRI": "금", + "SAT": "토" + } + }, + "SEE_USER_PROFILE": "{{username }}의 프로필 보기", + "USER_STORY": "유저 스토리", + "TASK": "태스크", + "ISSUE": "이슈", + "EPIC": "에픽", + "TAGS": { + "PLACEHOLDER": "태그 입력", + "DELETE": "태그 삭제하기", + "ADD": "태그 추가하기" + }, + "DESCRIPTION": { + "EMPTY": "공백으로 남기지 마세요. 재미없어요. 뭐라도 좀 적어보세요...", + "NO_DESCRIPTION": "아직 설명이 없습니다" + }, + "FIELDS": { + "SUBJECT": "주제", + "NAME": "이름", + "URL": "URL", + "DESCRIPTION": "설명", + "VALUE": "값", + "SLUG": "슬러그", + "COLOR": "색", + "IS_CLOSED": "완료했나요?", + "STATUS": "상태", + "TYPE": "타입", + "SEVERITY": "심각도", + "PRIORITY": "우선순위", + "ASSIGNED_TO": "할당됨", + "POINTS": "포인트", + "IS_BLOCKED": "차단됨", + "REF": "참조", + "VOTES": "투표", + "SPRINT": "스프린트" + }, + "ROLES": { + "ALL": "전체" + }, + "ASSIGNED_TO": { + "NOT_ASSIGNED": "할당 되지 않음", + "ASSIGN": "할당", + "DELETE_ASSIGNMENT": "할당 삭제하기", + "REMOVE_ASSIGNED": "할당 삭제", + "TOO_MANY": "사용자가 너무 많아요. 필터링 좀....", + "CONFIRM_UNASSIGNED": "어사인 하지 않은 상태로 둘 건가요?", + "TITLE_ACTION_EDIT_ASSIGNMENT": "할당 수정하기", + "SELF": "나에게 할당하기" + }, + "STATUS": { + "CLOSED": "완료함", + "OPEN": "열림" + }, + "WATCHERS": { + "WATCHERS": "구독중인 사람들", + "ADD": "구독자 추가", + "TITLE_ADD": "프로젝트 회원을 구독자 목록에 추가", + "DELETE": "구독자 삭제하기", + "TITLE_LIGHTBOX_DELETE_WARTCHER": "구독자 삭제..." + }, + "WATCH_BUTTON": { + "WATCH": "구독", + "WATCHING": "구독중", + "UNWATCH": "구독 취소", + "WATCHERS": "구독중인 사람들", + "BUTTON_TITLE": "구독/구독 취소", + "COUNTER_TITLE": "{total, plural, one{one watcher} other{# 명이 구독중}}" + }, + "VOTE_BUTTON": { + "BUTTON_TITLE": "이 아이템 공감/비공감", + "COUNTER_TITLE": "{total, plural, one{one vote} other{# 명의 찬성}}" + }, + "CUSTOM_ATTRIBUTES": { + "CUSTOM_FIELDS": "사용자 정의 필드", + "SAVE": "사용자 정의 필드 저장하기", + "EDIT": "사용자 정의 필드 수정하기", + "DELETE": "사용자 정의 속성 삭제하기", + "CONFIRM_DELETE": "이 사용자 정의 필드의 모든 값이 삭제된다는 점을 기억하십시오.\n계속 하시겠습니까?" + }, + "FILTERS": { + "INPUT_PLACEHOLDER": "제목 또는 참조", + "TITLE_ACTION_FILTER_BUTTON": "검색하기", + "TITLE": "필터", + "TITLE_ACTION_SEARCH": "검색", + "ACTION_SAVE_CUSTOM_FILTER": "커스컴 필터 저장하기", + "PLACEHOLDER_FILTER_NAME": "필터 이름을 쓰고 엔터키를 누르세요", + "APPLIED_FILTERS_NUM": "적용된 필터", + "CATEGORIES": { + "TYPE": "타입", + "STATUS": "상태", + "SEVERITY": "심각도", + "PRIORITIES": "우선순위", + "TAGS": "태그", + "ASSIGNED_TO": "할당됨", + "CREATED_BY": "생성함", + "CUSTOM_FILTERS": "사용자 정의 필터", + "EPIC": "에픽" + } + }, + "WYSIWYG": { + "OUTDATED": "편집하는 동안 다른 사람이 변경했습니다. 변경 사항을 저장하기 전에 활성 탭에서 새 버전을 확인하십시오.", + "MARKDOWN_HELP": "마크다운 문법 도움말" + }, + "PERMISIONS_CATEGORIES": { + "EPICS": { + "NAME": "에픽", + "VIEW_EPICS": "에픽 보기", + "ADD_EPICS": "에픽 추가", + "MODIFY_EPICS": "에픽 수정하기", + "COMMENT_EPICS": "에픽 댓글", + "DELETE_EPICS": "에픽 삭제하기" + }, + "SPRINTS": { + "NAME": "스프린트", + "VIEW_SPRINTS": "스프린트 보기", + "ADD_SPRINTS": "스프린트 추가하기", + "MODIFY_SPRINTS": "스프린트 수정하기", + "DELETE_SPRINTS": "스프린트 삭제하기" + }, + "USER_STORIES": { + "NAME": "유저 스토리", + "VIEW_USER_STORIES": "유저 스토리 보기", + "ADD_USER_STORIES": "유저 스토리 추가하기", + "MODIFY_USER_STORIES": "유저 스토리 수정하기", + "COMMENT_USER_STORIES": "유저 스토리 댓글", + "DELETE_USER_STORIES": "유저 스토리 삭제하기" + }, + "TASKS": { + "NAME": "태스크", + "VIEW_TASKS": "태스크 보기", + "ADD_TASKS": "태스크 추가하기", + "MODIFY_TASKS": "태스크 수정하기", + "COMMENT_TASKS": "태스크 댓글", + "DELETE_TASKS": "태스크 삭제하기" + }, + "ISSUES": { + "NAME": "이슈", + "VIEW_ISSUES": "이슈 보기", + "ADD_ISSUES": "이슈 추가하기", + "MODIFY_ISSUES": "이슈 수정하기", + "COMMENT_ISSUES": "이슈 댓글", + "DELETE_ISSUES": "이슈 삭제하기" + }, + "WIKI": { + "NAME": "위키", + "VIEW_WIKI_PAGES": "위키 보기", + "ADD_WIKI_PAGES": "위키 페이지 추가하기", + "MODIFY_WIKI_PAGES": "위키 페이지 수정하기", + "DELETE_WIKI_PAGES": "위키 페이지 삭제하기", + "VIEW_WIKI_LINKS": "위키 링크 보기", + "ADD_WIKI_LINKS": "위키 링크 추가하기", + "DELETE_WIKI_LINKS": "위키 링크 삭제하기" + } + } + }, + "LOGIN": { + "PAGE_TITLE": "로그인 - 타이가", + "PAGE_DESCRIPTION": "타이가에 로그인하세요. 타이가는 스타트업과 애자일 개발자/디자이너들을 위한 간명하고 아름다운 프로젝트 관리 플랫폼입니다. 정말 즐거울 거예요." + }, + "AUTH": { + "INVITED_YOU": "이 프로젝트에 참여하도록 초대받았습니다", + "NOT_REGISTERED_YET": "아직 가입을 안 했나요?", + "REGISTER": "회원 가입", + "CREATE_ACCOUNT": "무료 계정을 생성하세요" + }, + "LOGIN_COMMON": { + "HEADER": "타이가 계정을 이미 등록했습니다", + "PLACEHOLDER_AUTH_NAME": "아이디나 이메일 (대소문자 구분)", + "LINK_FORGOT_PASSWORD": "비밀번호를 잊었나요?", + "TITLE_LINK_FORGOT_PASSWORD": "비밀번호를 잊었나요?", + "ACTION_ENTER": "들어가기", + "ACTION_SIGN_IN": "로그인", + "PLACEHOLDER_AUTH_PASSWORD": "비밀번호 (대소문자 구분)" + }, + "LOGIN_FORM": { + "ERROR_AUTH_INCORRECT": "움파룸파가 말하길, 아이디나 이메일, 비밀번호 중 하나가 틀렸다고 하네요.", + "SUCCESS": "움파룸파가 즐거워 합니다. 타이가에 어서 오세요." + }, + "REGISTER": { + "PAGE_TITLE": "등록 - 타이가", + "PAGE_DESCRIPTION": "타이가에 계정을 만드세요. 스타트업과 애자일 개발자/디자이너들을 위한 간명하고 아름다운 프로젝트 관리 플랫폼입니다. 정말 즐거울 거예요." + }, + "REGISTER_FORM": { + "TITLE": "타이가 계정을 등록하기(무료)", + "PLACEHOLDER_NAME": "아이디를 입력하세요 (대소문자 구분)", + "PLACEHOLDER_FULL_NAME": "전체 이름을 넣으세요", + "PLACEHOLDER_EMAIL": "이메일", + "PLACEHOLDER_PASSWORD": "비밀번호 설정하기 (대소문자 구분)", + "ACTION_SIGN_UP": "등록하기", + "TITLE_LINK_LOGIN": "로그인", + "LINK_LOGIN": "이미 등록하셨나요? 로그인" + }, + "FORGOT_PASSWORD": { + "PAGE_TITLE": "비밀번호 찾기 - 타이가", + "PAGE_DESCRIPTION": "새 비밀번호를 발급받을 아이디나 이메일을 입력하세요." + }, + "FORGOT_PASSWORD_FORM": { + "TITLE": "혹시 비밀번호를 잊었나요?", + "SUBTITLE": "새로운 암호를 설정하기 위해서, 아이디나 이메일을 입력하세요.", + "PLACEHOLDER_FIELD": "아이디나 이메일", + "ACTION_RESET_PASSWORD": "비밀번호 재설정하기", + "LINK_CANCEL": "아니요 되돌아갈래요. 기억이 났어요.", + "SUCCESS_TITLE": "메일함을 확인해보세요!", + "SUCCESS_TEXT": "이메일 보관함을 확인하세요!
새 비밀번호를 설정할 수 있는 방법을 이메일로 알려드렸습니다.", + "ERROR": "움파룸파가 말하길, 아직 등록되지 않은 사용자라고 하네요." + }, + "CHANGE_PASSWORD": { + "PAGE_TITLE": "비밀번호 변경하기 - 타이가", + "SECTION_NAME": "비밀번호 변경하기", + "FIELD_CURRENT_PASSWORD": "현재 비밀번호", + "PLACEHOLDER_CURRENT_PASSWORD": "현재 비밀번호 (아직 설정한 적이 없다면 비워두세요)", + "FIELD_NEW_PASSWORD": "새 비밀번호", + "PLACEHOLDER_NEW_PASSWORD": "새 비밀번호를 입력하세요", + "FIELD_RETYPE_PASSWORD": "새 비밀번호를 한 번 더 입력하세요", + "PLACEHOLDER_RETYPE_PASSWORD": "새 비밀번호를 한 번 더 입력하세요", + "ERROR_PASSWORD_MATCH": "비밀번호가 일치하지 않습니다" + }, + "CHANGE_PASSWORD_RECOVERY_FORM": { + "TITLE": "타이가 패쓰 생성하기", + "SUBTITLE": "아참, 철분이 많은 음식을 먹으면 기억력에 좋다네요. ^^", + "PLACEHOLDER_NEW_PASSWORD": "새 비밀번호", + "PLACEHOLDER_RE_TYPE_NEW_PASSWORD": "새 비밀번호를 한 번 더 입력하세요", + "ACTION_RESET_PASSWORD": "비밀번호 재설정하기", + "ERROR": "움파룸파가 암호를 복구하지 못했습니다. 다시 한 번 시도해 주세요.", + "SUCCESS": "움파룸파가 새 비밀번호를 저장했습니다.
로그인해보세요." + }, + "INVITATION": { + "PAGE_TITLE": "초대 수락 - 타이가", + "PAGE_DESCRIPTION": "타이가에서 온 프로젝트 초대를 수락하세요. 타이가는 스타트업과 애자일 개발자/디자이너들을 위한 간명하고 아름다운 프로젝트 관리 플랫폼입니다. 정말 즐거울 거예요" + }, + "INVITATION_LOGIN_FORM": { + "NOT_FOUND": "움파룸파가, 당신의 초대장을 못 찾았습니다.", + "SUCCESS": "{{project_name}} 프로젝트에 오신 것을 환영합니다." + }, + "HOME": { + "PAGE_TITLE": "홈페이지 - 타이가", + "PAGE_DESCRIPTION": "타이가 홈페이지에서는 여러분의 프로젝트 뿐만 아니라 여러분이 관련된 유저 스토리, 태스크, 이슈를 확인할 수 있습니다.", + "EMPTY_WORKING_ON": "비어있는 것 같아요. 아닌가요?
타이가로 일을 시작하고 당신이 일하게 될 스토리, 태스크, 이슈들을 확인해보세요.", + "EMPTY_WATCHING": "프로젝트의 유저 스토리, 태스크 그리고 이슈들을 팔로우하여 변경사항이 있을 때마다 알림을 받으세요 :)", + "EMPTY_PROJECT_LIST": "아직 프로젝트가 없습니다.", + "WORKING_ON_SECTION": "일 하는 중", + "WATCHING_SECTION": "구독중", + "DASHBOARD": "프로젝트 대시보드" + }, + "EPICS": { + "TITLE": "에픽", + "SECTION_NAME": "에픽", + "EPIC": "에픽", + "PAGE_TITLE": "에픽 - {{projectName}}", + "PAGE_DESCRIPTION": "프로젝트의 에픽 목록 {{projectName}}: {{projectDescription}}", + "DASHBOARD": { + "ADD": "+ 에픽 추가", + "UNASSIGNED": "할당되지 않음" + }, + "EMPTY": { + "TITLE": "아직 에픽이 없는 것 같네요.", + "EXPLANATION": "에픽은 유저 스토리를 포함하는 상위 레벨 항목입니다.
에픽은 계층 구조의 최상위에 있으며 유저 스토리를 그룹화하는데 사용할 수 있습니다.", + "HELP": "에픽에 대하여 더 배우기" + }, + "TABLE": { + "VOTES": "투표", + "NAME": "이름", + "PROJECT": "프로젝트", + "SPRINT": "스프린트", + "ASSIGNED_TO": "할당됨", + "STATUS": "상태", + "PROGRESS": "진행", + "VIEW_OPTIONS": "옵션 보기" + }, + "CREATE": { + "TITLE": "새로운 에픽 만들기", + "PLACEHOLDER_DESCRIPTION": "다른 사람들이 이 에픽에 대해 좀 더 쉽게 이해할 수 있도록 설명을 추가해주세요.", + "TEAM_REQUIREMENT": "팀 요구 사항", + "CLIENT_REQUIREMENT": "고객 요구 사항", + "BLOCKED": "차단됨", + "BLOCKED_NOTE_PLACEHOLDER": "왜 이 에픽이 차단되었나요?", + "CREATE_EPIC": "에픽 만들기" + } + }, + "PROJECTS": { + "PAGE_TITLE": "내 프로젝트 - 타이가", + "PAGE_DESCRIPTION": "프로젝트 목록입니다. 새 프로젝트를 만들거나 순서를 바꿀 수 있습니다.", + "MY_PROJECTS": "내 프로젝트" + }, + "ATTACHMENT": { + "SECTION_NAME": "첨부", + "TITLE": "{{ fileName }} 파일은 {{ date }}에 업로드되었습니다.", + "LIST_VIEW_MODE": "목록으로 보기", + "GALLERY_VIEW_MODE": "갤러리로 보기", + "DESCRIPTION": "간단한 설명을 입력하세요", + "DEPRECATED": "(지원 안함)", + "DEPRECATED_FILE": "더 이상 지원하지 않도록 할까요?", + "ADD": "첨부 파일 추가. {{maxFileSizeMsg}}", + "DROP": "여기에 첨부파일을 끌어 놓으세요!", + "SHOW_DEPRECATED": "+ 더 이상 필요 없는 첨부파일 보기", + "HIDE_DEPRECATED": "- 더 이상 필요 없는 첨부파일 숨기기", + "COUNT_DEPRECATED": "({{ counter }} 지원 안함)", + "MAX_UPLOAD_SIZE": "업로드 가능한 최대 용량은 {{maxFileSize}}", + "DATE": "YYYY MMM DD [at] hh:mm", + "ERROR_UPLOAD_ATTACHMENT": "'{{fileName}}'를 업로드할 수 없었습니다. {{errorMessage}}", + "TITLE_LIGHTBOX_DELETE_ATTACHMENT": "첨부파일 삭제하기", + "MSG_LIGHTBOX_DELETE_ATTACHMENT": "첨부 파일 '{{fileName}}'", + "ERROR_DELETE_ATTACHMENT": "삭제할 수 없었습니다: {{errorMessage}}", + "ERROR_MAX_SIZE_EXCEEDED": "우리 움파룸파에게 '{{fileName}}' ({{fileSize}}) 는 너무 커요. ({{maxFileSize}}) 보다 작은 크기로 다시 시도해주세요." + }, + "PAGINATION": { + "PREVIOUS": "이전", + "NEXT": "다음" + }, + "ADMIN": { + "COMMON": { + "TITLE_ACTION_EDIT_VALUE": "값 수정하기", + "TITLE_ACTION_DELETE_VALUE": "값 삭제하기", + "TITLE_ACTION_DELETE_TAG": "태그 삭제하기" + }, + "HELP": "도움이 필요하다면 고객 지원 페이지를 확인하세요", + "PROJECT_DEFAULT_VALUES": { + "TITLE": "기본 값", + "SUBTITLE": "선택된 모든 항목을 모두 초기값으로 설정" + }, + "MEMBERSHIPS": { + "TITLE": "회원 관리", + "PAGE_TITLE": "팀원 - {{projectName}}", + "ADD_BUTTON": "회원 추가하기", + "ADD_BUTTON_TITLE": "회원 추가하기", + "LIMIT_USERS_WARNING_MESSAGE_FOR_ADMIN": "안타깝게도, 프로젝트의 ({{members}}) 허용된 회원 수 제한에 도달했습니다. ", + "LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "이 프로젝트는 허용된 최대 회원 수 ({{members}}) 명에 도달하였습니다. 더 많은 최대 회원 수를 할당받고 싶다면 관리자에게 문의하세요." + }, + "PROJECT_EXPORT": { + "TITLE": "내보내기", + "SUBTITLE": "백업 혹은 새 프로젝트를 만들기 위해 현재 프로젝트의 데이터를 내 컴퓨터에 저장합니다. ", + "EXPORT_BUTTON": "내보내기", + "EXPORT_BUTTON_TITLE": "프로젝트 내보내기", + "LOADING_TITLE": "덤프 파일을 생성하고 있습니다.", + "DUMP_READY": "덤프 파일을 모두 만들었습니다.", + "LOADING_MESSAGE": "이 페이지를 닫지 마세요.", + "ASYNC_MESSAGE": "작업이 끝나면 이메일로 알려드릴게요.", + "SYNC_MESSAGE": "자동으로 다운로드가 시작되지 않는다면 여기를 클릭하세요.", + "ERROR": "움파룸파가 덤프 파일을 만들 수 없었습니다. 다시 한 번 시도해주세요.", + "ERROR_BUSY": "죄송해요. 움파룸파가 지금 좀 바쁘네요. 잠시 후에 다시 해주시겠어요?" + }, + "MODULES": { + "TITLE": "모듈", + "EPICS": "에픽", + "EPICS_DESCRIPTION": "프로젝트의 가장 전략적인 부분을 시각화하고 관리합니다.", + "BACKLOG": "백로그", + "BACKLOG_DESCRIPTION": "유저 스토리를 관리하여 다가오는 작업과 우선 순위가 지정된 작업을 체계적으로 볼 수 있습니다.", + "NUMBER_SPRINTS": "예상되는 스프린트 의 갯수", + "NUMBER_SPRINTS_HELP": "정하지 않으려면 0을 입력합니다.", + "NUMBER_US_POINTS": "예상되는 총 스토리 포인트", + "NUMBER_US_POINTS_HELP": "정하지 않으려면 0을 입력합니다.", + "KANBAN": "칸반", + "KANBAN_DESCRIPTION": "이 칸반을 이용해 프로젝트를 효율적으로 만듭시다.", + "ISSUES": "이슈", + "ISSUES_DESCRIPTION": "프로젝트와 관련된 버그와 질문 및 개선 사항을 추적하십시오. 그 무엇도 놓치지 마세요!", + "WIKI": "위키", + "WIKI_DESCRIPTION": "다른 사람들과 공동으로 콘텐츠를 추가, 수정 또는 삭제합니다. 프로젝트 문서화에 적합합니다.", + "MEETUP": "미팅", + "MEETUP_DESCRIPTION": "당신의 화상회의 시스템을 선택하세요.", + "SELECT_VIDEOCONFERENCE": "화상 회의 시스템 선택", + "SALT_CHAT_ROOM": "채팅방 이름에 머릿말 추가", + "JITSI_CHAT_ROOM": "Jitsi", + "APPEARIN_CHAT_ROOM": "AppearIn", + "TALKY_CHAT_ROOM": "Talky", + "CUSTOM_CHAT_ROOM": "사용자 정의 ", + "URL_CHAT_ROOM": "채팅방 URL" + }, + "PROJECT_PROFILE": { + "PAGE_TITLE": "{{sectionName}} - 프로젝트 프로필 - {{projectName}}", + "PROJECT_DETAILS": "프로젝트 세부사항", + "PROJECT_NAME": "프로젝트 이름", + "TAGS": "태그", + "DESCRIPTION": "설명", + "RECRUITING": "이 프로젝트에 다른 사람이 필요합니까?", + "RECRUITING_MESSAGE": "누구를 찾고 계십니까?", + "RECRUITING_PLACEHOLDER": "찾고 있는 프로파일을 정의하십시오.", + "FEEDBACK": "타이가사용자들로부터 피드백을 받으시겠습니까?", + "PUBLIC_PROJECT": "공개된 프로젝트", + "PRIVATE_PROJECT": "비공개 프로젝트", + "PRIVATE_OR_PUBLIC": "공공 프로젝트와 비공개 프로젝트의 차이점은 무엇입니까?", + "DELETE": "프로젝트 삭제하기", + "CHANGE_LOGO": "로고 변경하기", + "ACTION_USE_DEFAULT_LOGO": "기본 이미지 사용", + "MAX_PRIVATE_PROJECTS": "당신에게 적용된 설정에서 허용하는 최대 비공개 프로젝트 수에 도달했습니다.", + "MAX_PRIVATE_PROJECTS_MEMBERS": "비공개 프로젝트의 최대 회원수를 초과하였습니다.", + "MAX_PUBLIC_PROJECTS": "안타깝게도 당신에게 설정된 최대 공공 프로젝트 갯수에 도달하였습니다.", + "MAX_PUBLIC_PROJECTS_MEMBERS": "프로젝트가 공개 프로젝트의 최대 회원 수를 초과했습니다.", + "PROJECT_OWNER": "프로젝트 소유자", + "REQUEST_OWNERSHIP": "소유권 요청", + "REQUEST_OWNERSHIP_CONFIRMATION_TITLE": "새 프로젝트의 소유자가 되고 싶습니까?", + "REQUEST_OWNERSHIP_DESC": "현재 프로젝트 소유자 {{name}}에게 이 프로젝트의 소유권을 당신에게 양도하도록 요청합니다.", + "REQUEST_OWNERSHIP_BUTTON": "요청하기", + "REQUEST_OWNERSHIP_SUCCESS": "프로젝트 소유자에게 알립니다.", + "CHANGE_OWNER": "소유자 변경하기", + "CHANGE_OWNER_SUCCESS_TITLE": "당신의 요청이 전송되었습니다!", + "CHANGE_OWNER_SUCCESS_DESC": "프로젝트 소유권 요청이 수락되거나 거부되면 이메일로 알려드립니다." + }, + "REPORTS": { + "TITLE": "보고서", + "SUBTITLE": "프로젝트 데이터를 CSV 형태로 내보낸 다음 여러분만의 보고서를 만들어 보세요.", + "DESCRIPTION": "CSV 파일을 다운로드하거나 생성 된 URL을 복사하여 원하는 텍스트 편집기 또는 스프레드 시트에서 프로젝트 데이터 보고서를 만듭니다. 모든 데이터를 쉽게 시각화하고 분석 할 수 있습니다.", + "HELP": "이걸 스프레드 시트에서 사용하는 방법이 무엇인가요?", + "REGENERATE_TITLE": "URL 변경하기", + "REGENERATE_SUBTITLE": "CSV 데이터 접근 URL을 변경하려고 합니다. 이전 URL은 비활성화 될 것입니다. 변경하시겠습니까?" + }, + "CSV": { + "SECTION_TITLE_EPIC": "에픽 보고서", + "SECTION_TITLE_US": "유저 스토리 보고서", + "SECTION_TITLE_TASK": "태스크 보고서", + "SECTION_TITLE_ISSUE": "이슈 보고서", + "DOWNLOAD": "CSV 다운로드", + "URL_FIELD_PLACEHOLDER": "CSV url을 다시 생성하세요", + "TITLE_REGENERATE_URL": "CSV url 재생성하기", + "ACTION_GENERATE_URL": "URL 생성하기", + "ACTION_REGENERATE": "재생성" + }, + "CUSTOM_FIELDS": { + "TITLE": "사용자 정의 필드", + "SUBTITLE": "유저 스토리, 태스크 그리고 이슈를 위한 사용자 정의 필드를 지정하세요.", + "EPIC_DESCRIPTION": "에픽 사용자 정의 필드", + "EPIC_ADD": "에픽에 사용자 정의 필드 추가", + "US_DESCRIPTION": "유저 스토리의 사용자 정의 필드", + "US_ADD": "유저 스토리에 사용자 정의 필드 추가하기", + "TASK_DESCRIPTION": "태스크의 사용자 정의 필드", + "TASK_ADD": "태스크에 사용자 정의 필드 추가하기", + "ISSUE_DESCRIPTION": "이슈의 사용자 정의 필드", + "ISSUE_ADD": "이슈에 사용자 정의 필드 추가하기", + "FIELD_TYPE_TEXT": "텍스트", + "FIELD_TYPE_RICHTEXT": "서식있는 텍스트", + "FIELD_TYPE_MULTI": "여러 줄", + "FIELD_TYPE_DATE": "날짜", + "FIELD_TYPE_URL": "Url" + }, + "PROJECT_VALUES": { + "PAGE_TITLE": "{{sectionName}} - 프로젝트 값들 - {{projectName}}", + "REPLACEMENT": "이 값을 가진 모든 아이템들의 값을 다음으로 변경합니다.", + "ERROR_DELETE_ALL": "최소한 한 개의 값은 남겨두어야 합니다." + }, + "PROJECT_VALUES_POINTS": { + "TITLE": "포인트", + "SUBTITLE": "유저 스토리의 포인트를 추산하세요.", + "US_TITLE": "유저 스토리 포인트", + "ACTION_ADD": "새 포인트 추가하기" + }, + "PROJECT_VALUES_PRIORITIES": { + "TITLE": "우선순위", + "SUBTITLE": "이슈의 우선순위를 지정하세요.", + "ISSUE_TITLE": "이슈 우선순위", + "ACTION_ADD": "우선순위 추가하기" + }, + "PROJECT_VALUES_SEVERITIES": { + "TITLE": "심각도", + "SUBTITLE": "이슈에 대한 심각도를 지정하세요.", + "ISSUE_TITLE": "이슈 심각도", + "ACTION_ADD": "심각도 추가하기" + }, + "PROJECT_VALUES_STATUS": { + "TITLE": "Statuses", + "SUBTITLE": "유저 스토리, 태스크 그리고 이슈의 상태를 지정하세요.", + "EPIC_TITLE": "에픽 상태", + "US_TITLE": "유저 스토리 상태", + "TASK_TITLE": "태스크 상태", + "ISSUE_TITLE": "이슈 상태" + }, + "PROJECT_VALUES_TYPES": { + "TITLE": "타입", + "SUBTITLE": "이슈의 종류를 지정하세요.", + "ISSUE_TITLE": "이슈 타입", + "ACTION_ADD": "{{objName}} 새로 추가하기" + }, + "PROJECT_VALUES_TAGS": { + "TITLE": "태그", + "SUBTITLE": "태그를 보고 색을 변경하세요.", + "EMPTY": "태그가 없습니다.", + "EMPTY_SEARCH": "검색 기준에 아무 것도 발견되지 않았습니다.", + "ACTION_ADD": "태그 추가하기", + "NEW_TAG": "새로운 태그", + "MIXING_HELP_TEXT": "병합하기 원하는 태그를 선택하세요.", + "MIXING_MERGE": "태그 병합", + "SELECTED": "선택됨" + }, + "ROLES": { + "PAGE_TITLE": "역할 - {{projectName}}", + "WARNING_NO_ROLE": "주의하세요, 현재 프로젝트에 유저 스토리의 포인트를 산정할 수 있는 역할이 없습니다.", + "HELP_ROLE_ENABLED": "사용하도록 설정하면, 회원들에게 이 역할이 할당되었을 때 유저 스토리의 포인트 값을 예측할 수 있습니다.", + "DISABLE_COMPUTABLE_ALERT_TITLE": "이 역할의 예측 기능을 비활성화 하시겠습니까?", + "DISABLE_COMPUTABLE_ALERT_SUBTITLE": "만약 {{roleName}} 역할에 대한 평가 권한을 비활성화 했다면, 이 역할로 수행한 모든 평가는 삭제될 것입니다.", + "COUNT_MEMBERS": "{{ role.members_count }} 명의 회원이 이 역할을 가지고 있습니다.", + "TITLE_DELETE_ROLE": "역할 삭제하기", + "REPLACEMENT_ROLE": "이 역할의 모든 사용자들은 다음의 역할로 변경됨", + "WARNING_DELETE_ROLE": "조심하세요! 모든 역할 예측이 삭제됩니다.", + "ERROR_DELETE_ALL": "최소한 한 개의 값은 남겨두어야 합니다.", + "EXTERNAL_USER": "외부 사용자" + }, + "THIRD_PARTIES": { + "SECRET_KEY": "비밀 키", + "PAYLOAD_URL": "Payload URL", + "VALID_IPS": "유효한 원본 IP (콤마','로 구분)" + }, + "BITBUCKET": { + "SECTION_NAME": "Bitbucket", + "PAGE_TITLE": "Bitbucket - {{projectName}}", + "INFO_VERIFYING_IP": "Bitbucket 요청은 IP를 이용해서 출처를 확인하는 방법으로 서명되지 않았습니다. 필드가 비어있을 경우, IP 유효성 검증이 되지 않습니다." + }, + "GITLAB": { + "SECTION_NAME": "Gitlab", + "PAGE_TITLE": "Gitlab - {{projectName}}", + "INFO_VERIFYING_IP": "Gitlab 요청은 IP를 이용해서 출처를 확인하는 방법으로 서명되지 않았습니다. 필드가 비어있을 경우, IP 유효성 검증이 되지 않습니다." + }, + "GITHUB": { + "SECTION_NAME": "GitHub", + "PAGE_TITLE": "GitHub - {{projectName}}" + }, + "GOGS": { + "SECTION_NAME": "Gogs", + "PAGE_TITLE": "Gogs - {{projectName}}" + }, + "WEBHOOKS": { + "PAGE_TITLE": "웹훅 - {{projectName}}", + "SECTION_NAME": "웹훅", + "ADD_NEW": "웹훅 추가하기", + "TYPE_NAME": "서비스 이름을 입력해 주세요", + "TYPE_PAYLOAD_URL": "서비스 주소를 입력하세요", + "TYPE_SERVICE_SECRET": "서비스 시크릿 키를 입력해 주세요", + "SAVE": "웹훅 저장하기", + "CANCEL": "웹훅 취소하기", + "SHOW_HISTORY": "(이력 보기)", + "TEST": "웹훅 테스트하기", + "EDIT": "웹훅 수정하기", + "DELETE": "웹훅 삭제하기", + "REQUEST": "요청하기", + "RESEND_REQUEST": "요청 재전송하기", + "HEADERS": "헤더", + "PAYLOAD": "Payload", + "RESPONSE": "응답하기", + "DATE": "YYYY MMM DD [at] hh:mm:ss", + "ACTION_HIDE_HISTORY": "(이력 숨기기)", + "ACTION_HIDE_HISTORY_TITLE": "상세 이력 숨기기", + "ACTION_SHOW_HISTORY": "(이력 보기)", + "ACTION_SHOW_HISTORY_TITLE": "상세 이력 보기", + "WEBHOOK_NAME": "웹훅 '{{name}}'" + }, + "CUSTOM_ATTRIBUTES": { + "PAGE_TITLE": "{{sectionName}} - 사용자 정의 속성 - {{projectName}}", + "ADD": "사용자 정의 필드 추가하기", + "EDIT": "사용자 정의 필드 수정하기", + "DELETE": "사용자 정의 필드 삭제하기", + "SAVE_TITLE": "사용자 정의 필드 저장하기", + "CANCEL_TITLE": "만들기 취소 하기", + "SET_FIELD_NAME": "사용자 정의 필드의 이름을 설정하세요", + "SET_FIELD_DESCRIPTION": "사용자 정의 필드에 대한 설명을 넣으세요", + "FIELD_TYPE_DEFAULT": "-- 하나를 고르세요 --", + "ACTION_UPDATE": "사용자 정의 필드 업데이트하기", + "ACTION_CANCEL_EDITION": "수정 내역 취소하기" + }, + "MEMBERSHIP": { + "COLUMN_MEMBER": "회원", + "COLUMN_ADMIN": "관리자", + "COLUMN_ROLE": "역할", + "COLUMN_STATUS": "상태", + "STATUS_ACTIVE": "활성상태", + "STATUS_PENDING": "보류 중", + "DELETE_MEMBER": "회원 삭제하기", + "RESEND": "다시 보내기", + "SUCCESS_SEND_INVITATION": "'{{email}}' 님에게 다시 초대장을 보냈습니다.", + "SUCCESS_DELETE": "{{message}} 를 지웠습니다.", + "ERROR_DELETE": "{{message}} 를 지울 수 없었습니다.", + "DEFAULT_DELETE_MESSAGE": "{{email}} 초대하기" + }, + "DEFAULT_VALUES": { + "LABEL_EPIC_STATUS": "에픽 상태의 기본값", + "LABEL_US_STATUS": "유저 스토리 상태의 기본 값", + "LABEL_POINTS": "포인트의 기본 값", + "LABEL_TASK_STATUS": "태스크 상태의 기본 값", + "LABEL_ISSUE_TYPE": "이슈 종류의 기본 값", + "LABEL_ISSUE_STATUS": "이슈 상태의 기본 값", + "LABEL_PRIORITY": "우선순위의 기본 값", + "LABEL_SEVERITY": "심각도의 기본 값" + }, + "STATUS": { + "PLACEHOLDER_WRITE_STATUS_NAME": "새 상태의 이름을 입력하세요" + }, + "TYPES": { + "PLACEHOLDER_WRITE_NAME": "새 엘리먼트의 이름을 입력하세요" + }, + "US_STATUS": { + "ACTION_ADD_STATUS": "상태 추가하기", + "IS_ARCHIVED_COLUMN": "보관됨", + "IS_CLOSED_COLUMN": "완료함", + "WIP_LIMIT_COLUMN": "동시 진행 제한 갯수", + "PLACEHOLDER_WRITE_NAME": "새 상태의 이름을 입력하세요" + }, + "MENU": { + "PROJECT": "프로젝트", + "ATTRIBUTES": "속성", + "MEMBERS": "회원", + "PERMISSIONS": "권한", + "INTEGRATIONS": "연동" + }, + "SUBMENU_PROJECT_VALUES": { + "STATUS": "상태", + "POINTS": "포인트", + "PRIORITIES": "우선순위", + "SEVERITIES": "심각도", + "TYPES": "타입", + "CUSTOM_FIELDS": "사용자 정의 필드", + "TAGS": "태그" + }, + "SUBMENU_ROLES": { + "TITLE": "역할", + "ACTION_NEW_ROLE": "역할 추가하기", + "TITLE_ACTION_NEW_ROLE": "역할 추가하기" + }, + "PROJECT_TRANSFER": { + "DO_YOU_ACCEPT_PROJECT_OWNERNSHIP": "새 프로젝트의 소유자가 되고 싶습니까?", + "PRIVATE": "비공개", + "ACCEPTED_PROJECT_OWNERNSHIP": "축하합니다! 새로운 프로젝트의 소유자가 되었습니다.", + "REJECTED_PROJECT_OWNERNSHIP": "네. 이 프로젝트 소유자에게 연락하겠습니다.", + "ACCEPT": "확인", + "REJECT": "거절", + "PROPOSE_OWNERSHIP": "{{owner}}가 자신이 소유한 프로젝트 {{project}}의 새로운 소유자가 될 수 있는지 제안하였습니다.", + "ADD_COMMENT": "프로젝트 소유자에 대한 의견을 추가 하시겠습니까?", + "UNLIMITED_PROJECTS": "제한 없음", + "OWNER_MESSAGE": { + "PRIVATE": "{{maxProjects}}개의 비공개 프로젝트를 소유 할 수 있음을 기억하십시오. 현재 당신은 {{currentProjects}}개의 비공개 프로젝트를 소유하고 있습니다.", + "PUBLIC": "{{maxProjects}}개의 공공 프로젝트를 소유 할 수 있음을 기억하십시오. 현재 당신은 {{currentProjects}}개의 공공 프로젝트를 소유하고 있습니다." + }, + "CANT_BE_OWNED": "현재 이 유형의 프로젝트 소유자가 될 수 없습니다. 이 프로젝트의 소유자가되고 싶다면 관리자에게 문의하여 프로젝트 소유권을 사용하도록 계정 설정을 변경하십시오." + } + }, + "USER": { + "PROFILE": { + "PAGE_TITLE": "{{userFullName}} (@{{userUsername}})", + "EDIT": "프로필 수정하기", + "CLOSED_US": "완료한 유저 스토리", + "PROJECTS": "프로젝트", + "PROJECTS_EMPTY": "{{username}} 님은 아직 프로젝트가 없습니다", + "CONTACTS": "연락처", + "CONTACTS_EMPTY": "{{username}} 님은 연락처가 없습니다", + "CURRENT_USER_CONTACTS_EMPTY": "연락처가 없습니다", + "CURRENT_USER_CONTACTS_EMPTY_EXPLAIN": "타이가에서 일하는 사람들은 자동으로 당신의 연락처가 됩니다.", + "TABS": { + "ACTIVITY_TAB": "타임라인", + "ACTIVITY_TAB_TITLE": "이 사용자의 전체 액티비티 보기", + "PROJECTS_TAB": "프로젝트", + "PROJECTS_TAB_TITLE": "이 사용자가 참여하는 모든 프로젝트 목록", + "LIKES_TAB": "좋아요", + "LIKES_TAB_TITLE": "이 사용자의 모든 좋아요 목록", + "VOTES_TAB": "투표", + "VOTES_TAB_TITLE": "이 사용자가 투표한 모든 투표 목록 보기", + "WATCHED_TAB": "구독", + "WATCHED_TAB_TITLE": "이 사용자가 구독중인 모든 목록 보기", + "CONTACTS_TAB": "연락처", + "CONTACTS_TAB_TITLE": "이 사용자가 만든 모든 연락처 목록" + } + }, + "PROFILE_SIDEBAR": { + "TITLE": "프로필", + "DESCRIPTION": "당신이 하는 모든 것, 그리고 당신이 어떤 일을 하고 있는 지 사람들이 몽땅 볼 수 있어요. 당신을 알릴 수 있는 멋진 소개를 추가하세요.", + "ADD_INFO": "이력 수정하기" + }, + "PROFILE_FAVS": { + "FILTER_INPUT_PLACEHOLDER": "아무거나 입력하세요...", + "FILTER_TYPE_ALL": "전체", + "FILTER_TYPE_ALL_TITLE": "모두 보기", + "FILTER_TYPE_PROJECTS": "프로젝트", + "FILTER_TYPE_PROJECTS_TITLE": "프로젝트만 보기", + "FILTER_TYPE_EPICS": "에픽", + "FILTER_TYPE_EPICS_TITLE": "에픽만 보기", + "FILTER_TYPE_USER_STORIES": "스토리", + "FILTER_TYPE_USER_STORIES_TITLE": "유저 스토리만 보기", + "FILTER_TYPE_TASKS": "태스크", + "FILTER_TYPE_TASKS_TITLE": "태스크만 보기", + "FILTER_TYPE_ISSUES": "이슈", + "FILTER_TYPE_ISSUES_TITLE": "이슈만 보기", + "EMPTY_TITLE": "여기엔 보여 줄 수 있는게 하나도 없네요." + } + }, + "PROJECT": { + "PAGE_TITLE": "{{projectName}}", + "HELP": "자주 사용하는 프로젝트들을 상위로 올려보세요.
상위 10개 프로젝트는 내비게이션 바의 프로젝트 목록에 나타납니다.", + "PRIVATE": "비공개 프로젝트", + "LOOKING_FOR_PEOPLE": "이 프로젝트는 사람을 찾고 있습니다.", + "FANS_COUNTER_TITLE": "{total, plural, one{one fan} other{# 명의 좋아요}}", + "WATCHERS_COUNTER_TITLE": "{total, plural, one{one watcher} other{# 명이 구독중}}", + "MEMBERS_COUNTER_TITLE": "{total, plural, one{one member} other{# 명의 회원}}", + "BLOCKED_PROJECT": { + "BLOCKED": "차단된 프로젝트", + "THIS_PROJECT_IS_BLOCKED": "이 프로젝트는 임시로 차단되었습니다.", + "TO_UNBLOCK_CONTACT_THE_ADMIN_STAFF": "프로젝트의 차단을 해제하려면 관리자에게 문의하십시오." + }, + "SECTION": { + "SEARCH": "검색", + "TIMELINE": "타임라인", + "BACKLOG": "백로그", + "KANBAN": "칸반", + "ISSUES": "이슈", + "WIKI": "위키", + "TEAM": "팀", + "MEETUP": "미팅", + "ADMIN": "관리자" + }, + "NAVIGATION": { + "ACTION_CREATE_PROJECT": "프로젝트 생성하기", + "MANAGE_PROJECTS": "프로젝트 관리하기", + "TITLE_CREATE_PROJECT": "프로젝트 생성하기", + "HELP_TITLE": "타이가 고객 지원 페이지", + "HELP": "도움말", + "HOMEPAGE": "홈페이지", + "FEEDBACK_TITLE": "피드백 보내기", + "FEEDBACK": "피드백", + "NOTIFICATIONS_TITLE": "알림 설정 수정", + "NOTIFICATIONS": "알림", + "VIEW_PROFILE_TITLE": "프로필 보기", + "VIEW_PROFILE": "프로필 보기", + "EDIT_PROFILE_TITLE": "프로필 수정하기", + "EDIT_PROFILE": "프로필 수정하기", + "CHANGE_PASSWORD_TITLE": "비밀번호 변경하기", + "CHANGE_PASSWORD": "비밀번호 변경하기", + "DASHBOARD_TITLE": "대시보드", + "DISCOVER_TITLE": "트렌드 프로젝트 찾기", + "DISCOVER": "찾기" + }, + "LIKE_BUTTON": { + "LIKE": "좋아요", + "LIKED": "좋아함", + "UNLIKE": "좋아요 취소", + "BUTTON_TITLE": "이 프로젝트를 좋아요 또는 좋아요 취소", + "COUNTER_TITLE": "{total, plural, one{one fan} other{# 명의 좋아요}}" + }, + "WATCH_BUTTON": { + "BUTTON_TITLE": "이 프로젝트를 구독하고 알림 정책 설정하기", + "WATCH": "구독", + "WATCHING": "구독중", + "COUNTER_TITLE": "{total, plural, one{one watcher} other{# 명이 구독중}}", + "OPTIONS": { + "NOTIFY_ALL": "모든 공지 받기", + "NOTIFY_ALL_TITLE": "이 프로젝트에 대한 모든 공지 받기", + "NOTIFY_INVOLVED": "내가 관련된 경우에만", + "NOTIFY_INVOLVED_TITLE": "연관된 경우에만 공지 받기", + "UNWATCH": "구독 취소", + "UNWATCH_TITLE": "이 프로젝트의 구독 취소" + } + }, + "CONTACT_BUTTON": { + "CONTACT_TITLE": "프로젝트 팀 문의", + "CONTACT_BUTTON": "프로젝트 문의" + }, + "CREATE": { + "TITLE": "프로젝트 생성하기", + "CHOOSE_TEMPLATE": "Which template fits your project better?", + "TEMPLATE_SCRUM": "스크럼", + "TEMPLATE_SCRUM_DESC": "Prioritize and solve your tasks in short time cycles.", + "TEMPLATE_SCRUM_LONGDESC": "Scrum is an iterative and incremental agile software development methodology for managing product development.\nThe product backlog is what will ultimately be delivered, ordered into the sequence in which it should be delivered. Product Backlogs are broken into manageable, executable chunks named sprints. Every certain amount of time the team initiates a new sprint and commits to deliver a certain number of user stories from the backlog, in accordance with their skills, abilities and resources. The project advances as the backlog becomes depleted.", + "TEMPLATE_KANBAN": "칸반", + "TEMPLATE_KANBAN_DESC": "Keep a constant workflow on independent tasks", + "TEMPLATE_KANBAN_LONGDESC": "The Kanban methodology is used to divide project development (any sort of project) into stages.\nA kanban card is like an index card or post-it note that details every task (or user story) in a project that needs to be completed. The Kanban board is used to move each card from one state of completion to the next and in so doing, helps track progress.", + "DUPLICATE": "Duplicate project", + "DUPLICATE_DESC": "Start clean and keep your configuration", + "IMPORT": "프로젝트 불러오기", + "IMPORT_DESC": "Import your project from multiple platforms into Taiga", + "INVITE": "Invite to the project", + "SOLO_PROJECT": "You'll be alone in this project", + "INVITE_LATER": "(You'll be able to invite more members later)", + "BACK": "이전", + "MAX_PRIVATE_PROJECTS": "Unfortunately, You've reached the maximum number of private projects.\nIf you would like to increase the current limit please contact the administrator.", + "MAX_PUBLIC_PROJECTS": "Unfortunately, You've reached the maximum number of public projects.\nIf you would like to increase the current limit please contact the administrator.", + "PUBLIC_PROJECT": "공개된 프로젝트", + "PRIVATE_PROJECT": "비공개 프로젝트" + }, + "COMMON": { + "DETAILS": "New project details", + "PROJECT_TITLE": "Project Name", + "PROJECT_DESCRIPTION": "Project Description" + }, + "DUPLICATE": { + "TITLE": "Duplicate Project", + "DESCRIPTION": "Start clean and keep your configuration", + "SELECT_PLACEHOLDER": "Choose an existing project to duplicate" + }, + "IMPORT": { + "TITLE": "Import Project", + "DESCRIPTION": "Import your project from multiple platforms into Taiga", + "ASYNC_IN_PROGRESS_TITLE": "움파룸파가 프로젝트를 불러오고 있습니다.", + "ASYNC_IN_PROGRESS_MESSAGE": "이 작업은 몇 분 정도 걸립니다.
작업이 끝나면 이메일로 알려드릴게요.", + "UPLOAD_IN_PROGRESS_MESSAGE": "{{totalSize}} 중 {{uploadedSize}} 만큼 업로드했습니다", + "ERROR": "움파룸파가 덤프 파일을 불러올 수 없습니다. 다시 한 번 시도해주세요.", + "ERROR_TOO_MANY_REQUEST": "죄송해요. 움파룸파가 지금 좀 바쁘네요. 잠시 후에 다시 해주시겠어요?", + "ERROR_MESSAGE": "움파룸파가 덤프 파일을 불러올 수 없습니다. 다시 한 번 시도해주세요. {{error_message}}", + "ERROR_MAX_SIZE_EXCEEDED": "우리 움파룸파에게 '{{fileName}}' ({{fileSize}}) 는 너무 커요. ({{maxFileSize}}) 보다 작은 크기로 다시 시도해주세요.", + "SYNC_SUCCESS": "프로젝트를 불러오는 데 성공했습니다.", + "IMPORT": "Import", + "WHO_IS": "Their tasks will be assigned to ...", + "WRITE_EMAIL": "Or if you want, write the email that this user uses in Taiga", + "SEARCH_CONTACT": "Or if you want, search in your contacts", + "WRITE_EMAIL_LABEL": "Write the email that this user uses in Taiga", + "ACCEEDE": "Acceede", + "PROJECT_MEMBERS": "프로젝트 회원", + "PROCESS_DESCRIPTION": "Tell us who from Taiga you want to assign the tasks of {{platform}}", + "MATCH": "Is {{user_external}} the same person as {{user_internal}}?", + "CHOOSE": "Select user", + "LINKS": "Links with {{platform}}", + "LINKS_DESCRIPTION": "Do you want to keep the link of each item with the original {{platform}} card?", + "WARNING_MAIL_USER": "Note that if the user does not have a Taiga account we will not be able to assign the tasks to him.", + "ASSIGN": "할당", + "PROJECT_SELECTOR": { + "NO_RESULTS": "검색 기준에 아무 것도 발견되지 않았습니다.", + "ACTION_SEARCH": "검색하기", + "ACTION_BACK": "이전" + }, + "PROJECT_RESTRICTIONS": { + "PROJECT_MEMBERS_DESC_PRIVATE": "The project you are trying to import has {{members}} members including you, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per private project. If you would like to increase that limit please contact the administrator.", + "PROJECT_MEMBERS_DESC_PUBLIC": "The project you are trying to import has {{members}} members including you, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per public project. If you would like to increase that limit please contact the administrator.", + "ACCOUNT_ALLOW_MEMBERS": "Your account only allows {{members}} members", + "PRIVATE_PROJECTS_SPACE": { + "TITLE": "안타깝게도, 당신의 설정에는 추가 비공개 프로젝트가 허용되어있지 않습니다.", + "DESC": "가져오기하려는 프로젝트가 비공개 되어있습니다. 안타깝게도, 현재 당신의 설정에는 추가 비공개 프로젝트가 허용되어있지 않습니다." + }, + "PUBLIC_PROJECTS_SPACE": { + "TITLE": "안타깝게도, 당신의 현재 설정에는 추가 공공 프로젝트가 허용되어있지 않습니다.", + "DESC": "가져오기 하려는 프로젝트는 공공 프로젝트입니다. 안타깝게도, 당신의 현재 섲렁에는 추가 공공 프로젝트가 허용되어있지 않습니다." + }, + "PRIVATE_PROJECTS_MEMBERS": { + "TITLE": "현재 당신의 설정으로는 비공개 프로젝트 당 최대 {{max_memberships}} 명의 회원을 수용할 수 있습니다." + }, + "PUBLIC_PROJECTS_MEMBERS": { + "TITLE": "현재 당신의 설정으로는 공개 프로젝트 당 최대 {{max_memberships}} 명의 회원을 수용할 수 있습니다." + }, + "PRIVATE_PROJECTS_SPACE_MEMBERS": { + "TITLE": "안타깝게도 현재 당신의 설정으로는 추가 비공개 프로젝트가 허용되지 않았거나 비공개 프로젝트 당 {{max_memberships}} 명 이상의 회원을 수용할 수 없도록 되어있습니다.", + "DESC": "가져오기 하려는 프로젝트가 비공개이며 {{members}} 명의 회원이 있습니다." + }, + "PUBLIC_PROJECTS_SPACE_MEMBERS": { + "TITLE": "안타깝게도 현재 당신의 설정으로는 추가 공개 프로젝트가 허용되지 않았거나 공개 프로젝트 당 {{max_memberships}} 명 이상의 회원을 수용할 수 없도록 되어있습니다.", + "DESC": "가져오기 하려는 프로젝트는 공개되어있으며 {{members}} 이상의 회원이 존재합니다." + } + }, + "IN_PROGRESS": { + "TITLE": "프로젝트 불러오기", + "DESCRIPTION": "이 과정은 시간이 걸릴 수 있습니다. 이 창을 닫지 마세요." + }, + "WARNING": { + "TITLE": "Some taks will be unassigned", + "DESCRIPTION": "There are still unidentified people. The cards assigned to these people will remain unassigned. Check all the contacts to not lose that information.", + "CHECK": "Check contacts" + }, + "TAIGA": { + "SELECTOR": "Import your Taiga project" + }, + "TRELLO": { + "SELECTOR": "Import your Trello boards into Taiga", + "CHOOSE_PROJECT": "Choose board that you want to import", + "NO_PROJECTS": "It seems you have no boards in Trello" + }, + "GITHUB": { + "SELECTOR": "Import your GitHub project issues", + "CHOOSE_PROJECT": "Find the project you want to import", + "NO_PROJECTS": "It seems you have no porjects in GitHub", + "HOW_DO_YOU_WANT_TO_IMPORT": "How do you want to import your issues into Taiga?", + "KANBAN_PROJECT": "As user stories in a kanban project", + "KANBAN_PROJECT_DESCRIPTION": "After that you can enable scrum with backlog.", + "SCRUM_PROJECT": "As user stories in a scrum project", + "SCRUM_PROJECT_DESCRIPTION": "After that you can enable kanban mode.", + "ISSUES_PROJECT": "As issues", + "ISSUES_PROJECT_DESCRIPTION": "You will not be able to use your issues in kanban or scrum mode. You will be able to enable kanban or scrum for new user stories" + }, + "ASANA": { + "SELECTOR": "Import your Asana project and choose how to manage it", + "CHOOSE_PROJECT": "Choose project that you want to import", + "NO_PROJECTS": "It seems you have no porjects in Asana", + "KANBAN_PROJECT": "칸반", + "SCRUM_PROJECT": "스크럼", + "CREATE_AS_SCRUM_DESCRIPTION": "The tasks and sub-tasks of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_KANBAN_DESCRIPTION": "The tasks and sub-tasks of your project will be created as Taiga user stories and tasks." + }, + "JIRA": { + "SELECTOR": "Import your Jira project and choose how to manage it", + "CHOOSE_PROJECT": "Choose project or board that you want to import", + "NO_PROJECTS": "It seems you have no porjects or boards in Jira", + "URL": "Your Jira URL", + "KANBAN_PROJECT": "칸반", + "SCRUM_PROJECT": "스크럼", + "ISSUES_PROJECT": "이슈", + "CREATE_AS_SCRUM_DESCRIPTION": "The issues and sub-issues of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_KANBAN_DESCRIPTION": "The issues and sub-issues of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_ISSUES_DESCRIPTION": "What do you want to do with sub-issues from the Jira project? (Taiga doesn't allow sub-issues)", + "CREATE_NEW_ISSUES": "Convert sub-issues to new Taiga issues", + "NOT_CREATE_NEW_ISSUES": "Do not import sub-issues" + } + } + }, + "LIGHTBOX": { + "DELETE_ACCOUNT": { + "CONFIRM": "타이가 계정을 정말로 삭제하시겠어요?", + "CANCEL": "설정으로 돌아가기", + "ACCEPT": "계정 삭제", + "BLOCK_PROJECT": "계정을 삭제한 후에는 당신이 소유하고 있는 모든 프로젝트가 차단됩니다. 이걸 원치 않으시면, 계정을 삭제하기 전에 프로젝트 소유권을 다른 회원에게 넘겨주세요." + }, + "DELETE_PROJECT": { + "TITLE": "프로젝트 삭제하기", + "QUESTION": "프로젝트를 정말 삭제하시려고요?", + "SUBTITLE": "모든 프로젝트 데이터(유저 스토리, 태스크, 이슈, 스프린트, 위키)가 사라질 겁니다. :-(", + "CONFIRM": "네. 진심으로 원해요." + }, + "ASSIGNED_TO": { + "SELECT": "다음 사람에게 할당", + "SEARCH": "사용자 검색" + }, + "ADD_MEMBER": { + "TITLE": "새 회원", + "PLACEHOLDER": "사용자를 필터링하거나 초대할 이메일 쓰기", + "ADD_EMAIL": "이메일 추가", + "REMOVE": "삭제", + "INVITE": "초대", + "CHOOSE_ROLE": "역할 선택", + "PLACEHOLDER_INVITATION_TEXT": "(선택사항) 초대장에 특별한 메시지를 적으세요. 새로운 회원에게 멋진 말을 전해주세요 ;-)", + "HELP_TEXT": "타이가에 이미 등록한 사용자라면 자동으로 프로젝트에 추가될 겁니다. 등록하지 않은 사용자라면 초대장이 발송됩니다." + }, + "CREATE_ISSUE": { + "TITLE": "이슈 추가하기" + }, + "FEEDBACK": { + "TITLE": "말해주세요...", + "COMMENT": "... 버그, 몇 가지 제안, 멋진 것 ... 아니면 타이가와의 최악의 악몽", + "ACTION_SEND": "피드백 보내기" + }, + "SEARCH": { + "TITLE": "검색", + "PLACEHOLDER_SEARCH": "무엇을 찾고 있나요?" + }, + "ADD_EDIT_SPRINT": { + "TITLE": "다음 스프린트", + "PLACEHOLDER_SPRINT_NAME": "스프린트 이름", + "PLACEHOLDER_SPRINT_START": "예정된 시작일", + "PLACEHOLDER_SPRINT_END": "예정된 종료일", + "ACTION_DELETE_SPRINT": "이 스프린트를 삭제하시려고요?", + "TITLE_ACTION_DELETE_SPRINT": "스프린트 삭제하기", + "LAST_SPRINT_NAME": "마지막 스프린트는 {{lastSprint}} 입니다 ;-)" + }, + "CREATE_EDIT_TASK": { + "TITLE": "태스크", + "PLACEHOLDER_SUBJECT": "태스크 주제", + "PLACEHOLDER_STATUS": "태스크 상태", + "OPTION_UNASSIGNED": "할당되지 않음", + "PLACEHOLDER_SHORT_DESCRIPTION": "간단한 설명을 입력하세요", + "ACTION_EDIT": "태스크 수정하기" + }, + "CREATE_EDIT_US": { + "TITLE": "새 유저 스토리", + "PLACEHOLDER_DESCRIPTION": "다른 사용자들이 이 유저 스토리에 대해 이해할 수 있도록 설명을 입력해주세요.", + "NEW_US": "새 유저 스토리", + "EDIT_US": "유저 스토리 수정하기" + }, + "DELETE_SPRINT": { + "TITLE": "스프린트 삭제하기" + }, + "CREATE_MEMBER": { + "PLACEHOLDER_INVITATION_TEXT": "(선택사항) 초대장에 특별한 메시지를 적으세요. 새로운 회원에게 멋진 말을 전해주세요 ;-)", + "PLACEHOLDER_TYPE_EMAIL": "이메일을 입력하세요", + "LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "이 프로젝트에 허용 된 최대 회원 수인 {{maxMembers}} 명에 도달하려합니다. 최대 회원 수를 늘리려면 관리자에게 문의하십시오.", + "LIMIT_USERS_WARNING_MESSAGE": "이 프로젝트에 허용 된 최대 회원 수 인 {{maxMembers}} 명에 도달하려고 합니다." + }, + "LEAVE_PROJECT_WARNING": { + "TITLE": "안타깝게도 이 프로젝트는 소유자 없이 남아있을 수 없습니다.", + "CURRENT_USER_OWNER": { + "DESC": "현재 이 프로젝트의 소유자입니다. 나가기전에 소유권을 다른 사람에게 양도하시기 바랍니다.", + "BUTTON": "프로젝트 소유자 변경하기" + }, + "OTHER_USER_OWNER": { + "DESC": "안타깝게도 현재 프로젝트 소유자인 회원을 삭제할 수 없습니다. 먼저 새 프로젝트 소유자를 지정하십시오.", + "BUTTON": "프로젝트 소유자 변경 요청" + } + }, + "CHANGE_OWNER": { + "TITLE": "누구를 새로운 프로젝트 소유자로 삼고 싶습니까?", + "ADD_COMMENT": "댓글 추가", + "BUTTON": "이 프로젝트 회원에게 새 프로젝트 소유자가 되도록 문의하십시오." + }, + "CONTACT_PROJECT": { + "TITLE": "이메일 보내기", + "WARNING": "프로젝트 관리자로부터 이메일을 받았습니다.", + "PLACEHOLDER": "메시지 쓰기", + "SEND": "보내기" + } + }, + "EPIC": { + "PAGE_TITLE": "{{epicSubject}} - 에픽 {{epicRef}} - {{projectName}}", + "PAGE_DESCRIPTION": "상태: {{epicStatus }}. 설명: {{epicDescription}}", + "SECTION_NAME": "에픽", + "TITLE_LIGHTBOX_UNLINK_RELATED_USERSTORY": "유저 스토리 연결 해제", + "MSG_LIGHTBOX_UNLINK_RELATED_USERSTORY": "유저 스토리 '{{subject}}' 와 관련된 링크가 삭제됩니다. ", + "ERROR_UNLINK_RELATED_USERSTORY": "링크를 해제할 수 없었습니다: {{errorMessage}}", + "CREATE_RELATED_USERSTORIES": "다음으로 관계 만들기", + "NEW_USERSTORY": "새 유저 스토리", + "EXISTING_USERSTORY": "존재하는 유저 스토리", + "CHOOSE_PROJECT_FOR_CREATION": "프로젝트가 무엇인가요?", + "SUBJECT": "주제", + "SUBJECT_BULK_MODE": "제목 (여러개 생성하기)", + "CHOOSE_PROJECT_FROM": "프로젝트가 무엇인가요?", + "CHOOSE_USERSTORY": "유저스토리가 무엇인가요?", + "NO_USERSTORIES": "이 프로젝트에는 아직 유저 스토리가 없습니다. 다른 프로젝트를 선택하십시오.", + "FILTER_USERSTORIES": "유저 스토리 필터", + "LIGHTBOX_TITLE_BLOKING_EPIC": "에픽 차단", + "ACTION_DELETE": "에픽 삭제" + }, + "US": { + "PAGE_TITLE": "{{userStorySubject}} - 유저 스토리 {{userStoryRef}} - {{projectName}}", + "PAGE_DESCRIPTION": "상태: {{userStoryStatus }}. 완료 {{userStoryProgressPercentage}}% ({{userStoryTotalTasks}} 중 {{userStoryClosedTasks}} 태스크 완료). 포인트: {{userStoryPoints}}. 상세사항: {{userStoryDescription}}", + "SECTION_NAME": "유저 스토리", + "LINK_TASKBOARD": "태스크보드", + "TITLE_LINK_TASKBOARD": "태스크보드로 가기", + "TOTAL_POINTS": "전체 포인트", + "ADD": "유저 스토리 추가하기", + "ADD_BULK": "유저 스토리 여러개 생성하기", + "PROMOTED": "이 유저 스토리는 이슈에서 만들어졌음", + "TITLE_LINK_GO_TO_ISSUE": "이슈로 가기", + "TITLE_DELETE_ACTION": "유저 스토리 삭제하기", + "LIGHTBOX_TITLE_BLOKING_US": "블로킹 유저 스토리", + "NOT_ESTIMATED": "추산되지 않음", + "TRIBE": { + "PUBLISH": "Tiaga Tribe의 Gig으로 배포하기", + "PUBLISH_INFO": "더 많은 정보", + "PUBLISH_TITLE": "Taiga Tribe로 배포하기에 대한 더 많은 정보", + "PUBLISHED_AS_GIG": "스토리가 Taiga Tribe의 Gig으로 배포되었습니다.", + "EDIT_LINK": "링크 수정", + "CLOSE": "닫기", + "SYNCHRONIZE_LINK": "Taiga Tribe와 동기화", + "PUBLISH_MORE_INFO_TITLE": "이 태스크에 누군가가 필요합니까?", + "PUBLISH_MORE_INFO_TEXT": "

만약 당신이 어떤 일에 도움이 필요하면 간단하게 Taiga Tribe 의 Gigs를 만들어 전세계의 도움을 받을 수 있습니다. 우리는 당신이 이 위대한 커뮤니티의 gig을 즐기고 제어하거나 관리하면서 기여 할 수 있기를 열망합니다.

Taiga Tribe 는 타이가의 형제로 태어났습니다. 두 플랫폼은 별개로 살아갈 수 있지만, 우리는 이들을 결합 하였을 때 더 큰 힘을 낼 수 있다고 믿습니다. 그리고 멋지게 통합되어 움직이는 것을 확인하였습니다.

" + }, + "FIELDS": { + "TEAM_REQUIREMENT": "팀 요구 사항", + "CLIENT_REQUIREMENT": "고객 요구 사항" + } + }, + "COMMENTS": { + "DELETED_INFO": "{{user}} 에 의해 댓글이 지워짐.", + "COMMENTS_COUNT": "{{comments}} 댓글", + "OLDER_FIRST": "오랜된 순으로", + "RECENT_FIRST": "최신 순으로", + "COMMENT": "댓글", + "EDITED_COMMENT": "수정됨:", + "SHOW_HISTORY": "역사 보기", + "TYPE_NEW_COMMENT": "댓글을 입력하세요", + "SHOW_DELETED": "삭제된 댓글 보기", + "HIDE_DELETED": "삭제된 댓글 가리기", + "DELETE": "댓글 삭제", + "RESTORE": "댓글 되살리기", + "HISTORY": { + "TITLE": "활동 내역" + } + }, + "ACTIVITY": { + "TITLE": "활동 내역", + "ACTIVITIES_COUNT": "{{activities}} 활동", + "TAGS_ADDED": "태그 추가됨:", + "TAGS_REMOVED": "태그 삭제됨:", + "US_POINTS": "{{role}} 포인트", + "NEW_ATTACHMENT": "새로운 첨부파일:", + "DELETED_ATTACHMENT": "첨부파일 삭제하기", + "UPDATED_ATTACHMENT": "첨부 파일이 업데이트됨 ({{filename}}):", + "CREATED_CUSTOM_ATTRIBUTE": "사용자 정의 속성 만들기", + "UPDATED_CUSTOM_ATTRIBUTE": "사용자 정의 속성 업데이트하기", + "BECAME_DEPRECATED": "지원하지 않도록 되었습니다.", + "BECAME_UNDEPRECATED": "다시 지원하도록 되었습니다.", + "TEAM_REQUIREMENT": "팀 요구 사항", + "CLIENT_REQUIREMENT": "고객 요구 사항", + "BLOCKED": "차단됨", + "VALUES": { + "UNASSIGNED": "할당되지 않음" + }, + "FIELDS": { + "SUBJECT": "주제", + "DESCRIPTION": "설명", + "STATUS": "상태", + "TYPE": "타입", + "ASSIGNED_TO": "할당됨", + "MILESTONE": "스프린트", + "COLOR": "색" + } + }, + "BACKLOG": { + "PAGE_TITLE": "백로그 - {{projectName}}", + "PAGE_DESCRIPTION": "프로젝트의 유저 스토리와 스프린트를 보여주는 백 패널 {{projectName}}: {{projectDescription}}", + "SECTION_NAME": "백로그", + "CUSTOMIZE_GRAPH": "백로그 그래프 사용자 정의하기", + "CUSTOMIZE_GRAPH_TEXT": "프로젝트의 진화를 돕는 좋은 그래프를 얻으려면, 당신은 포인트와 스프린트를 설정해야합니다.", + "CUSTOMIZE_GRAPH_ADMIN": "관리자", + "CUSTOMIZE_GRAPH_TITLE": "관리자 메뉴에서 포인트와 스프린트를 설정하세요.", + "MOVE_US_TO_CURRENT_SPRINT": "현재 스프린트로 옮기기", + "MOVE_US_TO_LATEST_SPRINT": "가장 최근 스프린트로 옮기기", + "EMPTY": "백로그가 비었습니다!", + "CREATE_NEW_US": "유저 스토리 생성하기", + "CREATE_NEW_US_EMPTY_HELP": "새로운 유저 스토리를 만들어 보고 싶죠?", + "EXCESS_OF_POINTS": "포인트 초과", + "PENDING_POINTS": "보류 중인 포인트", + "CLOSED_POINTS": "완료", + "COMPACT_SPRINT": "스프린트 접기", + "GO_TO_TASKBOARD": "{{::name}}의 태스크보드로 이동하기", + "EDIT_SPRINT": "스프린트 수정하기", + "TOTAL_POINTS": "전체", + "STATUS_NAME": "상태 이름", + "SORTABLE_FILTER_ERROR": "필터 창이 열려있을 때에는 백로그를 옮길 수 없습니다.", + "DOOMLINE": "프로젝트 범위 [둠 라인]", + "CHART": { + "XAXIS_LABEL": "스프린트", + "YAXIS_LABEL": "포인트", + "OPTIMAL": "\"{{sprintName}}\" 스프린트에서 최적의 대기 포인트는 {{value}} 로 되어야합니다.", + "REAL": "\"{{sprintName}}\" 스프린트의 실제 대기포인트는 {{value}} 입니다.", + "INCREMENT_TEAM": "팀 요구 사항에 따라 \"{{sprintName}}\" 스프린트의 포인트가 {{value}}로 증가했습니다.", + "INCREMENT_CLIENT": "고객 요구 사항에 따라 \"{{sprintName}}\" 스프린트의 포인트가 {{value}}로 증가했습니다." + }, + "TAGS": { + "TOGGLE": "태그 보여짐 토글", + "SHOW": "태그 보기", + "HIDE": "태그 숨기기" + }, + "FORECASTING": { + "TITLE": "속도 예측", + "BACKLOG": "백로그 표시", + "NEW_SPRINT": "당신의 속도를 기반으로한 다음 스프린트의 후보 유저 스토리 입니다. 클릭하여 새로운 스프린트를 만드십시오.", + "CURRENT_SPRINT": "당신의 속도를 기반으로한 다음 스프린트의 후보 유저 스토리 입니다. 클릭하여 현재 스프린트에 추가하십시오." + }, + "TABLE": { + "COLUMN_US": "유저 스토리", + "TITLE_COLUMN_POINTS": "역할 별로 보기" + }, + "SPRINT_SUMMARY": { + "TOTAL_POINTS": "종합
포인트", + "COMPLETED_POINTS": "완료한
포인트", + "OPEN_TASKS": "태스크
열림", + "CLOSED_TASKS": "완료한
태스크", + "IOCAINE_DOSES": "아이오케인
복용", + "SHOW_STATISTICS_TITLE": "지표 보기", + "TOGGLE_BAKLOG_GRAPH": "번다운 그래프 보이기/숨기기", + "POINTS_PER_ROLE": "역할별 포인트" + }, + "SUMMARY": { + "PROJECT_POINTS": "프로젝트
포인트", + "DEFINED_POINTS": "정의된
포인트", + "CLOSED_POINTS": "완료한
포인트", + "POINTS_PER_SPRINT": "포인트 /
스프린트" + }, + "FILTERS": { + "TOGGLE": "필터 보여짐 토글", + "HIDE": "필터 숨기기", + "SHOW": "필터 보기" + }, + "SPRINTS": { + "TITLE": "스프린트", + "DATE": "YYYY MMM DD", + "LINK_TASKBOARD": "스프린트 태스크보드", + "TITLE_LINK_TASKBOARD": "\"{{name}}\" 태스크보드로 가기", + "EMPTY": "스프린트가 아직 없습니다.", + "WARNING_EMPTY_SPRINT_ANONYMOUS": "이 스프린트는 유저 스토리가 없습니다.", + "WARNING_EMPTY_SPRINT": "새 스프린트를 추가하려면 백로그에서 스토리를 끌어 놓으세요", + "TITLE_ACTION_NEW_SPRINT": "새로운 스프린트 추가", + "TEXT_ACTION_NEW_SPRINT": "프로젝트에 새로운 스프린트를 만들어 보고 싶죠?", + "ACTION_SHOW_CLOSED_SPRINTS": "완료한 스프린트 보기", + "ACTION_HIDE_CLOSED_SPRINTS": "완료한 스프린트 숨기기" + } + }, + "ERROR": { + "TEXT1": "움파룸파가 무언가를 작업하고 있습니다.", + "NOT_FOUND": "찾지 못함", + "NOT_FOUND_TEXT": "404 에러: 당신이 접속한 페이지는 더 이상 존재하지 않습니다. 타이가홈페이지로 돌아가서 당신이 찾고 있는 페이지를 찾아보세요.", + "PERMISSION_DENIED": "권한이 없습니다", + "PERMISSION_DENIED_TEXT": "이 페이지를 볼 수 있는 권한이 없습니다.", + "VERSION_ERROR": "타이가 내부의 누군가가 이전에 이를 변경했으며 우리 움파룸파는 변경 사항을 적용 할 수 없습니다. 다시 로드하고 변경 사항을 다시 적용하십시오. (지금의 변경사항들은 손실 될 것입니다)." + }, + "TASKBOARD": { + "PAGE_TITLE": "{{sprintName}} - 스프린트 태스크보드 - {{projectName}}", + "PAGE_DESCRIPTION": "{{projectName}}의 스프린트 {{sprintName}} ({{startDate}}에서 {{endDate}}까지). {{completedPercentage}}% 완료됨 ({{completedPoints}} 중 {{totalPoints}}). {{openTasks}}는 {{totalTasks}}의 작업을 열었습니다.", + "SECTION_NAME": "태스크보드", + "TITLE_ACTION_ADD": "태스크 추가하기", + "TITLE_ACTION_ADD_BULK": "태스트 여러개 생성하기", + "TITLE_ACTION_ASSIGN": "태스크 할당하기", + "PLACEHOLDER_CARD_TITLE": "이것은 태스크가 될 수 있습니다.", + "PLACEHOLDER_CARD_TEXT": "스토리를 여러 태스크로 나누고 개별적으로 추적하세요.", + "TABLE": { + "COLUMN": "유저 스토리", + "TITLE_ACTION_FOLD": "컬럼 접기", + "TITLE_ACTION_UNFOLD": "컬럼 접기", + "TITLE_ACTION_FOLD_ROW": "행 접기", + "TITLE_ACTION_UNFOLD_ROW": "행 접기", + "FIELD_POINTS": "포인트", + "ROW_UNASSIGED_TASKS_TITLE": "할당되지 않은 태스크" + }, + "CHARTS": { + "XAXIS_LABEL": "일", + "YAXIS_LABEL": "포인트", + "OPTIMAL": "{{formattedDate}}에 대한 최적의 일일 대기 포인트는 {{roundedValue}}이어야 합니다.", + "REAL": "{{formattedDate}}의 실제 대기 포인트는 {{roundedValue}} 입니다.", + "DATE": "YYYY MMMM DD" + } + }, + "TASK": { + "PAGE_TITLE": "{{taskSubject}} - 태스크 {{taskRef}} - {{projectName}}", + "PAGE_DESCRIPTION": "상태: {{taskStatus }}. 세부사항: {{taskDescription}}", + "SECTION_NAME": "태스크", + "LINK_TASKBOARD": "태스크보드", + "TITLE_LINK_TASKBOARD": "태스크보드로 가기", + "PLACEHOLDER_SUBJECT": "새 태스크의 이름을 입력하세요", + "TITLE_SELECT_STATUS": "상태 이름", + "OWNER_US": "이 태스크는 다음에 속합니다.", + "TITLE_LINK_GO_OWNER": "유저 스토리로 가기", + "TITLE_DELETE_ACTION": "태스크 삭제하기", + "LIGHTBOX_TITLE_BLOKING_TASK": "블로킹 태스크", + "FIELDS": { + "IS_IOCAINE": "독약인가요?" + }, + "TITLE_ACTION_IOCAINE": "이 태스크에 대해 조금 압박감을 느끼나요? 이 태스크를 수정할 때 아이오케인을 클릭해 다른 사람들에게 알리세요. 조금씩 이 독에 맞서면 이 (허구의)치명적인 독에 면역이 될 수 있습니다. 때로는 추가 도전 과제를 취함으로써 당신이 하는 일을 더 잘 할 수 있는 것 처럼 말이죠!" + }, + "NOTIFICATION": { + "OK": "모든게 좋네요", + "WARNING": "음? 뭔가 문제가 있는데...", + "WARNING_TEXT": "변경사항이 저장되지 않아서 움파룸파는 슬퍼요.", + "SAVED": "움파룸파가 모든 사항을 저장했습니다.", + "CLOSE": "알림 닫기", + "MAIL": "메일로 알림", + "ASK_DELETE": "정말 삭제하실 건가요?" + }, + "CANCEL_ACCOUNT": { + "TITLE": "계정 취소 하기", + "SUBTITLE": "당신이 타이가 떠난다니 아쉽네요. 부디 좋은 기억만 남기를 바랍니다 :)", + "PLACEHOLDER_INPUT_TOKEN": "계정 토큰 삭제", + "ACTION_LEAVING": "네, 나갈래요!", + "SUCCESS": "움파룸파가 당신 계정을 지웠습니다" + }, + "CHANGE_EMAIL_FORM": { + "TITLE": "이메일 변경하기", + "SUBTITLE": "한번 더 클릭하시면 이메일 정보가 업데이트 됩니다.", + "PLACEHOLDER_INPUT_TOKEN": "이메일 토큰 변경", + "ACTION_CHANGE_EMAIL": "이메일 변경하기", + "SUCCESS": "움파룸파가 당신의 이메일을 업데이트 하였습니다." + }, + "ISSUES": { + "PAGE_TITLE": "이슈 - {{projectName}}", + "PAGE_DESCRIPTION": "프로젝트 {{projectName}}: {{projectDescription}}의 이슈 목록 패널", + "SECTION_NAME": "이슈", + "ACTION_NEW_ISSUE": "이슈 추가하기", + "ACTION_PROMOTE_TO_US": "유저 스토리에 등록하기", + "PROMOTED": "이 이슈가 유저 스토리에 등록되었습니다.", + "EXTERNAL_REFERENCE": "이 이슈가 만들어 진 곳은 ", + "GO_TO_EXTERNAL_REFERENCE": "원본으로 가기", + "ACTION_DELETE": "이슈 삭제하기", + "LIGHTBOX_TITLE_BLOKING_ISSUE": "걸림돌이 되는 이슈", + "FIELDS": { + "PRIORITY": "우선순위", + "SEVERITY": "심각도", + "TYPE": "타입" + }, + "CONFIRM_PROMOTE": { + "TITLE": "이 이슈를 유저 스토리에 등록하기", + "MESSAGE": "이 이슈에서 새 유저 스토리를 생성하시겠어요?" + }, + "TABLE": { + "COLUMNS": { + "TYPE": "타입", + "SEVERITY": "심각도", + "PRIORITY": "우선순위", + "SUBJECT": "주제", + "VOTES": "투표", + "STATUS": "상태", + "CREATED": "생성됨", + "ASSIGNED_TO": "할당됨" + }, + "TITLE_ACTION_CHANGE_STATUS": "상태 변경하기", + "TITLE_ACTION_ASSIGNED_TO": "할당됨", + "BLOCKED": "차단됨", + "EMPTY": { + "TITLE": "보고할 이슈가 없습니다. :-)", + "SUBTITLE": "이슈를 찾았나요?" + } + } + }, + "ISSUE": { + "PAGE_TITLE": "{{issueSubject}} - 이슈 {{issueRef}} - {{projectName}}", + "PAGE_DESCRIPTION": "상태: {{issueStatus }}. 종류: {{issueType}}, 우선순위: {{issuePriority}}. 심각도: {{issueSeverity}}. 설명: {{issueDescription}}" + }, + "KANBAN": { + "PAGE_TITLE": "칸반 - {{projectName}}", + "PAGE_DESCRIPTION": "프로젝트 {{projectName}}: {{projectDescription}}의 유저 스토리를 보여주는 칸반 패널", + "SECTION_NAME": "칸반", + "TITLE_ACTION_FOLD": "컬럼 접기", + "TITLE_ACTION_UNFOLD": "컬럼 접기", + "TITLE_ACTION_ADD_US": "새 유저 스토리 추가하기", + "TITLE_ACTION_ADD_BULK": "여러개 생성하기", + "ACTION_SHOW_ARCHIVED": "보관된 것 보기", + "ACTION_HIDE_ARCHIVED": "보관된 것 숨기기", + "HIDDEN_USER_STORIES": "이 상태에 있는 유저 스토리는 기본적으로 숨겨집니다.", + "PLACEHOLDER_CARD_TITLE": "당신의 유저 스토리들 입니다.", + "PLACEHOLDER_CARD_TEXT": "스토리에는 요구 사항을 구분하는 하위 태스크가 있을 수도 있습니다." + }, + "SEARCH": { + "PAGE_TITLE": "검색 - {{projectName}}", + "PAGE_DESCRIPTION": "프로젝트 내에서 유저 스토리, 이슈, 태스크 또는 위키 페이지를 포함한 모든 검색 {{projectName}}: {{projectDescription}}", + "FILTER_EPICS": "에픽", + "FILTER_USER_STORIES": "유저 스토리", + "FILTER_ISSUES": "이슈", + "FILTER_TASKS": "태스크", + "FILTER_WIKI": "위키 페이지", + "PLACEHOLDER_SEARCH": "검색하기", + "TITLE_ACTION_SEARCH": "검색하기", + "EMPTY_TITLE": "검색 조건에 부합하는 결과가 하나도 없네요.", + "EMPTY_DESCRIPTION": "위의 탭 중 하나를 사용하거나 다시 검색하십시오." + }, + "TEAM": { + "PAGE_TITLE": "팀 - {{projectName}}", + "PAGE_DESCRIPTION": "프로젝트의 모든 회원들을 보여주기 위한 팀 패널 {{projectName}}: {{projectDescription}}", + "SECTION_NAME": "팀", + "PLACEHOLDER_INPUT_SEARCH": "전체 이름 검색하기", + "COLUMN_MR_WOLF": "울프씨", + "EXPLANATION_COLUMN_MR_WOLF": " 완료한 이슈", + "COLUMN_IOCAINE": "아이오케인 중독자", + "EXPLANATION_COLUMN_IOCAINE": "복용한 아이오케인 양", + "COLUMN_CERVANTES": "세르반테스", + "EXPLANATION_COLUMN_CERVANTES": "위키 페이지가 수정되었습니다.", + "COLUMN_BUG_HUNTER": "버그 사냥꾼", + "EXPLANATION_COLUMN_BUG_HUNTER": "이슈 보고서", + "COLUMN_NIGHT_SHIFT": "야간 근무", + "EXPLANATION_COLUMN_NIGHT_SHIFT": "완료한 태스크", + "COLUMN_TOTAL_POWER": "전체 파워", + "EXPLANATION_COLUMN_TOTAL_POWER": "전체 포인트", + "SECTION_TITLE_TEAM": "팀 >", + "SECTION_FILTER_ALL": "전체", + "CONFIRM_LEAVE_PROJECT": "이 프로젝트를 정말로 떠나시려고요?", + "ACTION_LEAVE_PROJECT": "프로젝트 나가기" + }, + "USER_SETTINGS": { + "AVATAR_MAX_SIZE": "[최대 크기: {{maxFileSize}}]", + "MENU": { + "SECTION_TITLE": "사용자 설정", + "USER_PROFILE": "사용자 프로필", + "CHANGE_PASSWORD": "비밀번호 변경하기", + "EMAIL_NOTIFICATIONS": "이메일 알림" + }, + "NOTIFICATIONS": { + "SECTION_NAME": "이메일 알림", + "COLUMN_PROJECT": "프로젝트", + "COLUMN_RECEIVE_ALL": "모두 받기", + "COLUMN_ONLY_INVOLVED": "내가 관련된 경우에만", + "COLUMN_NO_NOTIFICATIONS": "알림 없음", + "OPTION_ALL": "전체", + "OPTION_INVOLVED": "관련됨", + "OPTION_NONE": "없음" + } + }, + "USER_PROFILE": { + "ACTION_USE_GRAVATAR": "기본 이미지 사용", + "ACTION_DELETE_ACCOUNT": "타이가 계정 삭제하기", + "CHANGE_EMAIL_SUCCESS": "이메일 보관함을 확인하세요!
새 주소를 설정할 수 있는 방법을
이메일로 알려드렸습니다.", + "CHANGE_PHOTO": "사진 변경하기", + "FIELD": { + "USERNAME": "아이디", + "EMAIL": "이메일", + "FULL_NAME": "전체 이름", + "PLACEHOLDER_FULL_NAME": "이름 전체를 적어 주세요(예. 조찬제)", + "BIO": "소개 (최대 210자)", + "PLACEHOLDER_BIO": "당신에 대해서 알려 주세요.", + "LANGUAGE": "언어", + "LANGUAGE_DEFAULT": "-- 기본 언어 사용하기 --", + "THEME": "테마", + "THEME_DEFAULT": "-- 기본 테마 사용하기 --" + } + }, + "WIKI": { + "PAGE_TITLE": "{{wikiPageName}} - 위키 - {{projectName}}", + "PAGE_DESCRIPTION": "{{lastModifiedDate}}에 최종 수정 (총 {{totalEditions}} 회 수정) 내용: {{ wikiPageContent }}", + "DATETIME": "YYYY MMM DD HH:mm", + "REMOVE": "이 위키 페이지 삭제하기", + "DELETE_LIGHTBOX_TITLE": "위키 페이지 삭제하기", + "DELETE_LINK_TITLE": "위키 링크 삭제하기", + "NAVIGATION": { + "HOME": "메인 페이지", + "SECTION_NAME": "북마크", + "ACTION_ADD_LINK": "북마크 추가", + "ALL_PAGES": "모든 위키 페이지" + }, + "SUMMARY": { + "TIMES_EDITED": "번
수정됨", + "LAST_EDIT": "에
수정됨", + "LAST_MODIFICATION": "마지막 수정" + }, + "SECTION_PAGES_LIST": "모든 페이지", + "PAGES_LIST_COLUMNS": { + "TITLE": "제목", + "EDITIONS": "판", + "CREATED": "생성됨", + "MODIFIED": "수정됨", + "CREATOR": "작성자", + "LAST_MODIFIER": "마지막 수정" + } + }, + "HINTS": { + "SECTION_NAME": "힌트", + "LINK": "사용법을 알고싶으시다면 지원 페이지를 방문해주세요.", + "LINK_TITLE": "지원 페이지를 방문하세요", + "HINT1_TITLE": "프로젝트를 내보내거나 가져올 수 있다는 건 아세요?", + "HINT1_TEXT": "이것은 당신에게 하나의 타이가에서 당신의 모든 데이터를 추출하여 다른 곳으로 이동시킬 수 있도록 허용합니다.", + "HINT2_TITLE": "사용자 정의 필드를 만들 수 있다는건 아세요?", + "HINT2_TEXT": "이제 팀은 특정 워크 플로우에 유용한 특정 데이터를 입력하는 유연한 방법으로 사용자 정의 필드를 만들 수 있습니다.", + "HINT3_TITLE": "당신과 가장 관련성이 높은 순서대로 프로젝트를 정렬하세요.", + "HINT3_TEXT": "상단의 빠른 접근 항목에서 10개의 목록이 보여 집니다.", + "HINT4_TITLE": "뭘 하고 있었는지 잊었습니까?", + "HINT4_TEXT": "걱정마세요, 대시보드에서 당신이 연 태스크, 이슈, 유저 스토리를 작업한 순서데로 찾아볼 수 있습니다." + }, + "TIMELINE": { + "UPLOAD_ATTACHMENT": "{{username}} 님이 {{obj_name}} 첨부파일을 업로드했습니다.", + "US_CREATED": "{{username}} 님이 {{project_name}}에 {{obj_name}} 유저 스토리를 생성하였습니다.", + "ISSUE_CREATED": "{{username}} 님이 {{project_name}}에 {{obj_name}} 이슈를 생성하였습니다.", + "TASK_CREATED": "{{username}} 님이 {{project_name}}에 {{obj_name}} 태스크를 추가하였습니다.", + "TASK_CREATED_WITH_US": "{{username}} 님이 {{project_name}} {{us_name}} 유저 스토리에 {{obj_name}}을 생성하였습니다.", + "WIKI_CREATED": "{{username}} 님이 {{project_name}}에 {{obj_name}} 위키 페이지를 만들었습니다.", + "MILESTONE_CREATED": "{{username}} 님이 {{project_name}}에 {{obj_name}} 스프린트를 만들었습니다.", + "EPIC_CREATED": "{{username}} 님이 새로운 에픽을 {{project_name}} 프로젝트에 {{obj_name}} 명으로 생성하였습니다.", + "EPIC_RELATED_USERSTORY_CREATED": "{{username}} 님이 {{project_name}} 프로젝트에서 {{related_us_name}} 유저 스토리를 {{epic_name}} 에픽과의 연결에 사용하였습니다.", + "NEW_PROJECT": "{{username}} 님이 {{project_name}} 프로젝트를 만들었습니다.", + "MILESTONE_UPDATED": "{{username}} 님이 {{obj_name}} 스프린트를 업데이트 했습니다.", + "US_UPDATED": "{{obj_name}} 유저 스토리에서 \"{{field_name}}\" 속성을 {{username}} 님이 업데이트 했습니다.", + "US_UPDATED_WITH_NEW_VALUE": "{{username}} 님이 {{obj_name}} 유저 스토리의 \"{{field_name}}\" 속성을 {{new_value}}로 변경하였습니다.", + "US_UPDATED_POINTS": "{{username}} 님이 {{obj_name}} 유저 스토리의 '{{role_name}}' 포인트를 {{new_value}}로 변경하였습니다.", + "ISSUE_UPDATED": "{{username}}님이 {{obj_name}} 이슈의 \"{{field_name}}\" 속성을 변경하였습니다.", + "ISSUE_UPDATED_WITH_NEW_VALUE": "{{username}} 님이 {{obj_name}} 이슈의 \"{{field_name}}\" 속성을 {{new_value}}로 변경하였습니다.", + "TASK_UPDATED": "{{username}} 님이 {{obj_name}} 태스크의 \"{{field_name}}\" 속성을 {{new_value}}로 변경하였습니다.", + "TASK_UPDATED_WITH_NEW_VALUE": "{{username}} 님이 {{obj_name}} 태스크의 \"{{field_name}}\" 속성을 {{new_value}}로 변경하였습니다.", + "TASK_UPDATED_WITH_US": "{{username}} 님이 {{us_name}} 유저 스토리에 있는 {{obj_name}} 태스크의 \"{{field_name}}\" 속성을 수정하였습니다.", + "TASK_UPDATED_WITH_US_NEW_VALUE": "{{username}} 님이 {{us_name}} 유저스토리에 있는 {{obj_name}} 태스크의 \"{{field_name}}\" 속성을 {{new_value}}로 수정하였습니다.", + "WIKI_UPDATED": "{{username}} 님이 {{obj_name}} 위키 페이지를 업데이트했습니다.", + "EPIC_UPDATED": "{{username}}님이 에픽 {{obj_name}}의 속성 \"{{field_name}}\"을 변경하였습니다.", + "EPIC_UPDATED_WITH_NEW_VALUE": "{{username}}님이 에픽 {{obj_name}}의 속성 \"{{field_name}}\"을 {{new_value}}로 변경하였습니다.", + "EPIC_UPDATED_WITH_NEW_COLOR": "{{username}}님이 에픽 {{obj_name}}의 \"{{field_name}}\"을 으로 변경하였습니다.", + "NEW_COMMENT_US": "{{username}} 님이 {{obj_name}} 유저 스토리에 댓글을 남겼습니다.", + "NEW_COMMENT_ISSUE": "{{username}} 님이 {{obj_name}} 이슈에 댓글을 남겼습니다.", + "NEW_COMMENT_TASK": "{{username}} 님이 {{obj_name}} 태스크에 댓글을 남겼습니다.", + "NEW_COMMENT_EPIC": "{{username}} 님이 {{obj_name}} 에픽에 댓글을 남겼습니다.", + "NEW_MEMBER": "{{project_name}}에 새 팀원이 들어왔습니다.", + "US_ADDED_MILESTONE": "{{username}} 님이 {{obj_name}} 유저 스토리를 {{sprint_name}}에 추가하였습니다.", + "US_MOVED": "{{username}} 님이 {{obj_name}} 유저 스토리를 이동했습니다.", + "US_REMOVED_FROM_MILESTONE": "{{username}} 님이 {{obj_name}} 유저 스토리를 백로그에 추가하였습니다.", + "BLOCKED": "{{username}} 님이 {{obj_name}}를 차단하였습니다.", + "UNBLOCKED": "{{username}} 님이 {{obj_name}}를 차단 해제하였습니다.", + "NEW_USER": "{{username}} 님이 타이가에 등록하였습니다." + }, + "LEGAL": { + "TERMS_OF_SERVICE_AND_PRIVACY_POLICY_AD": "새 계정을 생성하시는 것은,
서비스 약관개인정보 취급방침에 동의하시는 것을 의미합니다." + }, + "EXTERNAL_APP": { + "PAGE_TITLE": "외부 연동 앱은 권한이 필요합니다.", + "PAGE_DESCRIPTION": "외부 연동 앱은 권한이 필요합니다.", + "AUTHORIZATION_REQUEST": "{{application}}이 당신의 타이가 계정을 사용하도록 허가하시겠어요?", + "LOGIN_WITH_ANOTHER_USER": "다른 사용자로 로그인 하기", + "AUTHORIZE_APP": "인증 앱", + "CANCEL": "취소" + }, + "JOYRIDE": { + "NAV": { + "NEXT": "다음", + "BACK": "이전", + "SKIP": "건너뛰기", + "DONE": "완료됨" + }, + "DASHBOARD": { + "STEP1": { + "TITLE": "프로젝트", + "TEXT": "환영합니다! 여기에서 당신이 참여하고 있는 프로젝트를 찾으실 수 있습니다." + }, + "STEP2": { + "TITLE": "일 하는 중", + "TEXT": "여기에는 당신이 작업하고 있는 유저 스토리, 태스크, 이슈들이 표시됩니다." + }, + "STEP3": { + "TITLE": "구독중", + "TEXT1": "그리고 여기에서 프로젝트에 대해 알고 싶은 것들을 찾을 수 있습니다.", + "TEXT2": "이미 타이가에 있으신걸요? ;)" + }, + "STEP4": { + "TITLE": "시작해 봅시다.", + "TEXT1": "여러분의 첫번째 Tagia 프로젝트를 만드세요.", + "TEXT2": "행운을 빌어요!" + } + }, + "BACKLOG": { + "STEP1": { + "TITLE": "프로젝트 요약", + "TEXT1": "여기에서는 당신의 프로젝트의 상태를 알 수 있습니다.", + "TEXT2": "관리자 메뉴에서 프로젝트의 모든 설정을 변경할 수 있어요." + }, + "STEP2": { + "TITLE": "제품 백로그", + "TEXT": "백 로그는 프로젝트의 요구 사항 (유저 스토리)목록입니다. 스프린트를 계획 할 곳은 다음과 같습니다." + }, + "STEP3": { + "TITLE": "스프린트", + "TEXT": "스프린트는 특정 작업을 완료하고 전달해야하는 짧은 기간 (일반적으로 2주)입니다." + }, + "STEP4": { + "TITLE": "유저 스토리", + "TEXT": "그것들은 높은 수준의 요구 사항입니다. 백 로그에 추가하고 전달해야하는 스프린트로 드래그 할 수 있습니다." + } + }, + "KANBAN": { + "STEP1": { + "TITLE": "워크플로우 사용자 정의하기", + "TEXT": "관리자를 통해 워크 플로우 상태를 매핑하는 데 필요한 열을 설정하십시오" + }, + "STEP2": { + "TITLE": "유저 스토리 & 태스크", + "TEXT": "유저 스토리에 더 높은 권한이 필요합니다. 다른 컬럼에 끌어 놓으세요." + }, + "STEP3": { + "TITLE": "유저 스토리 추가하기", + "TEXT1": "단일 유저 스토리 (유저 스토리 아이콘 추가) 또는 그 그룹 (여러개의 아이콘)을 추가 할 수 있습니다.", + "TEXT2": "행운을 빌어요!" + } + } + }, + "DISCOVER": { + "PAGE_TITLE": "프로젝트 찾기 - 타이가", + "PAGE_DESCRIPTION": "타이가 공공 프로젝트 디렉토리를 검색 할 수 있습니다. 백 로그, 타임 라인, 이슈 및 팀을 탐색하십시오. 가장 인기 있거나 가장 활동적인 프로젝트를 확인하십시오. 칸반 또는 스크럼으로 필터", + "DISCOVER_TITLE": "프로젝트 찾기", + "DISCOVER_SUBTITLE": "{projects, plural, one{One public project to discover} other{# 개의 프로젝트를 발견}}", + "MOST_ACTIVE": "가장 활동적인", + "MOST_ACTIVE_EMPTY": "아직 활성화된 프로젝트가 없습니다.", + "MOST_LIKED": "가장 인기있는", + "MOST_LIKED_EMPTY": "아직 '좋아요' 표시한 프로젝트가 없습니다.", + "VIEW_MORE": "더 보기", + "FEATURED": "주요 프로젝트", + "EMPTY": "이 검색 기준으로 표시 할 프로젝트가 없습니다.
다시 시도해주세요!", + "FILTERS": { + "ALL": "전체", + "KANBAN": "칸반", + "SCRUM": "스크럼", + "PEOPLE": "사용자 찾기", + "WEEK": "지난 주", + "MONTH": "지난 달", + "YEAR": "작년", + "ALL_TIME": "모든 날짜", + "CLEAR": "필터 없애기" + }, + "SEARCH": { + "PAGE_TITLE": "검색 - 프로젝트 찾기 - 타이가", + "PAGE_DESCRIPTION": "타이가 공공 프로젝트 디렉토리를 검색 할 수 있습니다. 백 로그, 타임 라인, 이슈 및 팀을 탐색하십시오. 가장 인기 있거나 가장 활동적인 프로젝트를 확인하십시오. 칸반 또는 스크럼으로 필터", + "INPUT_PLACEHOLDER": "아무거나 입력하세요...", + "ACTION_TITLE": "검색", + "RESULTS": "검색 결과" + } + } +} \ No newline at end of file diff --git a/app/locales/taiga/locale-nb.json b/app/locales/taiga/locale-nb.json index c87cd24b..60301b69 100644 --- a/app/locales/taiga/locale-nb.json +++ b/app/locales/taiga/locale-nb.json @@ -4,7 +4,6 @@ "NO": "Nei", "OR": "eller", "LOADING": "Laster...", - "LOADING_PROJECT": "Laster prosjekt...", "DATE": "DD MMM YYYY", "DATETIME": "DD MMM YYYY HH:mm", "SAVE": "Lagre", @@ -27,12 +26,9 @@ "BLOCKED_NOTE": "Hvorfor er dette blokkert?", "BLOCKED_REASON": "Venligst forklar årsaken", "CREATED_BY": "Opprettet av {{fullDisplayName}}", - "FROM": "fra", - "TO": "til", "CLOSE": "lukk", "GO_HOME": "Led meg hjem", "PLUGINS": "Programtillegg", - "BETA": "Vi er i beta!", "ONE_ITEM_LINE": "En enhet per linje...", "NEW_BULK": "Ny sett (mange)", "RELATED_TASKS": "Relaterte oppgaver", @@ -41,7 +37,7 @@ "LOGOUT": "Logg ut", "EXTERNAL_USER": "en ekstern bruker", "GENERIC_ERROR": "En av våre Oompa Loompaer sier {{error}}.", - "IOCAINE_TEXT": "Føler du deg litt overveldet av en oppgave? Sørg for at andre vet om det ved å klikke på \"Iocane\" når du redigerer en oppgave. Det er mulig å bli immun mot denne (fiktive) dødelige giften ved å konsumere små mengder over tid, akkurat som det er mulig å bli bedre på det du gjør ved av og til å ta på deg ekstra utfordringer!", + "IOCAINE_TEXT": "This member is feeling a bit overwhelmed by this task. Will become immune to the iocaine poison over time with your help. For now, may need a hug.", "CLIENT_REQUIREMENT": "Klientkravet er nytt krav som tidligere ikke var forventet, og det er nødt til å være en del av prosjektet", "TEAM_REQUIREMENT": "TeamBehov er et behov som må eksistere i prosjektet, men som ikke har noen kostnad for klienten", "OWNER": "Prosjekteier", @@ -148,7 +144,6 @@ "PRIORITY": "Prioritet", "ASSIGNED_TO": "Tildelt til", "POINTS": "Poeng", - "BLOCKED_NOTE": "blokkert notat", "IS_BLOCKED": "er blokkert", "REF": "Ref", "VOTES": "Stemmer", @@ -187,10 +182,6 @@ "COUNTER_TITLE": "{total, plural, one{en følger} other{# følgere}}" }, "VOTE_BUTTON": { - "UPVOTE": "Stem på", - "UPVOTED": "Stemt på", - "DOWNVOTE": "Stem ned", - "VOTERS": "Stemmegivere", "BUTTON_TITLE": "Stem opp / Stem ned dette elementet", "COUNTER_TITLE": "{total, plural, one{en stemme} other{# stemmer}}" }, @@ -202,10 +193,9 @@ "CONFIRM_DELETE": "Husk at alle verdier i dette egendefinerte feltet vil bli slettet.\nEr du sikker på at du vil fortsette?" }, "FILTERS": { - "TITLE": "Filtre", "INPUT_PLACEHOLDER": "Subjekt eller referanse", "TITLE_ACTION_FILTER_BUTTON": "Søk", - "INPUT_SEARCH_PLACEHOLDER": "Subjekt eller referanse", + "TITLE": "Filtre", "TITLE_ACTION_SEARCH": "Søk", "ACTION_SAVE_CUSTOM_FILTER": "lagre som egendefinert filter", "PLACEHOLDER_FILTER_NAME": "Skriv filternavnet og trykk enter", @@ -220,41 +210,10 @@ "CREATED_BY": "Laget av", "CUSTOM_FILTERS": "Egendefinert filtre", "EPIC": "Epic" - }, - "CONFIRM_DELETE": { - "TITLE": "Slett egendefinert filter", - "MESSAGE": "det egendefinerte filteret '{{customFilterName}}'" } }, "WYSIWYG": { - "H1_BUTTON": "Første Nivå Overskrift", - "H1_SAMPLE_TEXT": "Din tittel her...", - "H2_BUTTON": "Andre Nivå Overskrift", - "H2_SAMPLE_TEXT": "Din tittel her...", - "H3_BUTTON": "Tredje Nivå Overskrift", - "H3_SAMPLE_TEXT": "Din tittel her...", - "BOLD_BUTTON": "Fet", - "BOLD_BUTTON_SAMPLE_TEXT": "Din tekst her...", - "ITALIC_BUTTON": "Kursiv", - "ITALIC_SAMPLE_TEXT": "Din tekst her...", - "STRIKE_BUTTON": "Gjennomstrek", - "STRIKE_SAMPLE_TEXT": "Din tekst her...", - "BULLETED_LIST_BUTTON": "Punktliste", - "BULLETED_LIST_SAMPLE_TEXT": "Din tekst her...", - "NUMERIC_LIST_BUTTON": "Numerisk liste", - "NUMERIC_LIST_SAMPLE_TEXT": "Din tekst her...", - "PICTURE_BUTTON": "Bilde", - "PICTURE_SAMPLE_TEXT": "Din alternative tekst til bildet her...", - "LINK_BUTTON": "Lenke", - "LINK_SAMPLE_TEXT": "Din tekst til lenken her...", - "QUOTE_BLOCK_BUTTON": "Sitatblokk", - "QUOTE_BLOCK_SAMPLE_TEXT": "Din tekst her...", - "CODE_BLOCK_BUTTON": "Kodeblokk", - "CODE_BLOCK_SAMPLE_TEXT": "Din tekst her...", - "PREVIEW_BUTTON": "Forhåndsvisning", - "EDIT_BUTTON": "Endre", - "ATTACH_FILE_HELP": "Legg ved filer ved å dra og slippe på tekstområdet ovenfor.", - "ATTACH_FILE_HELP_SAVE_FIRST": "Save first before if you want to attach files by dragging & dropping on the textarea above.", + "OUTDATED": "Another person has made changes while you were editing. Check the new version on the activiy tab before you save your changes.", "MARKDOWN_HELP": "Markdown syntaks hjelp" }, "PERMISIONS_CATEGORIES": { @@ -307,10 +266,6 @@ "ADD_WIKI_LINKS": "Legg til wiki-lenker", "DELETE_WIKI_LINKS": "Slett wiki-lenker" } - }, - "META": { - "PAGE_TITLE": "Taiga", - "PAGE_DESCRIPTION": "Taiga er en prosjektstyringsplatform for oppstartsbedrifter og agile utviklere & designere som vil ha et enkelt, nydelig verktøy som gjør arbeidet virkelig hyggelig." } }, "LOGIN": { @@ -366,7 +321,6 @@ }, "CHANGE_PASSWORD": { "PAGE_TITLE": "Endre ditt passord - Taiga", - "PAGE_DESCRIPTION": "Angi et nytt passord for din Taiga konto og hei!, det kan være lurt å spise litt mer jern-rik mat, det er godt for hjernen din :P", "SECTION_NAME": "Endre passord", "FIELD_CURRENT_PASSWORD": "Nåværende passord", "PLACEHOLDER_CURRENT_PASSWORD": "Din nåværende passord (eller tomt hvis du ikke har ett)", @@ -391,8 +345,7 @@ }, "INVITATION_LOGIN_FORM": { "NOT_FOUND": "Våre Oompa Loompas can ikke finne invitasjonen din.", - "SUCCESS": "Du er nå sluttet til prosjektet {{project_name}}, velkommen!", - "ERROR": "I følge våre Oompa Loompas har du ikke registert deg ennå eller skrevet et ugyldig passord" + "SUCCESS": "Du er nå sluttet til prosjektet {{project_name}}, velkommen!" }, "HOME": { "PAGE_TITLE": "Hjem - Taiga", @@ -463,10 +416,7 @@ "TITLE_LIGHTBOX_DELETE_ATTACHMENT": "Slett vedlegg...", "MSG_LIGHTBOX_DELETE_ATTACHMENT": "vedlegget '{{fileName}}'", "ERROR_DELETE_ATTACHMENT": "Vi hadde ikke mulighet til å slette: {{errorMessage}}", - "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) er for stor for våre Oompa Loompaer. Prøv med en mindre enn ({{maxFileSize}})", - "FIELDS": { - "IS_DEPRECATED": "Er foreldet" - } + "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) er for stor for våre Oompa Loompaer. Prøv med en mindre enn ({{maxFileSize}})" }, "PAGINATION": { "PREVIOUS": "Forrige", @@ -502,13 +452,10 @@ "ASYNC_MESSAGE": "Vi sender deg en epost når det er klart.", "SYNC_MESSAGE": "Hvis nedlastningen ikke starter automatisk, klikk her.", "ERROR": "Våre Oompa Loompaer har problemer med å generere din data dump. Vennligst prøv på nytt.", - "ERROR_BUSY": "Beklager, våre Oompa Loomper er svært opptatt akkuratt nå. Venligst prøv igjen om noen få minutter.", - "ERROR_MESSAGE": "Våre Oompa Loompaer har problemer med å generere din dump: {{message}}" + "ERROR_BUSY": "Beklager, våre Oompa Loomper er svært opptatt akkuratt nå. Venligst prøv igjen om noen få minutter." }, "MODULES": { "TITLE": "Moduler", - "ENABLE": "Aktiver", - "DISABLE": "Deaktiver", "EPICS": "Epics", "EPICS_DESCRIPTION": "Visualize and manage the most strategic part of your project", "BACKLOG": "Backlog", @@ -537,17 +484,16 @@ "PAGE_TITLE": "{{sectionName}} - Prosjektprofil - {{projectName}}", "PROJECT_DETAILS": "Prosjektdetaljer", "PROJECT_NAME": "Prosjektnavn", - "PROJECT_SLUG": "Prosjekt slug", "TAGS": "Etiketter", "DESCRIPTION": "Beskrivelse", "RECRUITING": "Leter dette prosjektet etter folk?", "RECRUITING_MESSAGE": "Hva leter du etter?", "RECRUITING_PLACEHOLDER": "Definer profilene du leter etter", + "FEEDBACK": "Receive feedback from Taiga users?", "PUBLIC_PROJECT": "Offentlig prosjekt", "PRIVATE_PROJECT": "Privat prosjekt", "PRIVATE_OR_PUBLIC": "Hva er forskjellen mellom offentlige og private prosjekt?", "DELETE": "Slett dette prosjektet", - "LOGO_HELP": "Bildet vil bli skalert til 80x80px.", "CHANGE_LOGO": "Endre logo", "ACTION_USE_DEFAULT_LOGO": "Bruk standardbilde", "MAX_PRIVATE_PROJECTS": "Du har nådd maksimalt antall private prosjekter som tillates med din gjeldende plan", @@ -595,6 +541,7 @@ "ISSUE_DESCRIPTION": "Hendelser egendefinerte felter", "ISSUE_ADD": "Legg til et egendefinert felt i Hendelser", "FIELD_TYPE_TEXT": "Tekst", + "FIELD_TYPE_RICHTEXT": "Rich text", "FIELD_TYPE_MULTI": "Flere linjer", "FIELD_TYPE_DATE": "Dato", "FIELD_TYPE_URL": "Url" @@ -623,7 +570,7 @@ "ACTION_ADD": "Legg til ny alvorlighetsgrad" }, "PROJECT_VALUES_STATUS": { - "TITLE": "Status", + "TITLE": "Statuses", "SUBTITLE": "Angi statusene som dine brukerhistorier, oppgaver og hendelser vil følge", "EPIC_TITLE": "Epic Statuses", "US_TITLE": "User Story Statuses", @@ -676,8 +623,8 @@ "INFO_VERIFYING_IP": "GitHub-forespørsler er ikke signert så den beste måten å verifisere opprinnelsen på er med IP. Hvis feltet er tomt blir det ingen IP validering." }, "GITHUB": { - "SECTION_NAME": "Github", - "PAGE_TITLE": "Github - {{projectName}}" + "SECTION_NAME": "GitHub", + "PAGE_TITLE": "GitHub - {{projectName}}" }, "GOGS": { "SECTION_NAME": "Gogs", @@ -686,7 +633,6 @@ "WEBHOOKS": { "PAGE_TITLE": "Webhooks - {{projectName}}", "SECTION_NAME": "Webkoblinger", - "SUBTITLE": "Webkoblinger varsler eksterne tjenester om hendelser i Taiga, som kommentarer, brukerhistorier ....", "ADD_NEW": "Legg til en ny webkobling", "TYPE_NAME": "Skriv inn tjenestenavn", "TYPE_PAYLOAD_URL": "Skriv inn tjenestens payload url", @@ -732,7 +678,6 @@ "DELETE_MEMBER": "Slett medlem", "RESEND": "Send igjen", "SUCCESS_SEND_INVITATION": "Vi har sendt invitasjonen på nytt til '{{email}}'.", - "ERROR_SEND_INVITATION": "Vi har ikke sendt invitasjonen.", "SUCCESS_DELETE": "Vi har slettet {{message}}.", "ERROR_DELETE": "Vi har ikke vært i stand til å slette {{message}}.", "DEFAULT_DELETE_MESSAGE": "invitasjonen til {{epost}}" @@ -761,16 +706,11 @@ "PLACEHOLDER_WRITE_NAME": "Skriv et navn til den nye statusen" }, "MENU": { - "TITLE": "Admin", "PROJECT": "Prosjekt", "ATTRIBUTES": "Egenskaper", "MEMBERS": "Medlemmer", "PERMISSIONS": "Tilganger", - "INTEGRATIONS": "Integrasjoner", - "PLUGINS": "Programtillegg" - }, - "SUBMENU_PROJECT_ATTRIBUTES": { - "TITLE": "Egenskaper" + "INTEGRATIONS": "Integrasjoner" }, "SUBMENU_PROJECT_VALUES": { "STATUS": "Status", @@ -781,17 +721,11 @@ "CUSTOM_FIELDS": "Egendefinerte felter", "TAGS": "Etiketter" }, - "SUBMENU_PROJECT_PROFILE": { - "TITLE": "Prosjektprofil" - }, "SUBMENU_ROLES": { "TITLE": "Roller", "ACTION_NEW_ROLE": "+ Ny rolle", "TITLE_ACTION_NEW_ROLE": "Legg til ny rolle" }, - "SUBMENU_THIDPARTIES": { - "TITLE": "Tjenester" - }, "PROJECT_TRANSFER": { "DO_YOU_ACCEPT_PROJECT_OWNERNSHIP": "Har du lyst til å bli den nye prosjekteieren?", "PRIVATE": "Privat", @@ -806,15 +740,13 @@ "PRIVATE": "Husk, du kan eie opp til {{maxProjects}} private prosjekter. Du eier for tiden {{currentProjects}} private prosjekter", "PUBLIC": "Husk, du kan eie opp til {{maxProjects}} offentlige prosjekter. Du eier foreløpig {{currentProjects}} offentlige prosjekter" }, - "CANT_BE_OWNED": "For øyeblikket kan du ikke bli eier av et prosjekt av denne typen. Dersom du ønsker å bli eier av dette prosjektet, venligst kontakt en administrator så de kan endre dine kontoinstillinger slik at du kan eie et prosjekt.", - "CHANGE_MY_PLAN": "Endre min plan" + "CANT_BE_OWNED": "For øyeblikket kan du ikke bli eier av et prosjekt av denne typen. Dersom du ønsker å bli eier av dette prosjektet, venligst kontakt en administrator så de kan endre dine kontoinstillinger slik at du kan eie et prosjekt." } }, "USER": { "PROFILE": { "PAGE_TITLE": "{{userFullName}} (@{{userUsername}})", "EDIT": "Endre profil", - "FOLLOW": "Følg", "CLOSED_US": "Lukket historie", "PROJECTS": "Prosjekter", "PROJECTS_EMPTY": "{{username}} har ikke prosjekter enda", @@ -822,7 +754,6 @@ "CONTACTS_EMPTY": "{{username}} har ingen kontakter enda", "CURRENT_USER_CONTACTS_EMPTY": "Du har ingen kontakter enda", "CURRENT_USER_CONTACTS_EMPTY_EXPLAIN": "Personene som du jobber sammen med i Taiga vil automatisk bli dine kontakter", - "REPORT": "Rapporter misbruk", "TABS": { "ACTIVITY_TAB": "Tidslinje", "ACTIVITY_TAB_TITLE": "Vis all aktiviteten til denne brukeren", @@ -848,13 +779,13 @@ "FILTER_TYPE_ALL": "Alle", "FILTER_TYPE_ALL_TITLE": "Vis alle", "FILTER_TYPE_PROJECTS": "Prosjekter", - "FILTER_TYPE_PROJECT_TITLES": "Vis kun prosjekter", + "FILTER_TYPE_PROJECTS_TITLE": "Vis kun prosjekter", "FILTER_TYPE_EPICS": "Epics", - "FILTER_TYPE_EPIC_TITLES": "Show only epics", + "FILTER_TYPE_EPICS_TITLE": "Show only epics", "FILTER_TYPE_USER_STORIES": "Historier", - "FILTER_TYPE_USER_STORIES_TITLES": "Vis kun brukerhistorier", + "FILTER_TYPE_USER_STORIES_TITLE": "Vis kun brukerhistorier", "FILTER_TYPE_TASKS": "Oppgaver", - "FILTER_TYPE_TASK_TITLES": "Vis kun oppgaver", + "FILTER_TYPE_TASKS_TITLE": "Vis kun oppgaver", "FILTER_TYPE_ISSUES": "Hendelser", "FILTER_TYPE_ISSUES_TITLE": "Vis kun hendelser", "EMPTY_TITLE": "Det ser ut som om det ikke er noe å vise her." @@ -862,8 +793,6 @@ }, "PROJECT": { "PAGE_TITLE": "{{projectName}}", - "WELCOME": "Velkommen", - "SECTION_PROJECTS": "Prosjekter", "HELP": "Reorganiser prosjektene dine etter de mest brukte.
De topp 10 mest brukte prosjektene vil vises i navigasjonslenken på toppen.", "PRIVATE": "Privat prosjekt", "LOOKING_FOR_PEOPLE": "Dette prosjekter søker etter mennesker", @@ -875,12 +804,6 @@ "THIS_PROJECT_IS_BLOCKED": "Dette prosjektet er midlertidig blokkert", "TO_UNBLOCK_CONTACT_THE_ADMIN_STAFF": "For å avblokkere dine prosjekter, kontakt administratoren" }, - "STATS": { - "PROJECT": "prosjekt
poeng", - "DEFINED": "definerte
poeng", - "ASSIGNED": "tildelte
poeng", - "CLOSED": "lukkede
poeng" - }, "SECTION": { "SEARCH": "Søk", "TIMELINE": "Tidslinje", @@ -893,15 +816,9 @@ "ADMIN": "Admin" }, "NAVIGATION": { - "SECTION_TITLE": "Dine prosjekter", - "PLACEHOLDER_SEARCH": "Søk i...", "ACTION_CREATE_PROJECT": "Opprett prosjekt", - "ACTION_IMPORT_PROJECT": "Importer prosjekt", "MANAGE_PROJECTS": "Håndter prosjekter", "TITLE_CREATE_PROJECT": "Opprett prosjekt", - "TITLE_IMPORT_PROJECT": "Importer prosjekt", - "TITLE_PRVIOUS_PROJECT": "Vis forrige prosjekter", - "TITLE_NEXT_PROJECT": "Vis neste prosjekter", "HELP_TITLE": "Taiga Brukerstøtte", "HELP": "Hjelp", "HOMEPAGE": "Hjemmeside", @@ -909,10 +826,6 @@ "FEEDBACK": "Tilbakemelding", "NOTIFICATIONS_TITLE": "Endre dine varslingsinstillinger", "NOTIFICATIONS": "Varsler", - "ORGANIZATIONS_TITLE": "Rediger dine organisasjoner", - "ORGANIZATIONS": "Endre organisasjoner", - "SETTINGS_TITLE": "Endre dine instillinger", - "SETTINGS": "Instillinger", "VIEW_PROFILE_TITLE": "Vis Profil", "VIEW_PROFILE": "Vis Profil", "EDIT_PROFILE_TITLE": "Rediger din profil", @@ -921,14 +834,68 @@ "CHANGE_PASSWORD": "Endre passord", "DASHBOARD_TITLE": "Dashbord", "DISCOVER_TITLE": "Oppdag populære prosjekter", - "NEW_ITEM": "Ny", - "DISCOVER": "Oppdag", - "ACTION_REORDER": "Dra & slipp for å omorganisere" + "DISCOVER": "Oppdag" + }, + "LIKE_BUTTON": { + "LIKE": "Liker", + "LIKED": "Likt", + "UNLIKE": "Ikke lik", + "BUTTON_TITLE": "Like eller ikke like dette prosjektet", + "COUNTER_TITLE": "{total, plural, one{en fan} other{# fans}}" + }, + "WATCH_BUTTON": { + "BUTTON_TITLE": "Overvåk dette prosjektet og sett varslingsstrategi", + "WATCH": "Følg", + "WATCHING": "Følger med på", + "COUNTER_TITLE": "{total, plural, one{en følger} other{# følgere}}", + "OPTIONS": { + "NOTIFY_ALL": "Motta alle varsler", + "NOTIFY_ALL_TITLE": "Motta alle varsler for dette prosjektet", + "NOTIFY_INVOLVED": "Kun involvert", + "NOTIFY_INVOLVED_TITLE": "Motta varsler kun når du er involvert", + "UNWATCH": "Ikke overvåk", + "UNWATCH_TITLE": "Ikke overvåk dette prosjektet" + } + }, + "CONTACT_BUTTON": { + "CONTACT_TITLE": "Contact the project team", + "CONTACT_BUTTON": "Contact the project" + }, + "CREATE": { + "TITLE": "Opprett prosjekt", + "CHOOSE_TEMPLATE": "Which template fits your project better?", + "TEMPLATE_SCRUM": "Scrum", + "TEMPLATE_SCRUM_DESC": "Prioritize and solve your tasks in short time cycles.", + "TEMPLATE_SCRUM_LONGDESC": "Scrum is an iterative and incremental agile software development methodology for managing product development.\nThe product backlog is what will ultimately be delivered, ordered into the sequence in which it should be delivered. Product Backlogs are broken into manageable, executable chunks named sprints. Every certain amount of time the team initiates a new sprint and commits to deliver a certain number of user stories from the backlog, in accordance with their skills, abilities and resources. The project advances as the backlog becomes depleted.", + "TEMPLATE_KANBAN": "Kanban", + "TEMPLATE_KANBAN_DESC": "Keep a constant workflow on independent tasks", + "TEMPLATE_KANBAN_LONGDESC": "The Kanban methodology is used to divide project development (any sort of project) into stages.\nA kanban card is like an index card or post-it note that details every task (or user story) in a project that needs to be completed. The Kanban board is used to move each card from one state of completion to the next and in so doing, helps track progress.", + "DUPLICATE": "Duplicate project", + "DUPLICATE_DESC": "Start clean and keep your configuration", + "IMPORT": "Importer prosjekt", + "IMPORT_DESC": "Import your project from multiple platforms into Taiga", + "INVITE": "Invite to the project", + "SOLO_PROJECT": "You'll be alone in this project", + "INVITE_LATER": "(You'll be able to invite more members later)", + "BACK": "Back", + "MAX_PRIVATE_PROJECTS": "Unfortunately, You've reached the maximum number of private projects.\nIf you would like to increase the current limit please contact the administrator.", + "MAX_PUBLIC_PROJECTS": "Unfortunately, You've reached the maximum number of public projects.\nIf you would like to increase the current limit please contact the administrator.", + "PUBLIC_PROJECT": "Offentlig Prosjekt", + "PRIVATE_PROJECT": "Privat Prosjekt" + }, + "COMMON": { + "DETAILS": "New project details", + "PROJECT_TITLE": "Project Name", + "PROJECT_DESCRIPTION": "Project Description" + }, + "DUPLICATE": { + "TITLE": "Duplicate Project", + "DESCRIPTION": "Start clean and keep your configuration", + "SELECT_PLACEHOLDER": "Choose an existing project to duplicate" }, "IMPORT": { - "TITLE": "Importer prosjekt", - "UPLOADING_FILE": "Laster opp dump-fil", - "DESCRIPTION": "Denne prosessen kan ta en stund, vennligst hold vinduet åpent.", + "TITLE": "Import Project", + "DESCRIPTION": "Import your project from multiple platforms into Taiga", "ASYNC_IN_PROGRESS_TITLE": "Våre Oompa Loompaer importerer ditt prosjekt", "ASYNC_IN_PROGRESS_MESSAGE": "Denne prosessen kan ta noen minutter
Vi vil sende deg en e-post når den er klar", "UPLOAD_IN_PROGRESS_MESSAGE": "Opplastet {{uploadedSize}} av {{totalSize}}", @@ -937,8 +904,29 @@ "ERROR_MESSAGE": "Våre Oompa Loompaer har problemer med å importere din data-dump: {{error_message}}", "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) er for stor for våre Oompa Loompaer. Prøv med en mindre enn ({{maxFileSize}})", "SYNC_SUCCESS": "Importen av ditt prosjekt var vellykket", + "IMPORT": "Import", + "WHO_IS": "Their tasks will be assigned to ...", + "WRITE_EMAIL": "Or if you want, write the email that this user uses in Taiga", + "SEARCH_CONTACT": "Or if you want, search in your contacts", + "WRITE_EMAIL_LABEL": "Write the email that this user uses in Taiga", + "ACCEEDE": "Acceede", + "PROJECT_MEMBERS": "Prosjektmedlemmer", + "PROCESS_DESCRIPTION": "Tell us who from Taiga you want to assign the tasks of {{platform}}", + "MATCH": "Is {{user_external}} the same person as {{user_internal}}?", + "CHOOSE": "Select user", + "LINKS": "Links with {{platform}}", + "LINKS_DESCRIPTION": "Do you want to keep the link of each item with the original {{platform}} card?", + "WARNING_MAIL_USER": "Note that if the user does not have a Taiga account we will not be able to assign the tasks to him.", + "ASSIGN": "Tildel", + "PROJECT_SELECTOR": { + "NO_RESULTS": "It looks like nothing was found with your search criteria", + "ACTION_SEARCH": "søk", + "ACTION_BACK": "Back" + }, "PROJECT_RESTRICTIONS": { - "PROJECT_MEMBERS_DESC": "Prosjektet du prøver å importere har {{members}} medlemmer. Dessverre, din nåværende plan tillater kun {{max_memberships}} medlemmer per prosjekt. Hvis du ønsker å øke denne grensen, vennligst kontakt administratoren.", + "PROJECT_MEMBERS_DESC_PRIVATE": "The project you are trying to import has {{members}} members including you, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per private project. If you would like to increase that limit please contact the administrator.", + "PROJECT_MEMBERS_DESC_PUBLIC": "The project you are trying to import has {{members}} members including you, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per public project. If you would like to increase that limit please contact the administrator.", + "ACCOUNT_ALLOW_MEMBERS": "Your account only allows {{members}} members", "PRIVATE_PROJECTS_SPACE": { "TITLE": "Dessverre, din nåværende plan tillater ikke private prosjekter", "DESC": "Prosjektet du prøver å importere er privat. Dessverre tillater ikke din gjeldende flere private prosjekter." @@ -961,39 +949,67 @@ "TITLE": "Dessverre, din nåværende plan tillater ikke flere offentlige prosjekter eller en økning til fler enn {{max_memberships}} medlemmer per offentlige prosjekt", "DESC": "Prosjektet du prøver å importere er offentlig og har fler enn {{members}} medlemmer." } - } - }, - "LIKE_BUTTON": { - "LIKE": "Liker", - "LIKED": "Likt", - "UNLIKE": "Ikke lik", - "BUTTON_TITLE": "Like eller ikke like dette prosjektet", - "COUNTER_TITLE": "{total, plural, one{en fan} other{# fans}}" - }, - "WATCH_BUTTON": { - "BUTTON_TITLE": "Overvåk dette prosjektet og sett varslingsstrategi", - "WATCH": "Følg", - "WATCHING": "Følger med på", - "COUNTER_TITLE": "{total, plural, one{en følger} other{# følgere}}", - "OPTIONS": { - "NOTIFY_ALL": "Motta alle varsler", - "NOTIFY_ALL_TITLE": "Motta alle varsler for dette prosjektet", - "NOTIFY_INVOLVED": "Kun involvert", - "NOTIFY_INVOLVED_TITLE": "Motta varsler kun når du er involvert", - "UNWATCH": "Ikke overvåk", - "UNWATCH_TITLE": "Ikke overvåk dette prosjektet" + }, + "IN_PROGRESS": { + "TITLE": "Importer prosjekt", + "DESCRIPTION": "Denne prosessen kan ta en stund, vennligst hold vinduet åpent." + }, + "WARNING": { + "TITLE": "Some taks will be unassigned", + "DESCRIPTION": "There are still unidentified people. The cards assigned to these people will remain unassigned. Check all the contacts to not lose that information.", + "CHECK": "Check contacts" + }, + "TAIGA": { + "SELECTOR": "Import your Taiga project" + }, + "TRELLO": { + "SELECTOR": "Import your Trello boards into Taiga", + "CHOOSE_PROJECT": "Choose board that you want to import", + "NO_PROJECTS": "It seems you have no boards in Trello" + }, + "GITHUB": { + "SELECTOR": "Import your GitHub project issues", + "CHOOSE_PROJECT": "Find the project you want to import", + "NO_PROJECTS": "It seems you have no porjects in GitHub", + "HOW_DO_YOU_WANT_TO_IMPORT": "How do you want to import your issues into Taiga?", + "KANBAN_PROJECT": "As user stories in a kanban project", + "KANBAN_PROJECT_DESCRIPTION": "After that you can enable scrum with backlog.", + "SCRUM_PROJECT": "As user stories in a scrum project", + "SCRUM_PROJECT_DESCRIPTION": "After that you can enable kanban mode.", + "ISSUES_PROJECT": "As issues", + "ISSUES_PROJECT_DESCRIPTION": "You will not be able to use your issues in kanban or scrum mode. You will be able to enable kanban or scrum for new user stories" + }, + "ASANA": { + "SELECTOR": "Import your Asana project and choose how to manage it", + "CHOOSE_PROJECT": "Choose project that you want to import", + "NO_PROJECTS": "It seems you have no porjects in Asana", + "KANBAN_PROJECT": "Kanban", + "SCRUM_PROJECT": "Scrum", + "CREATE_AS_SCRUM_DESCRIPTION": "The tasks and sub-tasks of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_KANBAN_DESCRIPTION": "The tasks and sub-tasks of your project will be created as Taiga user stories and tasks." + }, + "JIRA": { + "SELECTOR": "Import your Jira project and choose how to manage it", + "CHOOSE_PROJECT": "Choose project or board that you want to import", + "NO_PROJECTS": "It seems you have no porjects or boards in Jira", + "URL": "Your Jira URL", + "KANBAN_PROJECT": "Kanban", + "SCRUM_PROJECT": "Scrum", + "ISSUES_PROJECT": "Hendelser", + "CREATE_AS_SCRUM_DESCRIPTION": "The issues and sub-issues of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_KANBAN_DESCRIPTION": "The issues and sub-issues of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_ISSUES_DESCRIPTION": "What do you want to do with sub-issues from the Jira project? (Taiga doesn't allow sub-issues)", + "CREATE_NEW_ISSUES": "Convert sub-issues to new Taiga issues", + "NOT_CREATE_NEW_ISSUES": "Do not import sub-issues" } } }, "LIGHTBOX": { "DELETE_ACCOUNT": { - "SECTION_NAME": "Slett din Taiga konto", "CONFIRM": "Er du sikker på at du vil slette din Taiga konto?", - "NEWSLETTER_LABEL_TEXT": "Jeg vil ikke motta flere nyhetsbrev", "CANCEL": "Tilbake til instillinger", "ACCEPT": "Slett konto", - "BLOCK_PROJECT": "Merk at alle prosjektene der du står som eier vil bli blokkert etter at du sletter din konto. Dersom du ikke ønsker dette, overfør eierskapet til et annet medlem før du sletter kontoen.", - "SUBTITLE": "Det er synd å se at du forlater oss. Vi er her, skulle du noen sinne vurdere oss igjen! :(" + "BLOCK_PROJECT": "Merk at alle prosjektene der du står som eier vil bli blokkert etter at du sletter din konto. Dersom du ikke ønsker dette, overfør eierskapet til et annet medlem før du sletter kontoen." }, "DELETE_PROJECT": { "TITLE": "Slett prosjekt", @@ -1007,6 +1023,12 @@ }, "ADD_MEMBER": { "TITLE": "Nytt medlem", + "PLACEHOLDER": "Filter users or write an email to invite", + "ADD_EMAIL": "Add email", + "REMOVE": "Remove", + "INVITE": "Invite", + "CHOOSE_ROLE": "Choose a role", + "PLACEHOLDER_INVITATION_TEXT": "(Valgfritt) Legg til en egen tekst til invitasjonen. Fortell dine nye medlemmer noe fantastisk ;-)", "HELP_TEXT": "Hvis brukere allerede er registrerte på Taiga, vil de bli lagt til automatisk. Ellers vil de motta en invitasjon." }, "CREATE_ISSUE": { @@ -1068,6 +1090,12 @@ "TITLE": "Hvem vil du at skal være den nye eieren av prosjektet?", "ADD_COMMENT": "Legg til kommentar", "BUTTON": "Spør dette prosjektetmedlemet om å bli den nye prosjekteieren" + }, + "CONTACT_PROJECT": { + "TITLE": "Send an email to", + "WARNING": "The email will be received by the project admins", + "PLACEHOLDER": "Write your message", + "SEND": "Send" } }, "EPIC": { @@ -1101,15 +1129,9 @@ "ADD_BULK": "Legg til mange nye Brukerhistorier", "PROMOTED": "Denne Brukerhistorien har blitt oppgradert fra Hendelse:", "TITLE_LINK_GO_TO_ISSUE": "Gå til hendelse", - "EXTERNAL_REFERENCE": "Denne BH ble opprettet av", - "GO_TO_EXTERNAL_REFERENCE": "Gå til opphav", - "BLOCKED": "Denne brukerhistorien er blokkert", "TITLE_DELETE_ACTION": "Slett Brukerhistorie", "LIGHTBOX_TITLE_BLOKING_US": "Blokkerer oss", - "TASK_COMPLETED": "{{totalClosedTasks}}/{{totalTasks}} oppgaver ferdigstilt", - "ASSIGN": "Tildel Brukerhistorie", "NOT_ESTIMATED": "Ikke estimert", - "TOTAL_US_POINTS": "Total BH poeng", "TRIBE": { "PUBLISH": "Publish as Gig in Taiga Tribe", "PUBLISH_INFO": "Mer info", @@ -1119,23 +1141,19 @@ "CLOSE": "Close", "SYNCHRONIZE_LINK": "synchronize with Taiga Tribe", "PUBLISH_MORE_INFO_TITLE": "Do you need somebody for this task?", - "PUBLISH_MORE_INFO_TEXT": "

If you need help with a particular piece of work you can easily create gigs on Taiga Tribe and receive help from all over the world. You will be able to control and manage the gig enjoying a great community eager to contribute.

TaigaTribe was born as a Taiga sibling. Both platforms can live separately but we believe that there is much power in using them combined so we are making sure the integration works like a charm.

" + "PUBLISH_MORE_INFO_TEXT": "

If you need help with a particular piece of work you can easily create gigs on Taiga Tribe and receive help from all over the world. You will be able to control and manage the gig enjoying a great community eager to contribute.

TaigaTribe was born as a Taiga sibling. Both platforms can live separately but we believe that there is much power in using them combined so we are making sure the integration works like a charm.

" }, "FIELDS": { "TEAM_REQUIREMENT": "Team behov", - "CLIENT_REQUIREMENT": "Klientkrav", - "FINISH_DATE": "Sluttdato" + "CLIENT_REQUIREMENT": "Klientkrav" } }, "COMMENTS": { "DELETED_INFO": "Comment deleted by {{user}}", - "TITLE": "Kommentarer", "COMMENTS_COUNT": "{{comments}} Comments", - "ORDER": "Order", "OLDER_FIRST": "Older first", "RECENT_FIRST": "Recent first", "COMMENT": "Kommentar", - "EDIT_COMMENT": "Edit comment", "EDITED_COMMENT": "Edited:", "SHOW_HISTORY": "View historic", "TYPE_NEW_COMMENT": "Skriv en ny kommentar her", @@ -1148,13 +1166,8 @@ } }, "ACTIVITY": { - "SHOW_ACTIVITY": "Vis aktivitet", - "DATETIME": "DD MMM YYYY HH:mm", - "SHOW_MORE": "+ Vis tidligere innlegg ({{showMore}} mer)", "TITLE": "Aktivitet", "ACTIVITIES_COUNT": "{{activities}} Activities", - "REMOVED": "fjernet", - "ADDED": "lagt til", "TAGS_ADDED": "tags added:", "TAGS_REMOVED": "tags removed:", "US_POINTS": "{{role}} points", @@ -1163,50 +1176,21 @@ "UPDATED_ATTACHMENT": "updated attachment ({{filename}}):", "CREATED_CUSTOM_ATTRIBUTE": "created custom attribute", "UPDATED_CUSTOM_ATTRIBUTE": "updated custom attribute", - "SIZE_CHANGE": "Gjorde {size, plural, one{en endring} other{# endringer}}", "BECAME_DEPRECATED": "became deprecated", "BECAME_UNDEPRECATED": "became undeprecated", "TEAM_REQUIREMENT": "Team behov", "CLIENT_REQUIREMENT": "Klientkrav", "BLOCKED": "Blokkert", "VALUES": { - "YES": "ja", - "NO": "nei", - "EMPTY": "tomt", "UNASSIGNED": "ikke tildelt" }, "FIELDS": { "SUBJECT": "subjekt", - "NAME": "navn", "DESCRIPTION": "beskrivelse", - "CONTENT": "innhold", "STATUS": "status", - "IS_CLOSED": "er lukket", - "FINISH_DATE": "Sluttdato", "TYPE": "type", - "PRIORITY": "prioritet", - "SEVERITY": "Alvorlighetsgrad", "ASSIGNED_TO": "tildelt til", - "WATCHERS": "følgere", "MILESTONE": "sprint", - "USER_STORY": "brukerhistorie", - "PROJECT": "prosjekt", - "IS_BLOCKED": "er blokkert", - "BLOCKED_NOTE": "blokkert notat", - "POINTS": "poeng", - "CLIENT_REQUIREMENT": "klientkrav", - "TEAM_REQUIREMENT": "team behov", - "IS_IOCAINE": "Er Iocaine", - "TAGS": "etiketter", - "ATTACHMENTS": "vedlegg", - "IS_DEPRECATED": "Er foreldet", - "IS_NOT_DEPRECATED": "is not deprecated", - "ORDER": "rekkefølge", - "BACKLOG_ORDER": "backlog rekkefølge", - "SPRINT_ORDER": "sprint rekkefølge", - "KANBAN_ORDER": "kanban rekkefølge", - "TASKBOARD_ORDER": "Oppgavetavle rekkefølge", - "US_ORDER": "BH rekkefølge", "COLOR": "farge" } }, @@ -1220,8 +1204,6 @@ "CUSTOMIZE_GRAPH_TITLE": "Sett opp poengene og sprintene gjennom Admin-panelet", "MOVE_US_TO_CURRENT_SPRINT": "Gå til nåværende sprint", "MOVE_US_TO_LATEST_SPRINT": "Flytt til siste Sprint", - "SHOW_FILTERS": "Vis filtre", - "SHOW_TAGS": "Vis etiketter", "EMPTY": "Backlogen er tom!", "CREATE_NEW_US": "Opprett en ny BH", "CREATE_NEW_US_EMPTY_HELP": "Det kan være lurt å opprette en ny brukerhistorie", @@ -1248,6 +1230,12 @@ "SHOW": "Vis etiketter", "HIDE": "Skjul etiketter" }, + "FORECASTING": { + "TITLE": "Velocity forecasting", + "BACKLOG": "Display backlog", + "NEW_SPRINT": "Candidate User Stories for your next sprint based on your velocity. Click to create a new sprint.", + "CURRENT_SPRINT": "Candidate User Stories for your sprint based on your velocity. Click to add to current sprint." + }, "TABLE": { "COLUMN_US": "Brukerhistorie", "TITLE_COLUMN_POINTS": "Velg visning per Rolle" @@ -1270,8 +1258,6 @@ }, "FILTERS": { "TOGGLE": "Veksle filteres synlighet", - "TITLE": "Filter", - "REMOVE": "Fjern Filtere", "HIDE": "Skjul Filtere", "SHOW": "Vis Filtere" }, @@ -1280,7 +1266,6 @@ "DATE": "DD MMM YYYY", "LINK_TASKBOARD": "Sprint Oppgavepanel", "TITLE_LINK_TASKBOARD": "Gå til Oppgavepanel for \"{{name}}\"", - "NUMBER_SPRINTS": "
sprinter", "EMPTY": "Det er ingen sprinter enda", "WARNING_EMPTY_SPRINT_ANONYMOUS": "Denne sprinten har ingen Brukerhistorier", "WARNING_EMPTY_SPRINT": "Slipp Brukerhistorier her fra din backlog for å starte en ny sprint", @@ -1305,7 +1290,6 @@ "TITLE_ACTION_ADD": "Legg til en ny oppgave", "TITLE_ACTION_ADD_BULK": "Legg til noen nye Oppgaver samlet", "TITLE_ACTION_ASSIGN": "Tildel oppgave", - "TITLE_ACTION_EDIT": "Rediger oppgave", "PLACEHOLDER_CARD_TITLE": "Dette kunne vært en oppgave", "PLACEHOLDER_CARD_TEXT": "Splitt historier inn i oppgaver og følg dem separat", "TABLE": { @@ -1335,17 +1319,11 @@ "TITLE_SELECT_STATUS": "Status Navn", "OWNER_US": "Denne oppgaven tilhører", "TITLE_LINK_GO_OWNER": "Gå til brukerhistorie", - "ORIGIN_US": "Denne oppgaven har blitt opprettet fra", - "TITLE_LINK_GO_ORIGIN": "Gå til brukerhistorie", - "BLOCKED": "Denne oppgaven er blokkert", "TITLE_DELETE_ACTION": "Slett oppgave", "LIGHTBOX_TITLE_BLOKING_TASK": "Blokkerende oppgave", "FIELDS": { - "MILESTONE": "Sprint", - "USER_STORY": "Brukerhistorie", "IS_IOCAINE": "Er Iocaine" }, - "ACTION_IOCAINE": "Iocaine", "TITLE_ACTION_IOCAINE": "Føler du deg litt overveldet av en oppgave? Sørg for at andre vet om det ved å klikke på \"Iocane\" når du redigerer en oppgave. Det er mulig å bli immun mot denne (fiktive) dødelige giften ved å konsumere små mengder over tid, akkurat som det er mulig å bli bedre på det du gjør ved av og til å ta på deg ekstra utfordringer!" }, "NOTIFICATION": { @@ -1374,14 +1352,12 @@ "ISSUES": { "PAGE_TITLE": "Hendelser - {{projectName}}", "PAGE_DESCRIPTION": "Hendelsespanelet for prosjekt {{projectName}}: {{projectDescription}}", - "LIST_SECTION_NAME": "Hendelser", "SECTION_NAME": "Hendelse", "ACTION_NEW_ISSUE": "+ NY HENDELSE", "ACTION_PROMOTE_TO_US": "Oppgrader til Brukerhistorie", "PROMOTED": "Denne hendelsen har blitt oppgradert til BH", "EXTERNAL_REFERENCE": "Denne hendelsen har blitt opprettet av", "GO_TO_EXTERNAL_REFERENCE": "Gå til opphav", - "BLOCKED": "Denne hendelsen er blokkert", "ACTION_DELETE": "Slett hendelse", "LIGHTBOX_TITLE_BLOKING_ISSUE": "Blokker hendelse", "FIELDS": { @@ -1423,15 +1399,11 @@ "SECTION_NAME": "Kanban", "TITLE_ACTION_FOLD": "Slå sammen kolonne", "TITLE_ACTION_UNFOLD": "Brett ut kolonne", - "TITLE_ACTION_FOLD_CARDS": "Brett kort", - "TITLE_ACTION_UNFOLD_CARDS": "Brett ut kort", "TITLE_ACTION_ADD_US": "Legg til ny Brukerhistorie", "TITLE_ACTION_ADD_BULK": "Legg til ny samling", "ACTION_SHOW_ARCHIVED": "Vis arkiverte", "ACTION_HIDE_ARCHIVED": "Skjul arkivert", "HIDDEN_USER_STORIES": "Brukerhistoriene med denne statusen er skjult som standard", - "ARCHIVED": "Du har arkivert", - "UNDO_ARCHIVED": "Dra & slipp igjen for å angre", "PLACEHOLDER_CARD_TITLE": "Dette er dine Brukerhistorier", "PLACEHOLDER_CARD_TEXT": "Historier kan også ha underoppgaver med egne krav" }, @@ -1452,7 +1424,6 @@ "PAGE_TITLE": "Team - {{projectName}}", "PAGE_DESCRIPTION": "Teampanelet for å vise alle medlemmene i prosjektet {{projectName}}: {{projectDescription}}", "SECTION_NAME": "Team", - "APP_TITLE": "TEAM - {{projectName}}", "PLACEHOLDER_INPUT_SEARCH": "Søk på fult navn---", "COLUMN_MR_WOLF": "Mr. Wolf", "EXPLANATION_COLUMN_MR_WOLF": "Lukkede hendelser", @@ -1488,18 +1459,9 @@ "OPTION_ALL": "Alle", "OPTION_INVOLVED": "Involvert", "OPTION_NONE": "Ingen" - }, - "POPOVER": { - "USER_PROFILE": "Brukerprofil", - "CHANGE_PASSWORD": "Endre passord", - "NOTIFICATIONS": "Varsler", - "FEEDBACK": "Tilbakemelding", - "TITLE_AVATAR": "Brukerpreferanser" } }, "USER_PROFILE": { - "IMAGE_HELP": "Bildet vil bli skalert til 80x80px.", - "ACTION_CHANGE_IMAGE": "Endre", "ACTION_USE_GRAVATAR": "Bruk standardbilde", "ACTION_DELETE_ACCOUNT": "Slett Taiga-konto", "CHANGE_EMAIL_SUCCESS": "Sjekk din innboks!
Vi har sent en epost til din konto
med instruksjonene for å velge ny epostadresse.", @@ -1517,25 +1479,10 @@ "THEME_DEFAULT": "-- bruk standard tema --" } }, - "WIZARD": { - "SECTION_TITLE_CREATE_PROJECT": "Opprett prosjekt", - "CREATE_PROJECT_TEXT": "Friskt og stilrent. Så spennende!", - "CHOOSE_TEMPLATE": "Hvilken mal passer ditt prosjekt best?", - "CHOOSE_TEMPLATE_TITLE": "Mer info om prosjektmaler", - "CHOOSE_TEMPLATE_INFO": "Mer info", - "PROJECT_DETAILS": "Prosjektdetaljer", - "PUBLIC_PROJECT": "Offentlig Prosjekt", - "PRIVATE_PROJECT": "Privat Prosjekt", - "CREATE_PROJECT": "Opprett prosjekt", - "MAX_PRIVATE_PROJECTS": "Du har nådd maksimalt antall private prosjekter", - "MAX_PUBLIC_PROJECTS": "Dessverre, du har nådd maksimalt antall offentlige prosjekter", - "CHANGE_PLANS": "endre planer" - }, "WIKI": { "PAGE_TITLE": "{{wikiPageName}} - Wiki - {{projectName}}", "PAGE_DESCRIPTION": "Siste versjon: {{lastModifiedDate}} ({{totalEditions}} versjoner totalt) Innhold: {{ wikiPageContent }}", "DATETIME": "DD MMM YYYY HH:mm", - "PLACEHOLDER_PAGE": "Skriv din wiki-side", "REMOVE": "Fjern denne wiki-siden", "DELETE_LIGHTBOX_TITLE": "Slett wiki-siden", "DELETE_LINK_TITLE": "Slett wiki-lenke", @@ -1693,7 +1640,6 @@ "MOST_LIKED": "Mest likt", "MOST_LIKED_EMPTY": "Det er ingen LIKTE prosjekter enda", "VIEW_MORE": "Vis mer", - "RECRUITING": "Dette prosjekter søker etter mennesker", "FEATURED": "Utvalgte Prosjekter", "EMPTY": "Det er ingen prosjekter å vise med dette søkekriteriet.
Prøv igjen!", "FILTERS": { diff --git a/app/locales/taiga/locale-nl.json b/app/locales/taiga/locale-nl.json index 69990405..03a3c223 100644 --- a/app/locales/taiga/locale-nl.json +++ b/app/locales/taiga/locale-nl.json @@ -4,7 +4,6 @@ "NO": "Nee", "OR": "of", "LOADING": "Aan het laden...", - "LOADING_PROJECT": "Project laden...", "DATE": "DD MMM YYYY", "DATETIME": "DD MMM YYYY HH:mm", "SAVE": "Bewaar", @@ -27,12 +26,9 @@ "BLOCKED_NOTE": "Why is this blocked?", "BLOCKED_REASON": "Gelieve de reden uit te leggen", "CREATED_BY": "Aangemaakt door {{fullDisplayName}}", - "FROM": "van", - "TO": "aan", "CLOSE": "sluiten", "GO_HOME": "Neem me naar de homepage", "PLUGINS": "Plugins", - "BETA": "We zijn in beta!", "ONE_ITEM_LINE": "Eén item per regel...", "NEW_BULK": "Nieuwe bulk toevoeging", "RELATED_TASKS": "Gerelateerde taken", @@ -41,7 +37,7 @@ "LOGOUT": "Afmelden", "EXTERNAL_USER": "een extern gebruiker", "GENERIC_ERROR": "Een van onze Oempa Loempa's zegt {{error}}.", - "IOCAINE_TEXT": "Voel je je wat overweldigd door een taak? Zorg ervoor dat anderen dit weten door op Iocaine te klikken bij het wijzigen van een taak. Je kan stapsgewijs immuun worden tegen dit (fictioneel) dodelijk gif door kleine dosissen op te nemen. Net zoals je beter kan worden in wat je doet door af en toe een extra uitdaging aan te gaan!", + "IOCAINE_TEXT": "This member is feeling a bit overwhelmed by this task. Will become immune to the iocaine poison over time with your help. For now, may need a hug.", "CLIENT_REQUIREMENT": "Client requirement is new requirement that was not previously expected and it is required to be part of the project", "TEAM_REQUIREMENT": "Team requirement is a requirement that must exist in the project but should have no cost for the client", "OWNER": "Project Owner", @@ -148,7 +144,6 @@ "PRIORITY": "Prioriteit", "ASSIGNED_TO": "Toegewezen aan", "POINTS": "Punten", - "BLOCKED_NOTE": "geblokkeerde notitie", "IS_BLOCKED": "is geblokkeerd", "REF": "Ref", "VOTES": "Stemmen", @@ -187,10 +182,6 @@ "COUNTER_TITLE": "{total, plural, one{one watcher} other{# watchers}}" }, "VOTE_BUTTON": { - "UPVOTE": "Upvote", - "UPVOTED": "Upvoted", - "DOWNVOTE": "Downvote", - "VOTERS": "Voters", "BUTTON_TITLE": "Upvote/Downvote this item", "COUNTER_TITLE": "{total, plural, one{one vote} other{# votes}}" }, @@ -202,10 +193,9 @@ "CONFIRM_DELETE": "Remeber that all values in this custom field will be deleted.\n Are you sure you want to continue?" }, "FILTERS": { - "TITLE": "Filters", "INPUT_PLACEHOLDER": "Onderwerp of referentie", "TITLE_ACTION_FILTER_BUTTON": "zoek", - "INPUT_SEARCH_PLACEHOLDER": "Onderwerp of ref.", + "TITLE": "Filters", "TITLE_ACTION_SEARCH": "Zoek", "ACTION_SAVE_CUSTOM_FILTER": "Als eigen filter opslaan", "PLACEHOLDER_FILTER_NAME": "Geef de filternaam in en druk op enter", @@ -220,41 +210,10 @@ "CREATED_BY": "Aangemaakt door", "CUSTOM_FILTERS": "Eigen filters", "EPIC": "Epic" - }, - "CONFIRM_DELETE": { - "TITLE": "Verwijder eigen filter", - "MESSAGE": "de eigen filter '{{customFilterName}}'" } }, "WYSIWYG": { - "H1_BUTTON": "Eerste niveau heading", - "H1_SAMPLE_TEXT": "Jouw titel hier...", - "H2_BUTTON": "Kop tweede niveau", - "H2_SAMPLE_TEXT": "Jouw titel hier...", - "H3_BUTTON": "Kop derde nivea", - "H3_SAMPLE_TEXT": "Jouw titel hier...", - "BOLD_BUTTON": "Vet", - "BOLD_BUTTON_SAMPLE_TEXT": "Je tekst hier...", - "ITALIC_BUTTON": "Cursief", - "ITALIC_SAMPLE_TEXT": "Je tekst hier...", - "STRIKE_BUTTON": "Doorstreep", - "STRIKE_SAMPLE_TEXT": "Je tekst hier...", - "BULLETED_LIST_BUTTON": "Lijst met opsommingstekens", - "BULLETED_LIST_SAMPLE_TEXT": "Je tekst hier...", - "NUMERIC_LIST_BUTTON": "Nummerieke lijst", - "NUMERIC_LIST_SAMPLE_TEXT": "Je tekst hier...", - "PICTURE_BUTTON": "Foto", - "PICTURE_SAMPLE_TEXT": "Je alternatieve tekst voor afbeelding hier...", - "LINK_BUTTON": "Link", - "LINK_SAMPLE_TEXT": "Je tekst om te linken hier...", - "QUOTE_BLOCK_BUTTON": "Blokquote", - "QUOTE_BLOCK_SAMPLE_TEXT": "Je tekst hier...", - "CODE_BLOCK_BUTTON": "Code blok", - "CODE_BLOCK_SAMPLE_TEXT": "Je tekst hier...", - "PREVIEW_BUTTON": "Voorbeeld", - "EDIT_BUTTON": "Bewerk", - "ATTACH_FILE_HELP": "Attach files by dragging & dropping on the textarea above.", - "ATTACH_FILE_HELP_SAVE_FIRST": "Save first before if you want to attach files by dragging & dropping on the textarea above.", + "OUTDATED": "Another person has made changes while you were editing. Check the new version on the activiy tab before you save your changes.", "MARKDOWN_HELP": "Markdown syntax help" }, "PERMISIONS_CATEGORIES": { @@ -307,10 +266,6 @@ "ADD_WIKI_LINKS": "Wiki links toevoegen", "DELETE_WIKI_LINKS": "Verwijder wiki links" } - }, - "META": { - "PAGE_TITLE": "Taiga", - "PAGE_DESCRIPTION": "Taiga is een project management platform voor startups en agile ontwikkelaars & designers die een simpele, mooie tool willen om werken echt leuk te maken." } }, "LOGIN": { @@ -366,7 +321,6 @@ }, "CHANGE_PASSWORD": { "PAGE_TITLE": "Verander je wachtwoord - Taiga", - "PAGE_DESCRIPTION": "Zet een nieuw wachtwoord voor je Taiga account. Hey! Je kan best wat ijzerrijk voedsel eten, dat is goed voor de hersenen :P", "SECTION_NAME": "Wachtwoord wijzigen", "FIELD_CURRENT_PASSWORD": "Huidig wachtwoord", "PLACEHOLDER_CURRENT_PASSWORD": "Je huidige wachtwoord (of leeg als je nog geen wachtwoord hebt)", @@ -391,8 +345,7 @@ }, "INVITATION_LOGIN_FORM": { "NOT_FOUND": "Onze Oompa Loompa's kunnen je uitnodiging niet vinden.", - "SUCCESS": "Je bent met succes toegetreden tot dit project, Welkom bij {{project_name}}", - "ERROR": "Volgens onze Oempa-Loempa's, ben je nog niet geregistreerd of heb je een fout wachtwoord getypt." + "SUCCESS": "Je bent met succes toegetreden tot dit project, Welkom bij {{project_name}}" }, "HOME": { "PAGE_TITLE": "Home -Taiga", @@ -463,10 +416,7 @@ "TITLE_LIGHTBOX_DELETE_ATTACHMENT": "Verwijder bijlage", "MSG_LIGHTBOX_DELETE_ATTACHMENT": "de bijlage '{{fileName}}'", "ERROR_DELETE_ATTACHMENT": "We zijn er niet in geslaagd om te verwijderen: {{errorMessage}}", - "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) is te zwaar voor onze Oempa-Loempa's, probeer het met een bestand kleiner dan ({{maxFileSize}})", - "FIELDS": { - "IS_DEPRECATED": "is verouderd" - } + "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) is te zwaar voor onze Oempa-Loempa's, probeer het met een bestand kleiner dan ({{maxFileSize}})" }, "PAGINATION": { "PREVIOUS": "Vor", @@ -502,13 +452,10 @@ "ASYNC_MESSAGE": "We sturen je een email als het klaar is", "SYNC_MESSAGE": "Als de download niet automatisch start, klik dan hier.", "ERROR": "Onze Oempa-Loempa's hebben wat problemen bij het genereren van uw dump.\nProbeer het opnieuw a.u.b.", - "ERROR_BUSY": "Sorry, onze Oempa-Loempa's zijn op het moment erg druk. Probeer het nog eens over een paar minuten.", - "ERROR_MESSAGE": "Onze Oempa-Loempa's hebben wat problemen met het genereren van je dump: {{message}}" + "ERROR_BUSY": "Sorry, onze Oempa-Loempa's zijn op het moment erg druk. Probeer het nog eens over een paar minuten." }, "MODULES": { "TITLE": "Modules", - "ENABLE": "Inschakelen", - "DISABLE": "Uitschakelen", "EPICS": "Epics", "EPICS_DESCRIPTION": "Visualize and manage the most strategic part of your project", "BACKLOG": "Backlog", @@ -537,17 +484,16 @@ "PAGE_TITLE": "{{sectionName}} - Project profiel - {{projectName}}", "PROJECT_DETAILS": "Project details", "PROJECT_NAME": "Naam project", - "PROJECT_SLUG": "Project Slug", "TAGS": "Tags", "DESCRIPTION": "Beschrijving", "RECRUITING": "Is this project looking for people?", "RECRUITING_MESSAGE": "Who are you looking for?", "RECRUITING_PLACEHOLDER": "Define the profiles you are looking for", + "FEEDBACK": "Receive feedback from Taiga users?", "PUBLIC_PROJECT": "Open project", "PRIVATE_PROJECT": "Gesloten project", "PRIVATE_OR_PUBLIC": "What's the difference between public and private projects?", "DELETE": "Verwijder dit project", - "LOGO_HELP": "The image will be scaled to 80x80px.", "CHANGE_LOGO": "Change logo", "ACTION_USE_DEFAULT_LOGO": "Use default image", "MAX_PRIVATE_PROJECTS": "You've reached the maximum number of private projects allowed by your current plan", @@ -595,6 +541,7 @@ "ISSUE_DESCRIPTION": "Issues aangepaste velden", "ISSUE_ADD": "Voeg een aangepast veld toe in issues", "FIELD_TYPE_TEXT": "Tekst", + "FIELD_TYPE_RICHTEXT": "Rich text", "FIELD_TYPE_MULTI": "Over meerdere regels", "FIELD_TYPE_DATE": "Date", "FIELD_TYPE_URL": "Url" @@ -623,7 +570,7 @@ "ACTION_ADD": "Nieuwe ernst toevoegen" }, "PROJECT_VALUES_STATUS": { - "TITLE": "Status", + "TITLE": "Statuses", "SUBTITLE": "Specifieer de statussen waar je user stories, taken en issues door zullen gaan", "EPIC_TITLE": "Epic Statuses", "US_TITLE": "User Story Statuses", @@ -676,8 +623,8 @@ "INFO_VERIFYING_IP": "Gitlab requests zijn niet gesigneerd, dus de beste manier om hun oorsprong te verifiëren is op basis van IP. Als het veld leeg is zal er geen IP validatie plaatsvinden." }, "GITHUB": { - "SECTION_NAME": "Github", - "PAGE_TITLE": "Github - {{projectName}}" + "SECTION_NAME": "GitHub", + "PAGE_TITLE": "GitHub - {{projectName}}" }, "GOGS": { "SECTION_NAME": "Gogs", @@ -686,7 +633,6 @@ "WEBHOOKS": { "PAGE_TITLE": "Webhooks - {{projectName}}", "SECTION_NAME": "Webhooks", - "SUBTITLE": "Webhooks houden externe diensten op de hoogte van evenenmenten in Taiga, zoals commentaar, user stories....", "ADD_NEW": "Nieuwe webhook toevoegen", "TYPE_NAME": "Type de service naam", "TYPE_PAYLOAD_URL": "Type de service payload url", @@ -732,7 +678,6 @@ "DELETE_MEMBER": "Verwijder gebruiker", "RESEND": "Resend", "SUCCESS_SEND_INVITATION": "We hebben de uitnodiging opnieuw gestuurd aan '{{email}}'.", - "ERROR_SEND_INVITATION": "We hebben je een uitnodiging gestuurd", "SUCCESS_DELETE": "We hebben {{message}} verwijderd.", "ERROR_DELETE": "We zijn er niet in geslaagd om te verwijderen {{message}}", "DEFAULT_DELETE_MESSAGE": "de uitnodiging naar {{email}}" @@ -761,16 +706,11 @@ "PLACEHOLDER_WRITE_NAME": "Schrijf een naam voor de nieuwe status" }, "MENU": { - "TITLE": "Admin", "PROJECT": "Project", "ATTRIBUTES": "Attributen", "MEMBERS": "Gebruikers", "PERMISSIONS": "Permissies", - "INTEGRATIONS": "Integraties", - "PLUGINS": "Plugins" - }, - "SUBMENU_PROJECT_ATTRIBUTES": { - "TITLE": "Attributen" + "INTEGRATIONS": "Integraties" }, "SUBMENU_PROJECT_VALUES": { "STATUS": "Status", @@ -781,17 +721,11 @@ "CUSTOM_FIELDS": "Eigen velden", "TAGS": "Tags" }, - "SUBMENU_PROJECT_PROFILE": { - "TITLE": "Project profiel" - }, "SUBMENU_ROLES": { "TITLE": "Rollen", "ACTION_NEW_ROLE": "+ Nieuwe rol", "TITLE_ACTION_NEW_ROLE": "Nieuwe rol toevoegen" }, - "SUBMENU_THIDPARTIES": { - "TITLE": "Services" - }, "PROJECT_TRANSFER": { "DO_YOU_ACCEPT_PROJECT_OWNERNSHIP": "Would you like to become the new project owner?", "PRIVATE": "Private", @@ -806,15 +740,13 @@ "PRIVATE": "Please remember that you can own up to {{maxProjects}} private projects. You currently own {{currentProjects}} private projects", "PUBLIC": "Please remember that you can own up to {{maxProjects}} public projects. You currently own {{currentProjects}} public projects" }, - "CANT_BE_OWNED": "At the moment you cannot become an owner of a project of this type. If you would like to become the owner of this project, please contact the administrator so they change your account settings to enable project ownership.", - "CHANGE_MY_PLAN": "Change my plan" + "CANT_BE_OWNED": "At the moment you cannot become an owner of a project of this type. If you would like to become the owner of this project, please contact the administrator so they change your account settings to enable project ownership." } }, "USER": { "PROFILE": { "PAGE_TITLE": "{{userFullName}} (@{{userUsername}})", "EDIT": "Profiel bewerken", - "FOLLOW": "Volgen", "CLOSED_US": "Gesloten US", "PROJECTS": "Projecten", "PROJECTS_EMPTY": "{{username}} heeft nog geen projecten", @@ -822,7 +754,6 @@ "CONTACTS_EMPTY": "{{username}} heeft nog geen contacten", "CURRENT_USER_CONTACTS_EMPTY": "Je hebt nog geen contacten", "CURRENT_USER_CONTACTS_EMPTY_EXPLAIN": "De mensen waarmee je via Taiga werkt zullen automatisch je contacten worden", - "REPORT": "Meld misbruik", "TABS": { "ACTIVITY_TAB": "Tijdlijn", "ACTIVITY_TAB_TITLE": "Alle activiteit van deze gebruiker weergeven", @@ -848,13 +779,13 @@ "FILTER_TYPE_ALL": "Alles", "FILTER_TYPE_ALL_TITLE": "Alles weergeven", "FILTER_TYPE_PROJECTS": "Projecten", - "FILTER_TYPE_PROJECT_TITLES": "Enkel projecten weergeven", + "FILTER_TYPE_PROJECTS_TITLE": "Enkel projecten weergeven", "FILTER_TYPE_EPICS": "Epics", - "FILTER_TYPE_EPIC_TITLES": "Show only epics", + "FILTER_TYPE_EPICS_TITLE": "Show only epics", "FILTER_TYPE_USER_STORIES": "Verhalen", - "FILTER_TYPE_USER_STORIES_TITLES": "Enkel verhalen van gebruikers weergeven", + "FILTER_TYPE_USER_STORIES_TITLE": "Enkel verhalen van gebruikers weergeven", "FILTER_TYPE_TASKS": "Taken", - "FILTER_TYPE_TASK_TITLES": "Enkel taken weergeven", + "FILTER_TYPE_TASKS_TITLE": "Enkel taken weergeven", "FILTER_TYPE_ISSUES": "Issues", "FILTER_TYPE_ISSUES_TITLE": "Enkel problemen weergeven", "EMPTY_TITLE": "Het ziet er naar uit dat er hier niets is om weer te geven." @@ -862,8 +793,6 @@ }, "PROJECT": { "PAGE_TITLE": "{{projectName}}", - "WELCOME": "Welkom", - "SECTION_PROJECTS": "Projecten", "HELP": "Herorden je projecten met de vaakst gebruikte bovenaan.
De top 10 projecten zullen verschijnen in de project lijst bovenaan in de navigatie bar.", "PRIVATE": "Gesloten project", "LOOKING_FOR_PEOPLE": "This project is looking for people", @@ -875,12 +804,6 @@ "THIS_PROJECT_IS_BLOCKED": "This project is temporarily blocked", "TO_UNBLOCK_CONTACT_THE_ADMIN_STAFF": "In order to unblock your projects, contact the administrator." }, - "STATS": { - "PROJECT": "project
punten", - "DEFINED": "gedefinieerde
punten", - "ASSIGNED": "toegewezen
punten", - "CLOSED": "gesloten
punten" - }, "SECTION": { "SEARCH": "Zoek", "TIMELINE": "Tijdlijn", @@ -893,15 +816,9 @@ "ADMIN": "Admin" }, "NAVIGATION": { - "SECTION_TITLE": "Jouw projecten", - "PLACEHOLDER_SEARCH": "Zoeken in...", "ACTION_CREATE_PROJECT": "Project aanmaken", - "ACTION_IMPORT_PROJECT": "Importeer project", "MANAGE_PROJECTS": "Manage projects", "TITLE_CREATE_PROJECT": "Project aanmaken", - "TITLE_IMPORT_PROJECT": "Importeer project", - "TITLE_PRVIOUS_PROJECT": "Toon voorgaande projecten", - "TITLE_NEXT_PROJECT": "Toon volgende projecten", "HELP_TITLE": "Taiga support pagina", "HELP": "Help", "HOMEPAGE": "Homepage", @@ -909,10 +826,6 @@ "FEEDBACK": "Feedback", "NOTIFICATIONS_TITLE": "Notificatie instellingen bewerken", "NOTIFICATIONS": "Notificaties", - "ORGANIZATIONS_TITLE": "Jouw organisaties bewerken", - "ORGANIZATIONS": "Organisaties bewerken", - "SETTINGS_TITLE": "Instellingen aanpassen", - "SETTINGS": "Instellingen", "VIEW_PROFILE_TITLE": "Bekijk profiel", "VIEW_PROFILE": "Bekijk profiel", "EDIT_PROFILE_TITLE": "Bewerk je profiel", @@ -921,14 +834,68 @@ "CHANGE_PASSWORD": "Wachtwoord wijzigen", "DASHBOARD_TITLE": "Dashboard", "DISCOVER_TITLE": "Ontdek trending projecten", - "NEW_ITEM": "Nieuw", - "DISCOVER": "Ontdek", - "ACTION_REORDER": "Sleep om de volgorde te veranderen" + "DISCOVER": "Ontdek" + }, + "LIKE_BUTTON": { + "LIKE": "Vind ik leuk", + "LIKED": "Leuk gevonden", + "UNLIKE": "Vind ik niet meer leu", + "BUTTON_TITLE": "Vind dit project leuk of niet", + "COUNTER_TITLE": "{total, plural, one{one fan} other{# fans}}" + }, + "WATCH_BUTTON": { + "BUTTON_TITLE": "Watch this project and set notification policy", + "WATCH": "Bekijk", + "WATCHING": "Volgers", + "COUNTER_TITLE": "{total, plural, one{one watcher} other{# watchers}}", + "OPTIONS": { + "NOTIFY_ALL": "Ontvang alle notificaties", + "NOTIFY_ALL_TITLE": "Ontvang alle notificaties voor dit project", + "NOTIFY_INVOLVED": "Only involved", + "NOTIFY_INVOLVED_TITLE": "Recive notificacions only when you are involved", + "UNWATCH": "Unwatch", + "UNWATCH_TITLE": "Unwatch this project" + } + }, + "CONTACT_BUTTON": { + "CONTACT_TITLE": "Contact the project team", + "CONTACT_BUTTON": "Contact the project" + }, + "CREATE": { + "TITLE": "Project aanmaken", + "CHOOSE_TEMPLATE": "Which template fits your project better?", + "TEMPLATE_SCRUM": "Scrum", + "TEMPLATE_SCRUM_DESC": "Prioritize and solve your tasks in short time cycles.", + "TEMPLATE_SCRUM_LONGDESC": "Scrum is an iterative and incremental agile software development methodology for managing product development.\nThe product backlog is what will ultimately be delivered, ordered into the sequence in which it should be delivered. Product Backlogs are broken into manageable, executable chunks named sprints. Every certain amount of time the team initiates a new sprint and commits to deliver a certain number of user stories from the backlog, in accordance with their skills, abilities and resources. The project advances as the backlog becomes depleted.", + "TEMPLATE_KANBAN": "Kanban", + "TEMPLATE_KANBAN_DESC": "Keep a constant workflow on independent tasks", + "TEMPLATE_KANBAN_LONGDESC": "The Kanban methodology is used to divide project development (any sort of project) into stages.\nA kanban card is like an index card or post-it note that details every task (or user story) in a project that needs to be completed. The Kanban board is used to move each card from one state of completion to the next and in so doing, helps track progress.", + "DUPLICATE": "Duplicate project", + "DUPLICATE_DESC": "Start clean and keep your configuration", + "IMPORT": "Importeer project", + "IMPORT_DESC": "Import your project from multiple platforms into Taiga", + "INVITE": "Invite to the project", + "SOLO_PROJECT": "You'll be alone in this project", + "INVITE_LATER": "(You'll be able to invite more members later)", + "BACK": "Back", + "MAX_PRIVATE_PROJECTS": "Unfortunately, You've reached the maximum number of private projects.\nIf you would like to increase the current limit please contact the administrator.", + "MAX_PUBLIC_PROJECTS": "Unfortunately, You've reached the maximum number of public projects.\nIf you would like to increase the current limit please contact the administrator.", + "PUBLIC_PROJECT": "Public Project", + "PRIVATE_PROJECT": "Private Project" + }, + "COMMON": { + "DETAILS": "New project details", + "PROJECT_TITLE": "Project Name", + "PROJECT_DESCRIPTION": "Project Description" + }, + "DUPLICATE": { + "TITLE": "Duplicate Project", + "DESCRIPTION": "Start clean and keep your configuration", + "SELECT_PLACEHOLDER": "Choose an existing project to duplicate" }, "IMPORT": { - "TITLE": "Importeren project", - "UPLOADING_FILE": "Bezig met uploaden dump bestand", - "DESCRIPTION": "Dit proces kan even duren, laat het venster even open alsjeblieft.", + "TITLE": "Import Project", + "DESCRIPTION": "Import your project from multiple platforms into Taiga", "ASYNC_IN_PROGRESS_TITLE": "Onze Oempa-Loempa's zijn je project aan het importeren", "ASYNC_IN_PROGRESS_MESSAGE": "Dit proces kan een paar minuten duren
We sturen je een email als het gereed is", "UPLOAD_IN_PROGRESS_MESSAGE": "{{uploadedSize}} van {{totalSize}} geupload", @@ -937,8 +904,29 @@ "ERROR_MESSAGE": "Onze Oempa-Loempa's hebben wat problemen met het importeren van je dump: {{error_message}}", "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) is te zwaar voor onze Oempa-Loempa's, probeer het met een bestand kleiner dan ({{maxFileSize}})", "SYNC_SUCCESS": "Je project werd met succes geïmporteerd", + "IMPORT": "Import", + "WHO_IS": "Their tasks will be assigned to ...", + "WRITE_EMAIL": "Or if you want, write the email that this user uses in Taiga", + "SEARCH_CONTACT": "Or if you want, search in your contacts", + "WRITE_EMAIL_LABEL": "Write the email that this user uses in Taiga", + "ACCEEDE": "Acceede", + "PROJECT_MEMBERS": "Project Members", + "PROCESS_DESCRIPTION": "Tell us who from Taiga you want to assign the tasks of {{platform}}", + "MATCH": "Is {{user_external}} the same person as {{user_internal}}?", + "CHOOSE": "Select user", + "LINKS": "Links with {{platform}}", + "LINKS_DESCRIPTION": "Do you want to keep the link of each item with the original {{platform}} card?", + "WARNING_MAIL_USER": "Note that if the user does not have a Taiga account we will not be able to assign the tasks to him.", + "ASSIGN": "Assign", + "PROJECT_SELECTOR": { + "NO_RESULTS": "It looks like nothing was found with your search criteria", + "ACTION_SEARCH": "zoek", + "ACTION_BACK": "Back" + }, "PROJECT_RESTRICTIONS": { - "PROJECT_MEMBERS_DESC": "The project you are trying to import has {{members}} members, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per project. If you would like to increase that limit please contact the administrator.", + "PROJECT_MEMBERS_DESC_PRIVATE": "The project you are trying to import has {{members}} members including you, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per private project. If you would like to increase that limit please contact the administrator.", + "PROJECT_MEMBERS_DESC_PUBLIC": "The project you are trying to import has {{members}} members including you, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per public project. If you would like to increase that limit please contact the administrator.", + "ACCOUNT_ALLOW_MEMBERS": "Your account only allows {{members}} members", "PRIVATE_PROJECTS_SPACE": { "TITLE": "Unfortunately, your current plan does not allow for additional private projects", "DESC": "The project you are trying to import is private. Unfortunately, your current plan does not allow for additional private projects." @@ -961,39 +949,67 @@ "TITLE": "Unfortunately your current plan doesn't allow additional public projects or an increase of more than {{max_memberships}} members per public project", "DESC": "The project that you are trying to import is public and has more than {{members}} members." } - } - }, - "LIKE_BUTTON": { - "LIKE": "Vind ik leuk", - "LIKED": "Leuk gevonden", - "UNLIKE": "Vind ik niet meer leu", - "BUTTON_TITLE": "Vind dit project leuk of niet", - "COUNTER_TITLE": "{total, plural, one{one fan} other{# fans}}" - }, - "WATCH_BUTTON": { - "BUTTON_TITLE": "Watch this project and set notification policy", - "WATCH": "Bekijk", - "WATCHING": "Volgers", - "COUNTER_TITLE": "{total, plural, one{one watcher} other{# watchers}}", - "OPTIONS": { - "NOTIFY_ALL": "Ontvang alle notificaties", - "NOTIFY_ALL_TITLE": "Ontvang alle notificaties voor dit project", - "NOTIFY_INVOLVED": "Only involved", - "NOTIFY_INVOLVED_TITLE": "Recive notificacions only when you are involved", - "UNWATCH": "Unwatch", - "UNWATCH_TITLE": "Unwatch this project" + }, + "IN_PROGRESS": { + "TITLE": "Importeren project", + "DESCRIPTION": "Dit proces kan even duren, laat het venster even open alsjeblieft." + }, + "WARNING": { + "TITLE": "Some taks will be unassigned", + "DESCRIPTION": "There are still unidentified people. The cards assigned to these people will remain unassigned. Check all the contacts to not lose that information.", + "CHECK": "Check contacts" + }, + "TAIGA": { + "SELECTOR": "Import your Taiga project" + }, + "TRELLO": { + "SELECTOR": "Import your Trello boards into Taiga", + "CHOOSE_PROJECT": "Choose board that you want to import", + "NO_PROJECTS": "It seems you have no boards in Trello" + }, + "GITHUB": { + "SELECTOR": "Import your GitHub project issues", + "CHOOSE_PROJECT": "Find the project you want to import", + "NO_PROJECTS": "It seems you have no porjects in GitHub", + "HOW_DO_YOU_WANT_TO_IMPORT": "How do you want to import your issues into Taiga?", + "KANBAN_PROJECT": "As user stories in a kanban project", + "KANBAN_PROJECT_DESCRIPTION": "After that you can enable scrum with backlog.", + "SCRUM_PROJECT": "As user stories in a scrum project", + "SCRUM_PROJECT_DESCRIPTION": "After that you can enable kanban mode.", + "ISSUES_PROJECT": "As issues", + "ISSUES_PROJECT_DESCRIPTION": "You will not be able to use your issues in kanban or scrum mode. You will be able to enable kanban or scrum for new user stories" + }, + "ASANA": { + "SELECTOR": "Import your Asana project and choose how to manage it", + "CHOOSE_PROJECT": "Choose project that you want to import", + "NO_PROJECTS": "It seems you have no porjects in Asana", + "KANBAN_PROJECT": "Kanban", + "SCRUM_PROJECT": "Scrum", + "CREATE_AS_SCRUM_DESCRIPTION": "The tasks and sub-tasks of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_KANBAN_DESCRIPTION": "The tasks and sub-tasks of your project will be created as Taiga user stories and tasks." + }, + "JIRA": { + "SELECTOR": "Import your Jira project and choose how to manage it", + "CHOOSE_PROJECT": "Choose project or board that you want to import", + "NO_PROJECTS": "It seems you have no porjects or boards in Jira", + "URL": "Your Jira URL", + "KANBAN_PROJECT": "Kanban", + "SCRUM_PROJECT": "Scrum", + "ISSUES_PROJECT": "Issues", + "CREATE_AS_SCRUM_DESCRIPTION": "The issues and sub-issues of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_KANBAN_DESCRIPTION": "The issues and sub-issues of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_ISSUES_DESCRIPTION": "What do you want to do with sub-issues from the Jira project? (Taiga doesn't allow sub-issues)", + "CREATE_NEW_ISSUES": "Convert sub-issues to new Taiga issues", + "NOT_CREATE_NEW_ISSUES": "Do not import sub-issues" } } }, "LIGHTBOX": { "DELETE_ACCOUNT": { - "SECTION_NAME": "Taiga account verwijderen", "CONFIRM": "Weet je zeker dat je je Taiga account wilt verwijderen?", - "NEWSLETTER_LABEL_TEXT": "Ik wil de nieuwsbrief niet meer ontvangen", "CANCEL": "Back to settings", "ACCEPT": "Delete account", - "BLOCK_PROJECT": "Note that all the projects you own projects will be blocked after you delete your account. If you do want a project blocked, transfer ownership to another member of each project prior to deleting your account.", - "SUBTITLE": "Sorry to see you go. We'll be here if you should ever consider us again! :(" + "BLOCK_PROJECT": "Note that all the projects you own projects will be blocked after you delete your account. If you do want a project blocked, transfer ownership to another member of each project prior to deleting your account." }, "DELETE_PROJECT": { "TITLE": "Verwijder project", @@ -1007,6 +1023,12 @@ }, "ADD_MEMBER": { "TITLE": "Nieuwe gebruiker", + "PLACEHOLDER": "Filter users or write an email to invite", + "ADD_EMAIL": "Add email", + "REMOVE": "Remove", + "INVITE": "Invite", + "CHOOSE_ROLE": "Choose a role", + "PLACEHOLDER_INVITATION_TEXT": "(Optioneel) Voeg een gepersonaliseerd bericht toe aan je uitnodiging. Vertel iets leuks aan je nieuwe leden ;-)", "HELP_TEXT": "Als gebruikers al geregistreerd zijn op Taiga, zullen ze automatisch toegevoegd worden. Anders krijgen ze een uitnodiging." }, "CREATE_ISSUE": { @@ -1068,6 +1090,12 @@ "TITLE": "Who do you want to be the new project owner?", "ADD_COMMENT": "Add comment", "BUTTON": "Ask this project member to become the new project owner" + }, + "CONTACT_PROJECT": { + "TITLE": "Send an email to", + "WARNING": "The email will be received by the project admins", + "PLACEHOLDER": "Write your message", + "SEND": "Send" } }, "EPIC": { @@ -1101,15 +1129,9 @@ "ADD_BULK": "Voeg enkele nieuwe User Stories in bulk toe", "PROMOTED": "Deze US werd gepromoveerd van Issue:", "TITLE_LINK_GO_TO_ISSUE": "Ga naar probleem", - "EXTERNAL_REFERENCE": "Deze US is aangemaakt vanaf", - "GO_TO_EXTERNAL_REFERENCE": "Ga naar bron", - "BLOCKED": "Deze user story is geblokkeerd", "TITLE_DELETE_ACTION": "Verwijder user story", "LIGHTBOX_TITLE_BLOKING_US": "User story blokkeren", - "TASK_COMPLETED": "{{totalClosedTasks}}/{{totalTasks}} taken afgewerkt", - "ASSIGN": "User story toewijzen", "NOT_ESTIMATED": "Niet ingeschat", - "TOTAL_US_POINTS": "Totaal US punten", "TRIBE": { "PUBLISH": "Publish as Gig in Taiga Tribe", "PUBLISH_INFO": "More info", @@ -1119,23 +1141,19 @@ "CLOSE": "Close", "SYNCHRONIZE_LINK": "synchronize with Taiga Tribe", "PUBLISH_MORE_INFO_TITLE": "Do you need somebody for this task?", - "PUBLISH_MORE_INFO_TEXT": "

If you need help with a particular piece of work you can easily create gigs on Taiga Tribe and receive help from all over the world. You will be able to control and manage the gig enjoying a great community eager to contribute.

TaigaTribe was born as a Taiga sibling. Both platforms can live separately but we believe that there is much power in using them combined so we are making sure the integration works like a charm.

" + "PUBLISH_MORE_INFO_TEXT": "

If you need help with a particular piece of work you can easily create gigs on Taiga Tribe and receive help from all over the world. You will be able to control and manage the gig enjoying a great community eager to contribute.

TaigaTribe was born as a Taiga sibling. Both platforms can live separately but we believe that there is much power in using them combined so we are making sure the integration works like a charm.

" }, "FIELDS": { "TEAM_REQUIREMENT": "Eisen team", - "CLIENT_REQUIREMENT": "Requirement van de klant", - "FINISH_DATE": "Einddatum" + "CLIENT_REQUIREMENT": "Requirement van de klant" } }, "COMMENTS": { "DELETED_INFO": "Comment deleted by {{user}}", - "TITLE": "Reacties", "COMMENTS_COUNT": "{{comments}} Comments", - "ORDER": "Order", "OLDER_FIRST": "Older first", "RECENT_FIRST": "Recent first", "COMMENT": "Reageer", - "EDIT_COMMENT": "Edit comment", "EDITED_COMMENT": "Edited:", "SHOW_HISTORY": "View historic", "TYPE_NEW_COMMENT": "Type hier nieuw commentaar", @@ -1148,13 +1166,8 @@ } }, "ACTIVITY": { - "SHOW_ACTIVITY": "Toon activiteit", - "DATETIME": "DD MMM YYYY HH:mm", - "SHOW_MORE": "+ Toon vorige items ({{showMore}} meer)", "TITLE": "Activiteit", "ACTIVITIES_COUNT": "{{activities}} Activities", - "REMOVED": "verwijderd", - "ADDED": "toegevoegd", "TAGS_ADDED": "tags added:", "TAGS_REMOVED": "tags removed:", "US_POINTS": "{{role}} points", @@ -1163,50 +1176,21 @@ "UPDATED_ATTACHMENT": "updated attachment ({{filename}}):", "CREATED_CUSTOM_ATTRIBUTE": "created custom attribute", "UPDATED_CUSTOM_ATTRIBUTE": "updated custom attribute", - "SIZE_CHANGE": "{size, plural, one{één verandering} other{# veranderingen}} gemaakt", "BECAME_DEPRECATED": "became deprecated", "BECAME_UNDEPRECATED": "became undeprecated", "TEAM_REQUIREMENT": "Eisen team", "CLIENT_REQUIREMENT": "Requirement van de klant", "BLOCKED": "Geblokkeerd", "VALUES": { - "YES": "ja", - "NO": "nee", - "EMPTY": "leeg", "UNASSIGNED": "niet toegewezen" }, "FIELDS": { "SUBJECT": "onderwerp", - "NAME": "naam", "DESCRIPTION": "beschrijving", - "CONTENT": "inhoud", "STATUS": "status", - "IS_CLOSED": "is gesloten", - "FINISH_DATE": "einddatum", "TYPE": "type", - "PRIORITY": "prioriteit", - "SEVERITY": "ernst", "ASSIGNED_TO": "toegewezen aan", - "WATCHERS": "waarnemers", "MILESTONE": "sprint", - "USER_STORY": "user story", - "PROJECT": "project", - "IS_BLOCKED": "is geblokkeerd", - "BLOCKED_NOTE": "geblokkeerde notitie", - "POINTS": "punten", - "CLIENT_REQUIREMENT": "eisen klant", - "TEAM_REQUIREMENT": "team eisen", - "IS_IOCAINE": "is iocaine", - "TAGS": "tags", - "ATTACHMENTS": "bijlagen", - "IS_DEPRECATED": "is verourderd", - "IS_NOT_DEPRECATED": "is not deprecated", - "ORDER": "volgorde", - "BACKLOG_ORDER": "backlog volgorde", - "SPRINT_ORDER": "sprint volgorde", - "KANBAN_ORDER": "kanban volgorde", - "TASKBOARD_ORDER": "taakbord volgorde", - "US_ORDER": "us volgorde", "COLOR": "kleur" } }, @@ -1220,8 +1204,6 @@ "CUSTOMIZE_GRAPH_TITLE": "Set up the points and sprints through the Admin", "MOVE_US_TO_CURRENT_SPRINT": "Verplaats naar huidige sprint", "MOVE_US_TO_LATEST_SPRINT": "Move to latest Sprint", - "SHOW_FILTERS": "Toon filters", - "SHOW_TAGS": "Toon tags", "EMPTY": "The backlog is empty!", "CREATE_NEW_US": "Nieuwe US aanmaken", "CREATE_NEW_US_EMPTY_HELP": "Misschien wil je een nieuwe user story aanmaken", @@ -1248,6 +1230,12 @@ "SHOW": "Toon tags", "HIDE": "Verberg tags" }, + "FORECASTING": { + "TITLE": "Velocity forecasting", + "BACKLOG": "Display backlog", + "NEW_SPRINT": "Candidate User Stories for your next sprint based on your velocity. Click to create a new sprint.", + "CURRENT_SPRINT": "Candidate User Stories for your sprint based on your velocity. Click to add to current sprint." + }, "TABLE": { "COLUMN_US": "User Stories", "TITLE_COLUMN_POINTS": "Selecteer view per rol" @@ -1270,8 +1258,6 @@ }, "FILTERS": { "TOGGLE": "Zet de filter zichtbaarheid aan of af", - "TITLE": "Filters", - "REMOVE": "Filters verwijderd", "HIDE": "Filters verbergen", "SHOW": "Toon filters" }, @@ -1280,7 +1266,6 @@ "DATE": "DD MMM YYYY", "LINK_TASKBOARD": "Sprint taakbord", "TITLE_LINK_TASKBOARD": "Ga naar taakbord van \"{{name}}\"", - "NUMBER_SPRINTS": "
sprints", "EMPTY": "There are no sprints yet", "WARNING_EMPTY_SPRINT_ANONYMOUS": "This sprint has no User Stories", "WARNING_EMPTY_SPRINT": "Drop here Stories from your backlog to start a new sprint", @@ -1305,7 +1290,6 @@ "TITLE_ACTION_ADD": "Voeg een nieuwe taak toe", "TITLE_ACTION_ADD_BULK": "Wat nieuwe taken in bulk toevoegen", "TITLE_ACTION_ASSIGN": "Toegewezen taak", - "TITLE_ACTION_EDIT": "Bewerk taak", "PLACEHOLDER_CARD_TITLE": "Dit zou een taak kunnen zijn", "PLACEHOLDER_CARD_TEXT": "Split Stories into tasks to track them separately", "TABLE": { @@ -1335,17 +1319,11 @@ "TITLE_SELECT_STATUS": "Status naam", "OWNER_US": "Deze taak is van", "TITLE_LINK_GO_OWNER": "Ga naar user story", - "ORIGIN_US": "Deze taak werd aangemaakt vanaf", - "TITLE_LINK_GO_ORIGIN": "Ga naar user story", - "BLOCKED": "Deze taak is geblokkeerd", "TITLE_DELETE_ACTION": "Verwijder taak", "LIGHTBOX_TITLE_BLOKING_TASK": "Blokkerende taak", "FIELDS": { - "MILESTONE": "Sprint", - "USER_STORY": "User story", "IS_IOCAINE": "Is iocaine" }, - "ACTION_IOCAINE": "Iocaine", "TITLE_ACTION_IOCAINE": "Voel je je wat overweldigd door een taak? Zorg ervoor dat anderen dit weten door op Iocaine te klikken bij het wijzigen van een taak. Je kan stapsgewijs immuun worden tegen dit (fictioneel) dodelijk gif door kleine dosissen op te nemen. Net zoals je beter kan worden in wat je doet door af en toe een extra uitdaging aan te gaan!" }, "NOTIFICATION": { @@ -1374,14 +1352,12 @@ "ISSUES": { "PAGE_TITLE": "Issues - {{projectName}}", "PAGE_DESCRIPTION": "Het issue lijst overzicht van het project {{projectName}}: {{projectDescription}}", - "LIST_SECTION_NAME": "Issues", "SECTION_NAME": "Issue", "ACTION_NEW_ISSUE": "+ nieuw probleem", "ACTION_PROMOTE_TO_US": "Promoveer tot User Story", "PROMOTED": "Dit issue is gepromoveerd tot US:", "EXTERNAL_REFERENCE": "Dit issue is aangemaakt vanaf", "GO_TO_EXTERNAL_REFERENCE": "Ga naar bron", - "BLOCKED": "Dit issue is geblokkeerd", "ACTION_DELETE": "Verwijderd issue", "LIGHTBOX_TITLE_BLOKING_ISSUE": "Blokkerend issue", "FIELDS": { @@ -1423,15 +1399,11 @@ "SECTION_NAME": "Kanban", "TITLE_ACTION_FOLD": "Kolom inklappen", "TITLE_ACTION_UNFOLD": "Kolom uitklappen", - "TITLE_ACTION_FOLD_CARDS": "Kaarten inklappen", - "TITLE_ACTION_UNFOLD_CARDS": "Kaarten uitklappen", "TITLE_ACTION_ADD_US": "Nieuwe user story toevoegen", "TITLE_ACTION_ADD_BULK": "Nieuwe bulk toevoegen", "ACTION_SHOW_ARCHIVED": "Toon gearchiveerd", "ACTION_HIDE_ARCHIVED": "Verberg gearchiveerde", "HIDDEN_USER_STORIES": "De user stories met deze status zijn standaard verborgen", - "ARCHIVED": "Je hebt gearchiveerd", - "UNDO_ARCHIVED": "Drag & drop nog een keer om ongedaan te maken", "PLACEHOLDER_CARD_TITLE": "These are your User Stories", "PLACEHOLDER_CARD_TEXT": "Stories might also have subtasks to separate requirements" }, @@ -1452,7 +1424,6 @@ "PAGE_TITLE": "Team - {{projectName}}", "PAGE_DESCRIPTION": "Het team overzicht toont alle leden van het project {{projectName}}: {{projectDescription}}", "SECTION_NAME": "Team", - "APP_TITLE": "TEAM - {{projectName}}", "PLACEHOLDER_INPUT_SEARCH": "Zoek op volledige naam", "COLUMN_MR_WOLF": "Dhr. Wolf", "EXPLANATION_COLUMN_MR_WOLF": "Gesloten issues", @@ -1488,18 +1459,9 @@ "OPTION_ALL": "Alles", "OPTION_INVOLVED": "Betrokken", "OPTION_NONE": "Geen" - }, - "POPOVER": { - "USER_PROFILE": "Gebruikersprofiel", - "CHANGE_PASSWORD": "Wachtwoord wijzigen", - "NOTIFICATIONS": "Notificaties", - "FEEDBACK": "Feedback", - "TITLE_AVATAR": "Gebruikersinstellingen" } }, "USER_PROFILE": { - "IMAGE_HELP": "The image will be scaled to 80x80px.", - "ACTION_CHANGE_IMAGE": "Verander", "ACTION_USE_GRAVATAR": "Use default image", "ACTION_DELETE_ACCOUNT": "Verwijderd Taiga account", "CHANGE_EMAIL_SUCCESS": "Controleer je inbox!
We hebben je een email gestuurd met instructie om je nieuwe adres in te stellen", @@ -1517,25 +1479,10 @@ "THEME_DEFAULT": "-- gebruikt standaard thema --" } }, - "WIZARD": { - "SECTION_TITLE_CREATE_PROJECT": "Project aanmaken", - "CREATE_PROJECT_TEXT": "Vers en proper. Spanned!", - "CHOOSE_TEMPLATE": "Which template fits your project best?", - "CHOOSE_TEMPLATE_TITLE": "More info about project templates", - "CHOOSE_TEMPLATE_INFO": "More info", - "PROJECT_DETAILS": "Project Details", - "PUBLIC_PROJECT": "Public Project", - "PRIVATE_PROJECT": "Private Project", - "CREATE_PROJECT": "Project aanmaken", - "MAX_PRIVATE_PROJECTS": "You've reached the maximum number of private projects", - "MAX_PUBLIC_PROJECTS": "Unfortunately, you've reached the maximum number of public projects", - "CHANGE_PLANS": "change plans" - }, "WIKI": { "PAGE_TITLE": "{{wikiPageName}} - Wiki - {{projectName}}", "PAGE_DESCRIPTION": "Laatst bewerkt op {{lastModifiedDate}} ({{totalEditions}} keer bewerkt in totaal) Inhoud: {{ wikiPageContent }}", "DATETIME": "DD MMM YYYY HH:mm", - "PLACEHOLDER_PAGE": "Schrijf je wiki pagina", "REMOVE": "Verwijder deze wiki pagina", "DELETE_LIGHTBOX_TITLE": "Verwijderd wiki pagina", "DELETE_LINK_TITLE": "Delete Wiki link", @@ -1693,7 +1640,6 @@ "MOST_LIKED": "Most liked", "MOST_LIKED_EMPTY": "There are no LIKED projects yet", "VIEW_MORE": "View more", - "RECRUITING": "This project is looking for people", "FEATURED": "Featured Projects", "EMPTY": "There are no projects to show with this search criteria.
Try again!", "FILTERS": { diff --git a/app/locales/taiga/locale-pl.json b/app/locales/taiga/locale-pl.json index 46de1f6e..5b76d6ca 100644 --- a/app/locales/taiga/locale-pl.json +++ b/app/locales/taiga/locale-pl.json @@ -4,7 +4,6 @@ "NO": "Nie", "OR": "lub", "LOADING": "Wczytywanie...", - "LOADING_PROJECT": "Wczytywanie projektu...", "DATE": "DD MMM YYYY", "DATETIME": "DD MMM YYYY HH:mm", "SAVE": "Zapisz", @@ -27,21 +26,18 @@ "BLOCKED_NOTE": "Dlaczego jest zabokowane?", "BLOCKED_REASON": "Wyjaśnij powód", "CREATED_BY": "Utworzone przez {{fullDisplayName}}", - "FROM": "od", - "TO": "do", "CLOSE": "zamknij", "GO_HOME": "Zabierz mnie do strony domowej", "PLUGINS": "Wtyczki", - "BETA": "Wersja beta", "ONE_ITEM_LINE": "Jedna pozycja na wiersz...", "NEW_BULK": "Nowe zbiorcze dodawanie", "RELATED_TASKS": "Zadania pokrewne", - "PREVIOUS": "Previous", + "PREVIOUS": "Poprzedni", "NEXT": "Następny", "LOGOUT": "Wyloguj", "EXTERNAL_USER": "zewnętrzny użytkownik", "GENERIC_ERROR": "Umpa Lumpa mówi {{error}}.", - "IOCAINE_TEXT": "Czujesz się trochę przytłoczony zadaniem? Daj znać innym klikając na ikonę Iokainy podczas edycji zadania. Jest szansa, że staniesz się odporny na tą (fikcyjną ;) ) śmiertelną truciznę biorąc małe dawki. Z pewnością jednak da Ci ona dodatkowego kopa, który pomoże w pokonaniu nowego wyzwania i staniu się lepszym w tym co robisz!", + "IOCAINE_TEXT": "This member is feeling a bit overwhelmed by this task. Will become immune to the iocaine poison over time with your help. For now, may need a hug.", "CLIENT_REQUIREMENT": "Client requirement is new requirement that was not previously expected and it is required to be part of the project", "TEAM_REQUIREMENT": "Team requirement is a requirement that must exist in the project but should have no cost for the client", "OWNER": "Project Owner", @@ -130,7 +126,7 @@ "ADD": "Dodaj tag" }, "DESCRIPTION": { - "EMPTY": "Puste miejsce jest takie nudne... opisz, przydaj sensu...", + "EMPTY": "Puste miejsce jest takie nudne... opisz, nadaj sensu...", "NO_DESCRIPTION": "Jeszcze bez opisu" }, "FIELDS": { @@ -148,7 +144,6 @@ "PRIORITY": "Priorytet", "ASSIGNED_TO": "Przydzielone do", "POINTS": "Punkty", - "BLOCKED_NOTE": "zablokowana notka", "IS_BLOCKED": "zablokowana", "REF": "Ref", "VOTES": "Głosy", @@ -165,14 +160,14 @@ "TOO_MANY": "...zbyt wielu użytkowników, filtruj dalej Umpa Lumpy nie ogarniają", "CONFIRM_UNASSIGNED": "Jesteś pewny, że chcesz pozostawić nieprzypisane?", "TITLE_ACTION_EDIT_ASSIGNMENT": "Edytuj przypisanie", - "SELF": "Assign to me" + "SELF": "Przypisz do mnie" }, "STATUS": { "CLOSED": "Zamknięte", "OPEN": "Otwórz" }, "WATCHERS": { - "WATCHERS": "Watchers", + "WATCHERS": "Obserwatorzy", "ADD": "Dodaj obserwatorów", "TITLE_ADD": "Dodaj członka projektu do listy obserwatorów.", "DELETE": "Usuń obserwatora", @@ -182,15 +177,11 @@ "WATCH": "Obserwuj", "WATCHING": "Obserwujesz", "UNWATCH": "Nie obserwuj", - "WATCHERS": "Watchers", + "WATCHERS": "Obserwatorzy", "BUTTON_TITLE": "Obserwuj lub przestań obserwować", "COUNTER_TITLE": "{total, plural, one{one watcher} other{# watchers}}" }, "VOTE_BUTTON": { - "UPVOTE": "Oceń pozytywnie", - "UPVOTED": "Ocenione pozytywnie", - "DOWNVOTE": "Oceń negatywnie", - "VOTERS": "Voters", "BUTTON_TITLE": "Ocen ten obiekt", "COUNTER_TITLE": "{total, plural, one{one vote} other{# votes}}" }, @@ -202,10 +193,9 @@ "CONFIRM_DELETE": "Remeber that all values in this custom field will be deleted.\n Are you sure you want to continue?" }, "FILTERS": { - "TITLE": "Filtry", "INPUT_PLACEHOLDER": "Temat lub odniesienie", "TITLE_ACTION_FILTER_BUTTON": "szukaj", - "INPUT_SEARCH_PLACEHOLDER": "Temat lub referencja", + "TITLE": "Filtry", "TITLE_ACTION_SEARCH": "Szukaj", "ACTION_SAVE_CUSTOM_FILTER": "zapisz jako filtr niestandardowy", "PLACEHOLDER_FILTER_NAME": "Wpisz nazwę filtru i kliknij enter", @@ -220,41 +210,10 @@ "CREATED_BY": "Stworzona przez", "CUSTOM_FILTERS": "Filtry niestandardowe", "EPIC": "Epic" - }, - "CONFIRM_DELETE": { - "TITLE": "Usuń filtr niestandardowy", - "MESSAGE": "filtr niestandardowy '{{customFilterName}}'" } }, "WYSIWYG": { - "H1_BUTTON": "Nagłówek pierwszego poziomu", - "H1_SAMPLE_TEXT": "Przykładowy tekst...", - "H2_BUTTON": "Nagłówek drugiego poziomu", - "H2_SAMPLE_TEXT": "Przykładowy tekst...", - "H3_BUTTON": "Nagłówek trzeciego poziomu", - "H3_SAMPLE_TEXT": "Przykładowy tekst...", - "BOLD_BUTTON": "Pogrubienie", - "BOLD_BUTTON_SAMPLE_TEXT": "Przykładowy tekst...", - "ITALIC_BUTTON": "Kursywa", - "ITALIC_SAMPLE_TEXT": "Przykładowy tekst...", - "STRIKE_BUTTON": "Przekreślenie", - "STRIKE_SAMPLE_TEXT": "Przykładowy tekst...", - "BULLETED_LIST_BUTTON": "Lista", - "BULLETED_LIST_SAMPLE_TEXT": "Przykładowy tekst...", - "NUMERIC_LIST_BUTTON": "Lista Numerowana", - "NUMERIC_LIST_SAMPLE_TEXT": "Przykładowy tekst...", - "PICTURE_BUTTON": "Obraz", - "PICTURE_SAMPLE_TEXT": "Tekst alternatywny dla obrazka...", - "LINK_BUTTON": "Link", - "LINK_SAMPLE_TEXT": "Twój tekst do linku...", - "QUOTE_BLOCK_BUTTON": "Cytat", - "QUOTE_BLOCK_SAMPLE_TEXT": "Przykładowy tekst...", - "CODE_BLOCK_BUTTON": "Blok Kodu", - "CODE_BLOCK_SAMPLE_TEXT": "Przykładowy tekst...", - "PREVIEW_BUTTON": "Podgląd", - "EDIT_BUTTON": "Edycja", - "ATTACH_FILE_HELP": "Attach files by dragging & dropping on the textarea above.", - "ATTACH_FILE_HELP_SAVE_FIRST": "Save first before if you want to attach files by dragging & dropping on the textarea above.", + "OUTDATED": "Another person has made changes while you were editing. Check the new version on the activiy tab before you save your changes.", "MARKDOWN_HELP": "Składnia Markdown pomoc" }, "PERMISIONS_CATEGORIES": { @@ -307,10 +266,6 @@ "ADD_WIKI_LINKS": "Dodawaj linki Wiki", "DELETE_WIKI_LINKS": "Usuwaj linki Wiki" } - }, - "META": { - "PAGE_TITLE": "Taiga", - "PAGE_DESCRIPTION": "Taiga to platforma do zarządzania projektami dla startup'ów i zwinnych deweloperów i projektantów, którzy potrzebują prostego,atrakcyjnego wizualnie narzędzia. Taiga sprawia, że praca z projektem staje się przyjemniejsza." } }, "LOGIN": { @@ -366,7 +321,6 @@ }, "CHANGE_PASSWORD": { "PAGE_TITLE": "Zmień hasło - Taiga", - "PAGE_DESCRIPTION": "Ustaw nowe hasło dla swojego konta Taiga. Ej! może byś coś zjadł? To jest dobre dla Twojego mózgu :)", "SECTION_NAME": "Zmień hasło", "FIELD_CURRENT_PASSWORD": "Obecne hasło", "PLACEHOLDER_CURRENT_PASSWORD": "Twoje obecne hasło (lub puste, jeśli jeszcze go nie masz)", @@ -391,8 +345,7 @@ }, "INVITATION_LOGIN_FORM": { "NOT_FOUND": "Nasze Umpa Lumpy nie znajdują Twojego zaproszenia :(", - "SUCCESS": "Udało Ci się dołączyć do tego projektu. Witaj w {{project_name}}", - "ERROR": "Według naszych Umpa Lump, nie jesteś jeszcze zarejestrowany. Albo wpisałeś złe hasło." + "SUCCESS": "Udało Ci się dołączyć do tego projektu. Witaj w {{project_name}}" }, "HOME": { "PAGE_TITLE": "Strona główna - Taiga", @@ -427,7 +380,7 @@ "ASSIGNED_TO": "Przydzielone", "STATUS": "Statusy", "PROGRESS": "Postęp", - "VIEW_OPTIONS": "View options" + "VIEW_OPTIONS": "Zobacz opcje" }, "CREATE": { "TITLE": "Nowy epik", @@ -463,10 +416,7 @@ "TITLE_LIGHTBOX_DELETE_ATTACHMENT": "Usuń załącznik...", "MSG_LIGHTBOX_DELETE_ATTACHMENT": "załącznik '{{fileName}}'", "ERROR_DELETE_ATTACHMENT": "Nie udało się usunąć załącznika w związku z następującym błędem: {{errorMessage}}", - "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) plik jest za ciężki, maksymalna wartość to: ({{maxFileSize}})", - "FIELDS": { - "IS_DEPRECATED": "jest przedawniony" - } + "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) plik jest za ciężki, maksymalna wartość to: ({{maxFileSize}})" }, "PAGINATION": { "PREVIOUS": "Poprzedni", @@ -502,13 +452,10 @@ "ASYNC_MESSAGE": "Wyślemy Ci wiadomość e-mail, kiedy będziemy gotowi.", "SYNC_MESSAGE": "Jeśli pobieranie nie rozpocznie się automatycznie kliknij tutaj.", "ERROR": "Umpa Lumpy mają problem z wygenerowaniem zrzutu. Spróbuj ponownie.", - "ERROR_BUSY": "Przepraszam, Umpa Lumpy są teraz bardzo zajęte, spróbuj ponownie za chwilę.", - "ERROR_MESSAGE": "Umpa Lumpy mają następujący problem z wygenerowaniem zrzutu: {{message}}" + "ERROR_BUSY": "Przepraszam, Umpa Lumpy są teraz bardzo zajęte, spróbuj ponownie za chwilę." }, "MODULES": { "TITLE": "Moduły", - "ENABLE": "Włącz", - "DISABLE": "Wyłącz", "EPICS": "Epiki", "EPICS_DESCRIPTION": "Visualize and manage the most strategic part of your project", "BACKLOG": "Dziennik", @@ -537,21 +484,20 @@ "PAGE_TITLE": "{{sectionName}} - Profil projektu - {{projectName}}", "PROJECT_DETAILS": "Szczegóły projektu", "PROJECT_NAME": "Nazwa projektu", - "PROJECT_SLUG": "Szczegóły projektu", "TAGS": "Tagi", "DESCRIPTION": "Opis", "RECRUITING": "Czy ten pojekt szuka uczestników?", "RECRUITING_MESSAGE": "Kogo szukasz?", "RECRUITING_PLACEHOLDER": "Define the profiles you are looking for", + "FEEDBACK": "Receive feedback from Taiga users?", "PUBLIC_PROJECT": "Projekt publiczny", "PRIVATE_PROJECT": "Projekt prywatny", "PRIVATE_OR_PUBLIC": "What's the difference between public and private projects?", "DELETE": "Usuń ten projekt", - "LOGO_HELP": "The image will be scaled to 80x80px.", - "CHANGE_LOGO": "Change logo", - "ACTION_USE_DEFAULT_LOGO": "Use default image", - "MAX_PRIVATE_PROJECTS": "You've reached the maximum number of private projects allowed by your current plan", - "MAX_PRIVATE_PROJECTS_MEMBERS": "The maximum number of members for private projects has been exceeded", + "CHANGE_LOGO": "Zmień logo", + "ACTION_USE_DEFAULT_LOGO": "Użyj domyślnego obrazu", + "MAX_PRIVATE_PROJECTS": "Osiągnąłeś maksymalną liczbę prywatnych projektów dozwoloną przez obecny plan", + "MAX_PRIVATE_PROJECTS_MEMBERS": "Maksymalna liczba członków dla prywatnych projektów została przekroczona.", "MAX_PUBLIC_PROJECTS": "Unfortunately, you've reached the maximum number of public projects allowed by your current plan", "MAX_PUBLIC_PROJECTS_MEMBERS": "The project exceeds your maximum number of members for public projects", "PROJECT_OWNER": "Project owner", @@ -595,6 +541,7 @@ "ISSUE_DESCRIPTION": "Własne pola dla zgłoszeń", "ISSUE_ADD": "Dodaj własne pole dla zgłoszeń", "FIELD_TYPE_TEXT": "Tekst", + "FIELD_TYPE_RICHTEXT": "Rich text", "FIELD_TYPE_MULTI": "Pole wielowierszowe", "FIELD_TYPE_DATE": "Date", "FIELD_TYPE_URL": "Url" @@ -623,7 +570,7 @@ "ACTION_ADD": "Dodaj nową ważność" }, "PROJECT_VALUES_STATUS": { - "TITLE": "Status", + "TITLE": "Statuses", "SUBTITLE": "Zdefiniuj statusy dla historyjek użytkownika, zadań i zgłoszeń.", "EPIC_TITLE": "Epic Statuses", "US_TITLE": "User Story Statuses", @@ -640,9 +587,9 @@ "TITLE": "Tagi", "SUBTITLE": "View and edit the color of your tags", "EMPTY": "Currently there are no tags", - "EMPTY_SEARCH": "It looks like nothing was found with your search criteria", + "EMPTY_SEARCH": "Nie znaleziono niczego, co spełniałoby podane kryteria.", "ACTION_ADD": "Dodaj tag", - "NEW_TAG": "New tag", + "NEW_TAG": "Nowy tag", "MIXING_HELP_TEXT": "Select the tags that you want to merge", "MIXING_MERGE": "Merge Tags", "SELECTED": "Selected" @@ -676,8 +623,8 @@ "INFO_VERIFYING_IP": "Zapytania Gitlab nie są szyfrowane zatem najlepszym sposobem weryfikacji źródła jest sprawdzenie adresu IP.Jeśli pole pozostanie puste sprawdzanie IP nie będzie działać." }, "GITHUB": { - "SECTION_NAME": "Github", - "PAGE_TITLE": "Github - {{projectName}}" + "SECTION_NAME": "GitHub", + "PAGE_TITLE": "GitHub - {{projectName}}" }, "GOGS": { "SECTION_NAME": "Gogs", @@ -686,7 +633,6 @@ "WEBHOOKS": { "PAGE_TITLE": "Webhooks - {{projectName}}", "SECTION_NAME": "Webhooks", - "SUBTITLE": "Webhooks notify external services about events in Taiga, like comments, user stories....", "ADD_NEW": "Dodaj nowy webhook", "TYPE_NAME": "Wpisz nazwę serwisu", "TYPE_PAYLOAD_URL": "Type the service payload url", @@ -718,7 +664,7 @@ "CANCEL_TITLE": "Anuluj tworzenie", "SET_FIELD_NAME": "podaj nazwę pola", "SET_FIELD_DESCRIPTION": "podaj opis pola", - "FIELD_TYPE_DEFAULT": "-- select one --", + "FIELD_TYPE_DEFAULT": "-- wybierz --", "ACTION_UPDATE": "Aktualizuj pole", "ACTION_CANCEL_EDITION": "Anuluj edycję" }, @@ -732,7 +678,6 @@ "DELETE_MEMBER": "Usuń członka", "RESEND": "Wyślij ponownie", "SUCCESS_SEND_INVITATION": "Ponownie wysłano zaproszenie do '{{e-mail}}'.", - "ERROR_SEND_INVITATION": "Zaproszenie nie zostało wysłane.", "SUCCESS_DELETE": "Usunięto {{message}}.", "ERROR_DELETE": "Nie usunięto {{message}}.", "DEFAULT_DELETE_MESSAGE": "zaproszenie do {{e-mail}}" @@ -761,16 +706,11 @@ "PLACEHOLDER_WRITE_NAME": "Wpisz nazwę nowego statusu" }, "MENU": { - "TITLE": "Admin", "PROJECT": "Projekt", "ATTRIBUTES": "Atrybuty", "MEMBERS": "Członkowie", "PERMISSIONS": "Uprawnienia", - "INTEGRATIONS": "Integracje", - "PLUGINS": "Wtyczki" - }, - "SUBMENU_PROJECT_ATTRIBUTES": { - "TITLE": "Atrybuty" + "INTEGRATIONS": "Integracje" }, "SUBMENU_PROJECT_VALUES": { "STATUS": "Status", @@ -781,17 +721,11 @@ "CUSTOM_FIELDS": "Niestandardowe pola", "TAGS": "Tagi" }, - "SUBMENU_PROJECT_PROFILE": { - "TITLE": "Profil projektu" - }, "SUBMENU_ROLES": { "TITLE": "Role", "ACTION_NEW_ROLE": "+ Nowa rola", "TITLE_ACTION_NEW_ROLE": "Dodaj nową rolę" }, - "SUBMENU_THIDPARTIES": { - "TITLE": "Ważność" - }, "PROJECT_TRANSFER": { "DO_YOU_ACCEPT_PROJECT_OWNERNSHIP": "Would you like to become the new project owner?", "PRIVATE": "Private", @@ -806,15 +740,13 @@ "PRIVATE": "Please remember that you can own up to {{maxProjects}} private projects. You currently own {{currentProjects}} private projects", "PUBLIC": "Please remember that you can own up to {{maxProjects}} public projects. You currently own {{currentProjects}} public projects" }, - "CANT_BE_OWNED": "At the moment you cannot become an owner of a project of this type. If you would like to become the owner of this project, please contact the administrator so they change your account settings to enable project ownership.", - "CHANGE_MY_PLAN": "Change my plan" + "CANT_BE_OWNED": "At the moment you cannot become an owner of a project of this type. If you would like to become the owner of this project, please contact the administrator so they change your account settings to enable project ownership." } }, "USER": { "PROFILE": { "PAGE_TITLE": "{{userFullName}} (@{{userUsername}})", "EDIT": "Edycja profilu", - "FOLLOW": "Obserwuj", "CLOSED_US": "Zamknięte historyjki użytkownika", "PROJECTS": "Projekty", "PROJECTS_EMPTY": "{{username}} jeszcze nie uczestniczy w żadnym projekcie", @@ -822,13 +754,12 @@ "CONTACTS_EMPTY": "{{username}} jeszcze nie ma kontaktów", "CURRENT_USER_CONTACTS_EMPTY": "Jeszcze nie masz kontaktów", "CURRENT_USER_CONTACTS_EMPTY_EXPLAIN": "Ludzie z którymi pracujesz w Taiga staną się Twoimi kontaktami automatycznie.", - "REPORT": "Zgłoś naruszenie", "TABS": { "ACTIVITY_TAB": "Oś czasu", "ACTIVITY_TAB_TITLE": "Wyświetl całą aktywność użytkownika", "PROJECTS_TAB": "Projekty", "PROJECTS_TAB_TITLE": "Lista wszystkich projektów, do których należy użytkownik", - "LIKES_TAB": "Likes", + "LIKES_TAB": "Polubienia", "LIKES_TAB_TITLE": "List all likes made by this user", "VOTES_TAB": "Głosy", "VOTES_TAB_TITLE": "List all votes made by this user", @@ -848,13 +779,13 @@ "FILTER_TYPE_ALL": "Wszystkie", "FILTER_TYPE_ALL_TITLE": "Show all", "FILTER_TYPE_PROJECTS": "Projekty", - "FILTER_TYPE_PROJECT_TITLES": "Show only projects", + "FILTER_TYPE_PROJECTS_TITLE": "Show only projects", "FILTER_TYPE_EPICS": "Epiki", - "FILTER_TYPE_EPIC_TITLES": "Show only epics", + "FILTER_TYPE_EPICS_TITLE": "Show only epics", "FILTER_TYPE_USER_STORIES": "Stories", - "FILTER_TYPE_USER_STORIES_TITLES": "Show only user stories", + "FILTER_TYPE_USER_STORIES_TITLE": "Show only user stories", "FILTER_TYPE_TASKS": "Zadania", - "FILTER_TYPE_TASK_TITLES": "Show only tasks", + "FILTER_TYPE_TASKS_TITLE": "Show only tasks", "FILTER_TYPE_ISSUES": "Zgłoszenia", "FILTER_TYPE_ISSUES_TITLE": "Show only issues", "EMPTY_TITLE": "Wygląda na to, że nie ma niczego do wyświetlenia tutaj." @@ -862,8 +793,6 @@ }, "PROJECT": { "PAGE_TITLE": "{{projectName}}", - "WELCOME": "Witamy", - "SECTION_PROJECTS": "Projekty", "HELP": "Ustal kolejność Twoich projektów tak, aby na górze znalazły się te najważniejsze.
Pierwsze 10 projektów pojawi się w liście projektów na górnym pasku nawigacji.", "PRIVATE": "Projekt prywatny", "LOOKING_FOR_PEOPLE": "Ten projekt szuka uczestników", @@ -875,12 +804,6 @@ "THIS_PROJECT_IS_BLOCKED": "Ten projekt jest tymczasowo zablokowany", "TO_UNBLOCK_CONTACT_THE_ADMIN_STAFF": "Aby odblokować swój projekt, skontaktuj się z administacją" }, - "STATS": { - "PROJECT": "projekt
punkty", - "DEFINED": "zdefiniowane
punkty", - "ASSIGNED": "przypisane
punkty", - "CLOSED": "zamknięte
punkty" - }, "SECTION": { "SEARCH": "Szukaj", "TIMELINE": "Oś czasu", @@ -893,26 +816,16 @@ "ADMIN": "Admin" }, "NAVIGATION": { - "SECTION_TITLE": "Twoje projekty", - "PLACEHOLDER_SEARCH": "Szukaj w ...", "ACTION_CREATE_PROJECT": "Stwórz projekt", - "ACTION_IMPORT_PROJECT": "Importuj projekt", - "MANAGE_PROJECTS": "Manage projects", + "MANAGE_PROJECTS": "Zarządzaj projektami", "TITLE_CREATE_PROJECT": "Utwórz projekt", - "TITLE_IMPORT_PROJECT": "Importuj projekt", - "TITLE_PRVIOUS_PROJECT": "Pokaż poprzedni projekt", - "TITLE_NEXT_PROJECT": "Pokaż kolejne projekty", "HELP_TITLE": "Taiga strona wsparcia", "HELP": "Pomoc", - "HOMEPAGE": "Homepage", + "HOMEPAGE": "Strona startowa", "FEEDBACK_TITLE": "Prześlij opinię", "FEEDBACK": "Feedback", "NOTIFICATIONS_TITLE": "Edytuj ustawienia powiadomień", "NOTIFICATIONS": "Powiadomienia", - "ORGANIZATIONS_TITLE": "Edytuj organizacje", - "ORGANIZATIONS": "Edytuj organizacje", - "SETTINGS_TITLE": "Edytuj ustawienia", - "SETTINGS": "Ustawienia", "VIEW_PROFILE_TITLE": "Zobacz profil", "VIEW_PROFILE": "Zobacz profil", "EDIT_PROFILE_TITLE": "Edytuj profil", @@ -921,24 +834,99 @@ "CHANGE_PASSWORD": "Zmień hasło", "DASHBOARD_TITLE": "Dashboard", "DISCOVER_TITLE": "Odkryj projekty", - "NEW_ITEM": "Nowe", - "DISCOVER": "Odkryj", - "ACTION_REORDER": "Przeciągnij i upuść żeby zmienić kolejność" + "DISCOVER": "Odkryj" + }, + "LIKE_BUTTON": { + "LIKE": "Like", + "LIKED": "Liked", + "UNLIKE": "Unlike", + "BUTTON_TITLE": "Like or unlike this project", + "COUNTER_TITLE": "{total, plural, one{one fan} other{# fans}}" + }, + "WATCH_BUTTON": { + "BUTTON_TITLE": "Watch this project and set notification policy", + "WATCH": "Watch", + "WATCHING": "Obserwujesz", + "COUNTER_TITLE": "{total, plural, one{one watcher} other{# watchers}}", + "OPTIONS": { + "NOTIFY_ALL": "Receive all notifications", + "NOTIFY_ALL_TITLE": "Receive all notifications for this project", + "NOTIFY_INVOLVED": "Only involved", + "NOTIFY_INVOLVED_TITLE": "Recive notificacions only when you are involved", + "UNWATCH": "Unwatch", + "UNWATCH_TITLE": "Unwatch this project" + } + }, + "CONTACT_BUTTON": { + "CONTACT_TITLE": "Contact the project team", + "CONTACT_BUTTON": "Contact the project" + }, + "CREATE": { + "TITLE": "Utwórz projekt", + "CHOOSE_TEMPLATE": "Which template fits your project better?", + "TEMPLATE_SCRUM": "Scrum", + "TEMPLATE_SCRUM_DESC": "Prioritize and solve your tasks in short time cycles.", + "TEMPLATE_SCRUM_LONGDESC": "Scrum is an iterative and incremental agile software development methodology for managing product development.\nThe product backlog is what will ultimately be delivered, ordered into the sequence in which it should be delivered. Product Backlogs are broken into manageable, executable chunks named sprints. Every certain amount of time the team initiates a new sprint and commits to deliver a certain number of user stories from the backlog, in accordance with their skills, abilities and resources. The project advances as the backlog becomes depleted.", + "TEMPLATE_KANBAN": "Kanban", + "TEMPLATE_KANBAN_DESC": "Keep a constant workflow on independent tasks", + "TEMPLATE_KANBAN_LONGDESC": "The Kanban methodology is used to divide project development (any sort of project) into stages.\nA kanban card is like an index card or post-it note that details every task (or user story) in a project that needs to be completed. The Kanban board is used to move each card from one state of completion to the next and in so doing, helps track progress.", + "DUPLICATE": "Duplicate project", + "DUPLICATE_DESC": "Start clean and keep your configuration", + "IMPORT": "Importuj projekt", + "IMPORT_DESC": "Import your project from multiple platforms into Taiga", + "INVITE": "Invite to the project", + "SOLO_PROJECT": "You'll be alone in this project", + "INVITE_LATER": "(You'll be able to invite more members later)", + "BACK": "Back", + "MAX_PRIVATE_PROJECTS": "Niestety, osiągnąłeś maksimum dozwolonych projektów prywatnych.\nJeśli chciałbyś zwiększyć obecny limit, skontaktuj się z administratorem.", + "MAX_PUBLIC_PROJECTS": "Unfortunately, You've reached the maximum number of public projects.\nIf you would like to increase the current limit please contact the administrator.", + "PUBLIC_PROJECT": "Projekt publiczny", + "PRIVATE_PROJECT": "Projekt prywatny" + }, + "COMMON": { + "DETAILS": "New project details", + "PROJECT_TITLE": "Nazwa Projektu", + "PROJECT_DESCRIPTION": "Project Description" + }, + "DUPLICATE": { + "TITLE": "Duplicate Project", + "DESCRIPTION": "Start clean and keep your configuration", + "SELECT_PLACEHOLDER": "Choose an existing project to duplicate" }, "IMPORT": { - "TITLE": "Importowanie Projektu", - "UPLOADING_FILE": "Umpa Lumpy ładują plik zrzutu", - "DESCRIPTION": "Proces może zająć chwilkę, proszę nie zamykaj okna.", + "TITLE": "Import Project", + "DESCRIPTION": "Import your project from multiple platforms into Taiga", "ASYNC_IN_PROGRESS_TITLE": "Umpa Lumpy importują projekt", "ASYNC_IN_PROGRESS_MESSAGE": "To może zając kilka minut.
Otrzymasz mail gdy wszystko będzie gotowe.", "UPLOAD_IN_PROGRESS_MESSAGE": "Wysłano {{uploadedSize}} z {{totalSize}}", "ERROR": "Umpa Lumpy mają problem z importem. Spróbuj ponownie.", - "ERROR_TOO_MANY_REQUEST": "Umpa Lumpy są teraz zajęte a serwer ma zadyszkę. Spróbuj ponownie za chwilę.", + "ERROR_TOO_MANY_REQUEST": "Przepraszam, Umpa Lumpy są teraz bardzo zajęte, spróbuj ponownie za chwilę.", "ERROR_MESSAGE": "Przy imporcie wystąpił następujący problem: {{error_message}}", "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) plik jest za ciężki, maksymalna wartość to: ({{maxFileSize}})", "SYNC_SUCCESS": "Twój projekt zaimportował się prawidłowo!", + "IMPORT": "Import", + "WHO_IS": "Their tasks will be assigned to ...", + "WRITE_EMAIL": "Or if you want, write the email that this user uses in Taiga", + "SEARCH_CONTACT": "Or if you want, search in your contacts", + "WRITE_EMAIL_LABEL": "Write the email that this user uses in Taiga", + "ACCEEDE": "Acceede", + "PROJECT_MEMBERS": "Project Members", + "PROCESS_DESCRIPTION": "Tell us who from Taiga you want to assign the tasks of {{platform}}", + "MATCH": "Is {{user_external}} the same person as {{user_internal}}?", + "CHOOSE": "Select user", + "LINKS": "Links with {{platform}}", + "LINKS_DESCRIPTION": "Do you want to keep the link of each item with the original {{platform}} card?", + "WARNING_MAIL_USER": "Note that if the user does not have a Taiga account we will not be able to assign the tasks to him.", + "ASSIGN": "Assign", + "PROJECT_SELECTOR": { + "NO_RESULTS": "Nie znaleziono niczego, co spełniałoby podane kryteria.", + "ACTION_SEARCH": "szukaj", + "ACTION_BACK": "Back" + }, "PROJECT_RESTRICTIONS": { - "PROJECT_MEMBERS_DESC": "The project you are trying to import has {{members}} members, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per project. If you would like to increase that limit please contact the administrator.", + "PROJECT_MEMBERS_DESC_PRIVATE": "The project you are trying to import has {{members}} members including you, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per private project. If you would like to increase that limit please contact the administrator.", + "PROJECT_MEMBERS_DESC_PUBLIC": "The project you are trying to import has {{members}} members including you, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per public project. If you would like to increase that limit please contact the administrator.", + "ACCOUNT_ALLOW_MEMBERS": "Your account only allows {{members}} members", "PRIVATE_PROJECTS_SPACE": { "TITLE": "Unfortunately, your current plan does not allow for additional private projects", "DESC": "The project you are trying to import is private. Unfortunately, your current plan does not allow for additional private projects." @@ -961,39 +949,67 @@ "TITLE": "Unfortunately your current plan doesn't allow additional public projects or an increase of more than {{max_memberships}} members per public project", "DESC": "The project that you are trying to import is public and has more than {{members}} members." } - } - }, - "LIKE_BUTTON": { - "LIKE": "Like", - "LIKED": "Liked", - "UNLIKE": "Unlike", - "BUTTON_TITLE": "Like or unlike this project", - "COUNTER_TITLE": "{total, plural, one{one fan} other{# fans}}" - }, - "WATCH_BUTTON": { - "BUTTON_TITLE": "Watch this project and set notification policy", - "WATCH": "Watch", - "WATCHING": "Obserwujesz", - "COUNTER_TITLE": "{total, plural, one{one watcher} other{# watchers}}", - "OPTIONS": { - "NOTIFY_ALL": "Receive all notifications", - "NOTIFY_ALL_TITLE": "Receive all notifications for this project", - "NOTIFY_INVOLVED": "Only involved", - "NOTIFY_INVOLVED_TITLE": "Recive notificacions only when you are involved", - "UNWATCH": "Unwatch", - "UNWATCH_TITLE": "Unwatch this project" + }, + "IN_PROGRESS": { + "TITLE": "Importowanie Projektu", + "DESCRIPTION": "Proces może zająć chwilkę, proszę nie zamykaj okna." + }, + "WARNING": { + "TITLE": "Some taks will be unassigned", + "DESCRIPTION": "There are still unidentified people. The cards assigned to these people will remain unassigned. Check all the contacts to not lose that information.", + "CHECK": "Check contacts" + }, + "TAIGA": { + "SELECTOR": "Import your Taiga project" + }, + "TRELLO": { + "SELECTOR": "Import your Trello boards into Taiga", + "CHOOSE_PROJECT": "Choose board that you want to import", + "NO_PROJECTS": "It seems you have no boards in Trello" + }, + "GITHUB": { + "SELECTOR": "Import your GitHub project issues", + "CHOOSE_PROJECT": "Find the project you want to import", + "NO_PROJECTS": "It seems you have no porjects in GitHub", + "HOW_DO_YOU_WANT_TO_IMPORT": "How do you want to import your issues into Taiga?", + "KANBAN_PROJECT": "As user stories in a kanban project", + "KANBAN_PROJECT_DESCRIPTION": "After that you can enable scrum with backlog.", + "SCRUM_PROJECT": "As user stories in a scrum project", + "SCRUM_PROJECT_DESCRIPTION": "After that you can enable kanban mode.", + "ISSUES_PROJECT": "As issues", + "ISSUES_PROJECT_DESCRIPTION": "You will not be able to use your issues in kanban or scrum mode. You will be able to enable kanban or scrum for new user stories" + }, + "ASANA": { + "SELECTOR": "Import your Asana project and choose how to manage it", + "CHOOSE_PROJECT": "Choose project that you want to import", + "NO_PROJECTS": "It seems you have no porjects in Asana", + "KANBAN_PROJECT": "Kanban", + "SCRUM_PROJECT": "Scrum", + "CREATE_AS_SCRUM_DESCRIPTION": "The tasks and sub-tasks of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_KANBAN_DESCRIPTION": "The tasks and sub-tasks of your project will be created as Taiga user stories and tasks." + }, + "JIRA": { + "SELECTOR": "Import your Jira project and choose how to manage it", + "CHOOSE_PROJECT": "Choose project or board that you want to import", + "NO_PROJECTS": "It seems you have no porjects or boards in Jira", + "URL": "Your Jira URL", + "KANBAN_PROJECT": "Kanban", + "SCRUM_PROJECT": "Scrum", + "ISSUES_PROJECT": "Zgłoszenia", + "CREATE_AS_SCRUM_DESCRIPTION": "The issues and sub-issues of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_KANBAN_DESCRIPTION": "The issues and sub-issues of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_ISSUES_DESCRIPTION": "What do you want to do with sub-issues from the Jira project? (Taiga doesn't allow sub-issues)", + "CREATE_NEW_ISSUES": "Convert sub-issues to new Taiga issues", + "NOT_CREATE_NEW_ISSUES": "Do not import sub-issues" } } }, "LIGHTBOX": { "DELETE_ACCOUNT": { - "SECTION_NAME": "Usuń konto z Taiga", "CONFIRM": "Czy na pewno chcesz usunąć swoje konto z Taiga?", - "NEWSLETTER_LABEL_TEXT": "Nie chcę więcej otrzymywać waszego newslettera", "CANCEL": "Powrót do ustawień", "ACCEPT": "Usuń konto", - "BLOCK_PROJECT": "Note that all the projects you own projects will be blocked after you delete your account. If you do want a project blocked, transfer ownership to another member of each project prior to deleting your account.", - "SUBTITLE": "Sorry to see you go. We'll be here if you should ever consider us again! :(" + "BLOCK_PROJECT": "Note that all the projects you own projects will be blocked after you delete your account. If you do want a project blocked, transfer ownership to another member of each project prior to deleting your account." }, "DELETE_PROJECT": { "TITLE": "Usuń projekt", @@ -1007,6 +1023,12 @@ }, "ADD_MEMBER": { "TITLE": "Nowy Członek", + "PLACEHOLDER": "Filter users or write an email to invite", + "ADD_EMAIL": "Dodaj e-mail", + "REMOVE": "Usuń", + "INVITE": "Zaproś", + "CHOOSE_ROLE": "Wybierz rolę", + "PLACEHOLDER_INVITATION_TEXT": "(Opcjonalne) Dodaj spersonalizowany tekst do zaproszenia. Napisz coś słodziachnego do nowego członka zespołu :)", "HELP_TEXT": "Jeżeli użytkownik jest już zarejestrowany w Taiga, będzie dodany automatycznie. W przeciwnym wypadku otrzyma zaproszenie." }, "CREATE_ISSUE": { @@ -1050,7 +1072,7 @@ "CREATE_MEMBER": { "PLACEHOLDER_INVITATION_TEXT": "(Opcjonalne) Dodaj spersonalizowany tekst do zaproszenia. Napisz coś słodziachnego do nowego członka zespołu :)", "PLACEHOLDER_TYPE_EMAIL": "Wpisz Email", - "LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "You are about to reach the maximum number of members allowed for this project, {{maxMembers}} members. If you would like to increase the current limit, please contact the administrator.", + "LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "Wkrótce osiągniesz maksimum dozwolonych członków dla tego projektu - {{maxMembers}} członków. Jeśli chciałbyś zwiększyć obecny limit, skontaktuj się z administratorem.", "LIMIT_USERS_WARNING_MESSAGE": "You are about to reach the maximum number of members allowed for this project, {{maxMembers}} members." }, "LEAVE_PROJECT_WARNING": { @@ -1065,9 +1087,15 @@ } }, "CHANGE_OWNER": { - "TITLE": "Who do you want to be the new project owner?", - "ADD_COMMENT": "Add comment", + "TITLE": "Kto ma być nowym właścicielem projektu?", + "ADD_COMMENT": "Dodaj komentarz", "BUTTON": "Ask this project member to become the new project owner" + }, + "CONTACT_PROJECT": { + "TITLE": "Wyślij e-mail do", + "WARNING": "The email will be received by the project admins", + "PLACEHOLDER": "Write your message", + "SEND": "Wyślij" } }, "EPIC": { @@ -1079,11 +1107,11 @@ "ERROR_UNLINK_RELATED_USERSTORY": "We have not been able to unlink: {{errorMessage}}", "CREATE_RELATED_USERSTORIES": "Stwórz relację z", "NEW_USERSTORY": "Nowa historyjka użytkownika", - "EXISTING_USERSTORY": "Existing user story", - "CHOOSE_PROJECT_FOR_CREATION": "What's the project?", + "EXISTING_USERSTORY": "Istniejąca historia użytkownika", + "CHOOSE_PROJECT_FOR_CREATION": "Co to za projekt?", "SUBJECT": "Temat", "SUBJECT_BULK_MODE": "Subject (bulk insert)", - "CHOOSE_PROJECT_FROM": "What's the project?", + "CHOOSE_PROJECT_FROM": "Co to za projekt?", "CHOOSE_USERSTORY": "What's the user story?", "NO_USERSTORIES": "This project has no User Stories yet. Please select another project.", "FILTER_USERSTORIES": "Filter user stories", @@ -1101,112 +1129,68 @@ "ADD_BULK": "Masowo dodaj nowe historyjki użytkownika", "PROMOTED": "Ta historyjka awansowała ze zgłoszenia:", "TITLE_LINK_GO_TO_ISSUE": "Idź do zgłoszenia", - "EXTERNAL_REFERENCE": "Ta historyjka została utworzona z", - "GO_TO_EXTERNAL_REFERENCE": "Idź do źródła", - "BLOCKED": "Ta historia użytkownika jest zablokowana", "TITLE_DELETE_ACTION": "Usuń historyjkę użytkownika", "LIGHTBOX_TITLE_BLOKING_US": "Blokuje nas", - "TASK_COMPLETED": "{{totalClosedTasks}}/{{totalTasks}} zadanie zakończone", - "ASSIGN": "Przypisz historyjkę użytkownika", "NOT_ESTIMATED": "Nie oszacowane", - "TOTAL_US_POINTS": "Łącznie punktów", "TRIBE": { "PUBLISH": "Publish as Gig in Taiga Tribe", "PUBLISH_INFO": "More info", "PUBLISH_TITLE": "More info on publishing in Taiga Tribe", "PUBLISHED_AS_GIG": "Story published as Gig in Taiga Tribe", - "EDIT_LINK": "Edit link", + "EDIT_LINK": "Edytuj link", "CLOSE": "Zamknij", "SYNCHRONIZE_LINK": "synchronizuj z Taiga Tribe", "PUBLISH_MORE_INFO_TITLE": "Potrzebujesz kogoś do tego zadania?", - "PUBLISH_MORE_INFO_TEXT": "

If you need help with a particular piece of work you can easily create gigs on Taiga Tribe and receive help from all over the world. You will be able to control and manage the gig enjoying a great community eager to contribute.

TaigaTribe was born as a Taiga sibling. Both platforms can live separately but we believe that there is much power in using them combined so we are making sure the integration works like a charm.

" + "PUBLISH_MORE_INFO_TEXT": "

If you need help with a particular piece of work you can easily create gigs on Taiga Tribe and receive help from all over the world. You will be able to control and manage the gig enjoying a great community eager to contribute.

TaigaTribe was born as a Taiga sibling. Both platforms can live separately but we believe that there is much power in using them combined so we are making sure the integration works like a charm.

" }, "FIELDS": { "TEAM_REQUIREMENT": "Wymaganie zespołu", - "CLIENT_REQUIREMENT": "Wymaganie klienta", - "FINISH_DATE": "Data zakończenia" + "CLIENT_REQUIREMENT": "Wymaganie klienta" } }, "COMMENTS": { "DELETED_INFO": "Komentarz usunięty przez {{user}}", - "TITLE": "Komentarze", - "COMMENTS_COUNT": "{{comments}} Comments", - "ORDER": "Order", + "COMMENTS_COUNT": "{{comments}} Komentarze", "OLDER_FIRST": "Starsze najpierw", "RECENT_FIRST": "Ostatnie najpierw", "COMMENT": "Komentarz", - "EDIT_COMMENT": "Edytuj komentarz", "EDITED_COMMENT": "Edytowano", "SHOW_HISTORY": "View historic", "TYPE_NEW_COMMENT": "Tutaj wpisz nowy komentarz", "SHOW_DELETED": "Pokaż usunięty komentarz", "HIDE_DELETED": "Ukryj skasowane komentarze", - "DELETE": "Delete comment", + "DELETE": "Usuń komentarz", "RESTORE": "Przywróć komentarz", "HISTORY": { "TITLE": "Aktywność" } }, "ACTIVITY": { - "SHOW_ACTIVITY": "Pokaż aktywność", - "DATETIME": "DD MMM YYYY HH:mm", - "SHOW_MORE": "+ Pokaż poprzednie wpisy ({{showMore}} więcej)", "TITLE": "Aktywność", "ACTIVITIES_COUNT": "{{activities}} Aktywności", - "REMOVED": "usunięty", - "ADDED": "dodany", "TAGS_ADDED": "dodano klucz", "TAGS_REMOVED": "usunięto tag:", "US_POINTS": "{{role}} points", "NEW_ATTACHMENT": "nowy załącznik", - "DELETED_ATTACHMENT": "deleted attachment:", + "DELETED_ATTACHMENT": "załącznik usunięty:", "UPDATED_ATTACHMENT": "updated attachment ({{filename}}):", "CREATED_CUSTOM_ATTRIBUTE": "created custom attribute", "UPDATED_CUSTOM_ATTRIBUTE": "updated custom attribute", - "SIZE_CHANGE": "Dokonano {size, plural, one{one change} other{# changes}}", "BECAME_DEPRECATED": "became deprecated", "BECAME_UNDEPRECATED": "became undeprecated", "TEAM_REQUIREMENT": "Wymaganie zespołu", "CLIENT_REQUIREMENT": "Wymaganie klienta", "BLOCKED": "Zablokowane", "VALUES": { - "YES": "tak", - "NO": "nie", - "EMPTY": "pusty", "UNASSIGNED": "nieprzypisany" }, "FIELDS": { "SUBJECT": "temat", - "NAME": "imię", "DESCRIPTION": "opis", - "CONTENT": "treść", "STATUS": "status", - "IS_CLOSED": "zamknięty", - "FINISH_DATE": "data zakończenia", "TYPE": "typ", - "PRIORITY": "priorytet", - "SEVERITY": "ważność", "ASSIGNED_TO": "przypisane do", - "WATCHERS": "obserwatorzy", "MILESTONE": "sprint", - "USER_STORY": "historyjka użytkownika", - "PROJECT": "projekt", - "IS_BLOCKED": "zablokowany", - "BLOCKED_NOTE": "notka blokady", - "POINTS": "punkty", - "CLIENT_REQUIREMENT": "wymaganie klienta", - "TEAM_REQUIREMENT": "wymaganie zespołu", - "IS_IOCAINE": "Iokaina", - "TAGS": "tagi", - "ATTACHMENTS": "załączniki", - "IS_DEPRECATED": "jest przedawniony", - "IS_NOT_DEPRECATED": "is not deprecated", - "ORDER": "kolejność", - "BACKLOG_ORDER": "kolejność backlogu", - "SPRINT_ORDER": "kolejność sprintów", - "KANBAN_ORDER": "kolejność kanban", - "TASKBOARD_ORDER": "kolejność tablicy zadań", - "US_ORDER": "Kolejność HU", "COLOR": "kolor" } }, @@ -1220,8 +1204,6 @@ "CUSTOMIZE_GRAPH_TITLE": "Set up the points and sprints through the Admin", "MOVE_US_TO_CURRENT_SPRINT": "Przejdź do bieżącego sprintu", "MOVE_US_TO_LATEST_SPRINT": "Przejdź do ostatniego sprintu", - "SHOW_FILTERS": "Pokaż filtry", - "SHOW_TAGS": "Pokaż tagi", "EMPTY": "The backlog is empty!", "CREATE_NEW_US": "Utwórz nową HU", "CREATE_NEW_US_EMPTY_HELP": "Możesz utworzyć nową historyjkę użytkownika", @@ -1248,6 +1230,12 @@ "SHOW": "Pokaż tagi", "HIDE": "Ukryj tagi" }, + "FORECASTING": { + "TITLE": "Velocity forecasting", + "BACKLOG": "Display backlog", + "NEW_SPRINT": "Candidate User Stories for your next sprint based on your velocity. Click to create a new sprint.", + "CURRENT_SPRINT": "Candidate User Stories for your sprint based on your velocity. Click to add to current sprint." + }, "TABLE": { "COLUMN_US": "Historyjki użytkownika", "TITLE_COLUMN_POINTS": "Widok według ról" @@ -1270,8 +1258,6 @@ }, "FILTERS": { "TOGGLE": "Przełącz widoczność filtrów", - "TITLE": "Filtry", - "REMOVE": "Usuń filtry", "HIDE": "Ukryj filtry", "SHOW": "Pokaż filtry" }, @@ -1280,7 +1266,6 @@ "DATE": "DD MMM YYYY", "LINK_TASKBOARD": "Tablica zadań sprintu", "TITLE_LINK_TASKBOARD": "Idź do tablicy zadań użytkownika {{name}}", - "NUMBER_SPRINTS": "
sprintów", "EMPTY": "There are no sprints yet", "WARNING_EMPTY_SPRINT_ANONYMOUS": "This sprint has no User Stories", "WARNING_EMPTY_SPRINT": "Drop here Stories from your backlog to start a new sprint", @@ -1305,7 +1290,6 @@ "TITLE_ACTION_ADD": "Dodaj nowe zadanie", "TITLE_ACTION_ADD_BULK": "Dodaj nowe zadania zbiorczo", "TITLE_ACTION_ASSIGN": "Przydziel zadanie", - "TITLE_ACTION_EDIT": "Zmień zadanie", "PLACEHOLDER_CARD_TITLE": "This could be a task", "PLACEHOLDER_CARD_TEXT": "Split Stories into tasks to track them separately", "TABLE": { @@ -1335,17 +1319,11 @@ "TITLE_SELECT_STATUS": "SNazwa statusu", "OWNER_US": "To zadanie należy do", "TITLE_LINK_GO_OWNER": "Idź do historyjki użytkownika", - "ORIGIN_US": "Źródło tego zadania to", - "TITLE_LINK_GO_ORIGIN": "Idź do historyjki użytkownika", - "BLOCKED": "To zadanie jest zablokowane", "TITLE_DELETE_ACTION": "Usuń zadanie", "LIGHTBOX_TITLE_BLOKING_TASK": "Blokowanie zadania", "FIELDS": { - "MILESTONE": "Sprint", - "USER_STORY": "Historyjka użytkownika", "IS_IOCAINE": "Iocaina" }, - "ACTION_IOCAINE": "Iocaina", "TITLE_ACTION_IOCAINE": "Czujesz się trochę przytłoczony zadaniem? Daj znać innym klikając na ikonę Iokainy podczas edycji zadania. Jest szansa, że staniesz się odporny na tą (fikcyjną ;) ) śmiertelną truciznę biorąc małe dawki. Z pewnością jednak da Ci ona dodatkowego kopa, który pomoże w pokonaniu nowego wyzwania i staniu się lepszym w tym co robisz!" }, "NOTIFICATION": { @@ -1374,14 +1352,12 @@ "ISSUES": { "PAGE_TITLE": "Zgłoszenia - {{projectName}}", "PAGE_DESCRIPTION": "Lista zgłoszeń w projekcie {{projectName}}: {{projectDescription}}", - "LIST_SECTION_NAME": "Zgłoszenia", "SECTION_NAME": "Zgłoszenie", "ACTION_NEW_ISSUE": "+ NOWE ZGŁOSZENIE", "ACTION_PROMOTE_TO_US": "Awansuj na historyjkę użytkownika", "PROMOTED": "To zgłoszenie zostało wypromowane na HU:", "EXTERNAL_REFERENCE": "Źródło zgłoszenia", "GO_TO_EXTERNAL_REFERENCE": "Idź do źródła", - "BLOCKED": "To zgłoszenie jest zablokowane", "ACTION_DELETE": "Usuń zgłoszenie", "LIGHTBOX_TITLE_BLOKING_ISSUE": "Blokowanie zgłoszenia", "FIELDS": { @@ -1423,15 +1399,11 @@ "SECTION_NAME": "Kanaban", "TITLE_ACTION_FOLD": "Zwiń kolumnę", "TITLE_ACTION_UNFOLD": "Rozwiń kolumnę", - "TITLE_ACTION_FOLD_CARDS": "Zwiń karty", - "TITLE_ACTION_UNFOLD_CARDS": "Rozwiń karty", "TITLE_ACTION_ADD_US": "Dodaj nową HU", "TITLE_ACTION_ADD_BULK": "Dodaj zbiorczo HU", "ACTION_SHOW_ARCHIVED": "Pokaż archiwalne", "ACTION_HIDE_ARCHIVED": "Ukryj archiwalne", "HIDDEN_USER_STORIES": "Historyjki użytkownika o tym statusie są domyślnie ukryte", - "ARCHIVED": "Zarchiwizowano", - "UNDO_ARCHIVED": "Przeciągnij i upuść ponownie aby cofnąć", "PLACEHOLDER_CARD_TITLE": "To są Twoje Historyjki Użytkownika", "PLACEHOLDER_CARD_TEXT": "Stories might also have subtasks to separate requirements" }, @@ -1452,7 +1424,6 @@ "PAGE_TITLE": "Zespół - {{projectName}}", "PAGE_DESCRIPTION": "Panel zespołu w którym zebrani są wszyscy jego członkowie pracujący przy projekcie {{projectName}}: {{projectDescription}}", "SECTION_NAME": "Zespół", - "APP_TITLE": "ZESPÓŁ - {{projectName}}", "PLACEHOLDER_INPUT_SEARCH": "Szukaj po imieniu...", "COLUMN_MR_WOLF": "Mr. Wolf", "EXPLANATION_COLUMN_MR_WOLF": "Zamknięte zgłoszenia", @@ -1488,19 +1459,10 @@ "OPTION_ALL": "Wszystkie", "OPTION_INVOLVED": "Z moim udziałem", "OPTION_NONE": "Żadne" - }, - "POPOVER": { - "USER_PROFILE": "Profil użytkownika", - "CHANGE_PASSWORD": "Zmień hasło", - "NOTIFICATIONS": "Powiadomienia", - "FEEDBACK": "Feedback", - "TITLE_AVATAR": "Preferencje użytkownika" } }, "USER_PROFILE": { - "IMAGE_HELP": "The image will be scaled to 80x80px.", - "ACTION_CHANGE_IMAGE": "Zmień", - "ACTION_USE_GRAVATAR": "Use default image", + "ACTION_USE_GRAVATAR": "Użyj domyślnego obrazu", "ACTION_DELETE_ACCOUNT": "Usuń konto Taiga", "CHANGE_EMAIL_SUCCESS": "Sprawdź swoją skrzynkę e-mail!
Wysłaliśmy wiadomość z instrukcjami.", "CHANGE_PHOTO": "Zmień zdjęcie", @@ -1517,25 +1479,10 @@ "THEME_DEFAULT": "-- używaj domyślnego szablonu --" } }, - "WIZARD": { - "SECTION_TITLE_CREATE_PROJECT": "Utwórz projekt", - "CREATE_PROJECT_TEXT": "Nowy, zwinny! To takie ekscytujące!", - "CHOOSE_TEMPLATE": "Which template fits your project best?", - "CHOOSE_TEMPLATE_TITLE": "More info about project templates", - "CHOOSE_TEMPLATE_INFO": "More info", - "PROJECT_DETAILS": "Project Details", - "PUBLIC_PROJECT": "Public Project", - "PRIVATE_PROJECT": "Private Project", - "CREATE_PROJECT": "Utwórz projekt", - "MAX_PRIVATE_PROJECTS": "Osiągnąłeś maksymalną liczbę prywatnych projektów", - "MAX_PUBLIC_PROJECTS": "Niestety osiągnąłeś maksymalną liczbę publicznych projektów", - "CHANGE_PLANS": "change plans" - }, "WIKI": { "PAGE_TITLE": "{{wikiPageName}} - Wiki - {{projectName}}", "PAGE_DESCRIPTION": "Ostatnio edytowane dnia {{lastModifiedDate}} ({{totalEditions}} edycji łącznie) Zawartość: {{ wikiPageContent }}", "DATETIME": "DD MMM YYYY HH:mm", - "PLACEHOLDER_PAGE": "Napisz swoje Wiki", "REMOVE": "Usuń tą stronę Wiki", "DELETE_LIGHTBOX_TITLE": "Usuń tą stronę Wiki", "DELETE_LINK_TITLE": "Usuń link Wiki", @@ -1543,16 +1490,16 @@ "HOME": "Strona Główna", "SECTION_NAME": "ZAKŁADKI", "ACTION_ADD_LINK": "Dodaj zakładkę", - "ALL_PAGES": "All wiki pages" + "ALL_PAGES": "Wszystkie strony Wiki" }, "SUMMARY": { "TIMES_EDITED": "razy
edytowano", "LAST_EDIT": "ostatnia
edycja", "LAST_MODIFICATION": "ostatnia modyfikacja" }, - "SECTION_PAGES_LIST": "All pages", + "SECTION_PAGES_LIST": "Wszystkie strony", "PAGES_LIST_COLUMNS": { - "TITLE": "Title", + "TITLE": "Tytuł", "EDITIONS": "Editions", "CREATED": "Utworzone", "MODIFIED": "Modified", @@ -1645,7 +1592,7 @@ "STEP4": { "TITLE": "Zaczynajmy", "TEXT1": "Możesz zacząć od stworzenia swojego pierwszego projektu w Taiga.", - "TEXT2": "Good luck!" + "TEXT2": "Powodzenia!" } }, "BACKLOG": { @@ -1679,7 +1626,7 @@ "STEP3": { "TITLE": "Dodawanie Historyjek Użytkownika", "TEXT1": "You may want to add a single User Story (add US icon) or a group of them (bulk icon)", - "TEXT2": "Good luck!" + "TEXT2": "Powodzenia!" } } }, @@ -1690,10 +1637,9 @@ "DISCOVER_SUBTITLE": "{projects, plural, one{One public project to discover} other{# public projects to discover}}", "MOST_ACTIVE": "Most active", "MOST_ACTIVE_EMPTY": "There are no ACTIVE projects yet", - "MOST_LIKED": "Most liked", + "MOST_LIKED": "Najbardziej lubiane", "MOST_LIKED_EMPTY": "There are no LIKED projects yet", "VIEW_MORE": "View more", - "RECRUITING": "Ten projekt szuka ludzi", "FEATURED": "Featured Projects", "EMPTY": "There are no projects to show with this search criteria.
Try again!", "FILTERS": { @@ -1702,8 +1648,8 @@ "SCRUM": "Scrum", "PEOPLE": "Looking for people", "WEEK": "Last week", - "MONTH": "Last month", - "YEAR": "Last year", + "MONTH": "Ostatni miesiąc", + "YEAR": "Ostatni rok", "ALL_TIME": "All time", "CLEAR": "Clear filters" }, diff --git a/app/locales/taiga/locale-pt-br.json b/app/locales/taiga/locale-pt-br.json index 20f236ce..8ca127a1 100644 --- a/app/locales/taiga/locale-pt-br.json +++ b/app/locales/taiga/locale-pt-br.json @@ -4,14 +4,13 @@ "NO": "Não", "OR": "ou", "LOADING": "Carregando...", - "LOADING_PROJECT": "Carregando o projeto...", "DATE": "DD MMM YYYY", "DATETIME": "DD MMM YYYY HH:mm", "SAVE": "Salvar", "CANCEL": "Cancelar", "ACCEPT": "Aceitar", "DELETE": "Apagar", - "UNLINK": "Unlink", + "UNLINK": "Separar", "CREATE": "Criar", "ADD": "Adicionar", "COPY_TO_CLIPBOARD": "Copiar para a área de transferência: Ctrl+C", @@ -27,12 +26,9 @@ "BLOCKED_NOTE": "Por que esta bloqueado?", "BLOCKED_REASON": "Por favor, explique a razão", "CREATED_BY": "Criado por {{fullDisplayName}}", - "FROM": "de", - "TO": "para", "CLOSE": "fechar", "GO_HOME": "Ir ao início", "PLUGINS": "Plugins", - "BETA": "Estamos em beta!", "ONE_ITEM_LINE": "Um item por linha...", "NEW_BULK": "Nova inserção em lote", "RELATED_TASKS": "Tarefas relacionadas", @@ -41,17 +37,17 @@ "LOGOUT": "Sair", "EXTERNAL_USER": "um usuário externo", "GENERIC_ERROR": "Um Oompa Loompas disse {{error}}.", - "IOCAINE_TEXT": "Se sentindo sobrecarregado por uma tarefa? Assegure-se de que os outros saibam disso clicando em Iocaine quando estiver editando a tarefa. É possível se tornar imune a essse veneno mortal (fictício) consumindo pequenas quantidades ao longo do tempo, assim como é possível ficar melhor no que faz, ocasionalmente, por assumir desafios extras!", + "IOCAINE_TEXT": "This member is feeling a bit overwhelmed by this task. Will become immune to the iocaine poison over time with your help. For now, may need a hug.", "CLIENT_REQUIREMENT": "Requisito de cliente é um novo requisito que não foi anteriormente previsto e que necessita se tornar uma parte do projeto.", "TEAM_REQUIREMENT": "Requisito de time é um requisito que deve existir no projeto, mas que não deve ter nenhum custo para o cliente.", "OWNER": "Dono do Projeto", "CAPSLOCK_WARNING": "Seja cuidadoso! Você está escrevendo em letras maiúsculas e esse campo é case sensitive, ou seja, trata com distinção as letras maiúsculas das minúsculas.", "CONFIRM_CLOSE_EDIT_MODE_TITLE": "Você tem certeza que quer fechar o modo de edição?", "CONFIRM_CLOSE_EDIT_MODE_MESSAGE": "Lembre-se que se você fechar o modo de edição sem salvar, todas as mudanças serão perdidas", - "RELATED_USERSTORIES": "Related user stories", + "RELATED_USERSTORIES": "Histórias de usuário relacionadas", "CARD": { - "ASSIGN_TO": "Assign To", - "EDIT": "Edit card" + "ASSIGN_TO": "Atribuir a", + "EDIT": "Editar cartão" }, "FORM_ERRORS": { "DEFAULT_MESSAGE": "Este valor parece ser inválido.", @@ -125,7 +121,7 @@ "ISSUE": "Problema", "EPIC": "Épico", "TAGS": { - "PLACEHOLDER": "Enter tag", + "PLACEHOLDER": "Inserir tag", "DELETE": "Apagar tag", "ADD": "Adicionar tag" }, @@ -148,7 +144,6 @@ "PRIORITY": "Prioridade", "ASSIGNED_TO": "Atribuído a", "POINTS": "Pontos", - "BLOCKED_NOTE": "Nota de bloqueio", "IS_BLOCKED": "está bloqueada", "REF": "Ref", "VOTES": "Votos", @@ -187,10 +182,6 @@ "COUNTER_TITLE": "{total, plural, one{um observador} other{#watchers}}" }, "VOTE_BUTTON": { - "UPVOTE": "Aprovar", - "UPVOTED": "Aprovado", - "DOWNVOTE": "Reprovar", - "VOTERS": "Eleitores", "BUTTON_TITLE": "Aprovar/Reprovar este item", "COUNTER_TITLE": "{total, plural, one{um voto} other{# votos}}" }, @@ -199,17 +190,16 @@ "SAVE": "Salvar Campo Personalizado", "EDIT": "Editar Campo Personalizado", "DELETE": "Apagar atributo personalizado", - "CONFIRM_DELETE": "Remeber that all values in this custom field will be deleted.\n Are you sure you want to continue?" + "CONFIRM_DELETE": "Lembre-se que todos os valores neste campo customizado serão deletados.\nVocê tem certeza que quer continuar?" }, "FILTERS": { - "TITLE": "Filtros", "INPUT_PLACEHOLDER": "Assunto ou referência", "TITLE_ACTION_FILTER_BUTTON": "procurar", - "INPUT_SEARCH_PLACEHOLDER": "Assunto ou ref", + "TITLE": "Filtros", "TITLE_ACTION_SEARCH": "Procurar", "ACTION_SAVE_CUSTOM_FILTER": "salve como filtro personalizado", "PLACEHOLDER_FILTER_NAME": "Digite o nome do filtro e pressione Enter", - "APPLIED_FILTERS_NUM": "filters applied", + "APPLIED_FILTERS_NUM": "filtros aplicados", "CATEGORIES": { "TYPE": "Tipo", "STATUS": "Status", @@ -220,51 +210,20 @@ "CREATED_BY": "Criado por", "CUSTOM_FILTERS": "Filtros personalizados", "EPIC": "Épico" - }, - "CONFIRM_DELETE": { - "TITLE": "Apagar filtro personalizado", - "MESSAGE": "O filtro personalizado '{{customFilterName}}'" } }, "WYSIWYG": { - "H1_BUTTON": "Primeira caixa de cabeçalho", - "H1_SAMPLE_TEXT": "Seu título aqui...", - "H2_BUTTON": "Segundo caixa de cabeçalho", - "H2_SAMPLE_TEXT": "Seu título aqui...", - "H3_BUTTON": "Terceira caixa de cabeçalho", - "H3_SAMPLE_TEXT": "Seu título aqui...", - "BOLD_BUTTON": "Negrito", - "BOLD_BUTTON_SAMPLE_TEXT": "Seu texto aqui...", - "ITALIC_BUTTON": "Itálico", - "ITALIC_SAMPLE_TEXT": "Seu texto aqui...", - "STRIKE_BUTTON": "Riscar", - "STRIKE_SAMPLE_TEXT": "Seu texto aqui...", - "BULLETED_LIST_BUTTON": "Lista de marcadores", - "BULLETED_LIST_SAMPLE_TEXT": "Seu texto aqui...", - "NUMERIC_LIST_BUTTON": "Lista numérica", - "NUMERIC_LIST_SAMPLE_TEXT": "Seu texto aqui...", - "PICTURE_BUTTON": "Imagem", - "PICTURE_SAMPLE_TEXT": "Seu texto alternativo para a imagem aqui...", - "LINK_BUTTON": "Link", - "LINK_SAMPLE_TEXT": "Seu texto para o link vai aqui...", - "QUOTE_BLOCK_BUTTON": "Bloco de citação", - "QUOTE_BLOCK_SAMPLE_TEXT": "Seu texto aqui...", - "CODE_BLOCK_BUTTON": "Bloco de código", - "CODE_BLOCK_SAMPLE_TEXT": "Seu texto aqui...", - "PREVIEW_BUTTON": "Pré Visualizar", - "EDIT_BUTTON": "Editar", - "ATTACH_FILE_HELP": "Anexe arquivos arrastando e soltando na área de texto acima.", - "ATTACH_FILE_HELP_SAVE_FIRST": "Save first before if you want to attach files by dragging & dropping on the textarea above.", + "OUTDATED": "Another person has made changes while you were editing. Check the new version on the activiy tab before you save your changes.", "MARKDOWN_HELP": "Ajuda de sintaxe markdown" }, "PERMISIONS_CATEGORIES": { "EPICS": { "NAME": "Épicos", - "VIEW_EPICS": "View epics", - "ADD_EPICS": "Add epics", - "MODIFY_EPICS": "Modify epics", - "COMMENT_EPICS": "Comment epics", - "DELETE_EPICS": "Delete epics" + "VIEW_EPICS": "Ver épicos", + "ADD_EPICS": "Adicionar épicos", + "MODIFY_EPICS": "Modificar épicos", + "COMMENT_EPICS": "Comentar épicos", + "DELETE_EPICS": "Deletar épicos" }, "SPRINTS": { "NAME": "Sprints", @@ -286,7 +245,7 @@ "VIEW_TASKS": "Ver tarefas", "ADD_TASKS": "Adicionar uma nova Tarefa", "MODIFY_TASKS": "Modificar tarefa", - "COMMENT_TASKS": "Comment tasks", + "COMMENT_TASKS": "Comentar tarefas", "DELETE_TASKS": "Apagar tarefas" }, "ISSUES": { @@ -294,7 +253,7 @@ "VIEW_ISSUES": "Ver problemas", "ADD_ISSUES": "Adicionar problemas", "MODIFY_ISSUES": "Modificar problemas", - "COMMENT_ISSUES": "Comment issues", + "COMMENT_ISSUES": "Comentar problemas", "DELETE_ISSUES": "Apagar problemas" }, "WIKI": { @@ -307,10 +266,6 @@ "ADD_WIKI_LINKS": "Adicionar links da wiki", "DELETE_WIKI_LINKS": "Apagar links da wiki" } - }, - "META": { - "PAGE_TITLE": "Taiga", - "PAGE_DESCRIPTION": "Taiga é uma plataforma de gerenciamento de projetos para startups e desenvolvedores ágeis & designers que querem uma simples, bela ferramenta que faça o trabalho ser agradável." } }, "LOGIN": { @@ -366,7 +321,6 @@ }, "CHANGE_PASSWORD": { "PAGE_TITLE": "Alterar sua senha - Taiga", - "PAGE_DESCRIPTION": "Escolher nova senha para o seu Taiga e hey!, você deveria comer comida rica em ferro, é ótimo para o cérebro :P", "SECTION_NAME": "Alterar senha", "FIELD_CURRENT_PASSWORD": "Senha atual", "PLACEHOLDER_CURRENT_PASSWORD": "Sua senha atual (ou vazio caso ainda não tenha uma senha)", @@ -391,8 +345,7 @@ }, "INVITATION_LOGIN_FORM": { "NOT_FOUND": "Nossos Oompa Loompas não puderam encontrar seu convite.", - "SUCCESS": "Você ingressou com sucesso nesse projeto, Seja bem vindo ao projeto {{project_name}}", - "ERROR": "De acordo com nossos Oompa Loompas, você não está inscrito ou digitou uma senha inválida." + "SUCCESS": "Você ingressou com sucesso nesse projeto, Seja bem vindo ao projeto {{project_name}}" }, "HOME": { "PAGE_TITLE": "Início - Taiga", @@ -408,15 +361,15 @@ "TITLE": "ÉPICOS", "SECTION_NAME": "Épicos", "EPIC": "ÉPICO", - "PAGE_TITLE": "Epics - {{projectName}}", - "PAGE_DESCRIPTION": "The epics list of the project {{projectName}}: {{projectDescription}}", + "PAGE_TITLE": "Épico - {{projectName}}", + "PAGE_DESCRIPTION": "A lista de épicos do projeto {{projectName}}: {{projectDescription}}", "DASHBOARD": { "ADD": "+ ADICIONAR ÉPICO", "UNASSIGNED": "Não-atribuído" }, "EMPTY": { - "TITLE": "It looks like there aren't any epics yet", - "EXPLANATION": "Epics are items at a higher level that encompass user stories.
Epics are at the top of the hierarchy and can be used to group user stories together.", + "TITLE": "Parece que não há nenhum épico ainda", + "EXPLANATION": "Épicos são itens em um nível mais alto que contêm histórias de usuário.
Épicos são o topo da hierarquia e podem ser usados para agrupar histórias.", "HELP": "Saiba mais sobre épicos" }, "TABLE": { @@ -424,16 +377,16 @@ "NAME": "Nome", "PROJECT": "Projeto", "SPRINT": "Sprint", - "ASSIGNED_TO": "Assigned", + "ASSIGNED_TO": "Atribuído", "STATUS": "Status", "PROGRESS": "Progresso", "VIEW_OPTIONS": "Ver opções" }, "CREATE": { "TITLE": "Novo Épico", - "PLACEHOLDER_DESCRIPTION": "Please add descriptive text to help others better understand this epic", - "TEAM_REQUIREMENT": "Team requirement", - "CLIENT_REQUIREMENT": "Client requirement", + "PLACEHOLDER_DESCRIPTION": "Por favor, adicione um texto descritivo para ajudar outras pessoas a entenderem melhor este épico", + "TEAM_REQUIREMENT": "Requisitos da equipe", + "CLIENT_REQUIREMENT": "Requisitos do cliente", "BLOCKED": "Bloqueado", "BLOCKED_NOTE_PLACEHOLDER": "Por que esse épico está bloqueado?", "CREATE_EPIC": "Criar épico" @@ -463,10 +416,7 @@ "TITLE_LIGHTBOX_DELETE_ATTACHMENT": "Apagar anexo...", "MSG_LIGHTBOX_DELETE_ATTACHMENT": "o anexo '{{fileName}}'", "ERROR_DELETE_ATTACHMENT": "Não fomos capazes de apagar: {{errorMessage}}", - "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) é muito pesado para nossos Oompa Loompas, tente algo menor que ({{maxFileSize}})", - "FIELDS": { - "IS_DEPRECATED": "está obsoleto" - } + "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) é muito pesado para nossos Oompa Loompas, tente algo menor que ({{maxFileSize}})" }, "PAGINATION": { "PREVIOUS": "Anterior", @@ -502,15 +452,12 @@ "ASYNC_MESSAGE": "Enviaremos um email para você assim que estiver pronto.", "SYNC_MESSAGE": "Se o download não iniciar automáticamente clique aqui", "ERROR": "Nossos Oompa Loopmas tiveram alguns problemas gerando o dump. Por favor, tente novamente.", - "ERROR_BUSY": "Desculpe, nossos Oompa Loompas estão muito ocupados neste instante. Tente novamente em alguns minutos.", - "ERROR_MESSAGE": "Nossos Oompa Loompas tiveram alguns problemas gerando o seu dump: {{message}}" + "ERROR_BUSY": "Desculpe, nossos Oompa Loompas estão muito ocupados neste instante. Tente novamente em alguns minutos." }, "MODULES": { "TITLE": "Modulos", - "ENABLE": "Habilitar", - "DISABLE": "Desabilitar", "EPICS": "Épicos", - "EPICS_DESCRIPTION": "Visualize and manage the most strategic part of your project", + "EPICS_DESCRIPTION": "Visualize e gerencie a parte mais estratégica do seu projeto", "BACKLOG": "Backlog", "BACKLOG_DESCRIPTION": "Gerencie suas histórias de usuários para manter uma visualização organizada de trabalhos futuros e priorizados.", "NUMBER_SPRINTS": "Número de sprints esperadas", @@ -537,17 +484,16 @@ "PAGE_TITLE": "{{sectionName}} - Perfil do projeto - {{projectName}}", "PROJECT_DETAILS": "Detalhes do projeto", "PROJECT_NAME": "Nome do projeto", - "PROJECT_SLUG": "Slug do projeto", "TAGS": "Tags", "DESCRIPTION": "Descrição", "RECRUITING": "Este projeto esta a procura de colaboradores?", "RECRUITING_MESSAGE": "O que você está procurando?", "RECRUITING_PLACEHOLDER": "Defina o perfil que você procura?", + "FEEDBACK": "Receive feedback from Taiga users?", "PUBLIC_PROJECT": "Projeto Publico", "PRIVATE_PROJECT": "Projeto Privado", "PRIVATE_OR_PUBLIC": "Qual a diferença entre projeto público e privado?", "DELETE": "Apagar este projeto", - "LOGO_HELP": "A imagem deve ser na escala de 80x80px.", "CHANGE_LOGO": "Alterar logo", "ACTION_USE_DEFAULT_LOGO": "Usar imagem padrão", "MAX_PRIVATE_PROJECTS": "Você atingiu o número máximo de projetos privados permitidos para seu plano atual.", @@ -562,7 +508,7 @@ "REQUEST_OWNERSHIP_SUCCESS": "Vamos notificar o dono do projeto", "CHANGE_OWNER": "Mudar dono", "CHANGE_OWNER_SUCCESS_TITLE": "Ok, sua requisição foi enviada!", - "CHANGE_OWNER_SUCCESS_DESC": "We will notify you by email if the project ownership request is accepted or declined" + "CHANGE_OWNER_SUCCESS_DESC": "Nós notificaremos você por email se a requisição de propriedade do projeto for aceita ou recusada" }, "REPORTS": { "TITLE": "Relatórios", @@ -573,7 +519,7 @@ "REGENERATE_SUBTITLE": "Você está prestes a alterar a url de acesso a dados do CSV. A URL anterior será desabilitada. Você está certo disso?" }, "CSV": { - "SECTION_TITLE_EPIC": "epics reports", + "SECTION_TITLE_EPIC": "relatórios de épicos", "SECTION_TITLE_US": "Relatórios de histórias de usuários", "SECTION_TITLE_TASK": "relatórios de tarefas", "SECTION_TITLE_ISSUE": "relatórios de problemas", @@ -586,8 +532,8 @@ "CUSTOM_FIELDS": { "TITLE": "Campos Personalizados", "SUBTITLE": "Especificar campos personalizados para histórias de usuários, tarefas e problemas", - "EPIC_DESCRIPTION": "Epics custom fields", - "EPIC_ADD": "Add a custom field in epics", + "EPIC_DESCRIPTION": "Campos personalizados dos épicos", + "EPIC_ADD": "Adicionar campos personalizados em épicos", "US_DESCRIPTION": "Campos personalizados das histórias de usuários", "US_ADD": "Adicionar campo personalizado nas histórias de usuários", "TASK_DESCRIPTION": "Campos personalizados das Tarefas", @@ -595,6 +541,7 @@ "ISSUE_DESCRIPTION": "Campos personalizados dos problemas", "ISSUE_ADD": "Adicionar um campo personalizado em problemas ", "FIELD_TYPE_TEXT": "Texto", + "FIELD_TYPE_RICHTEXT": "Rich text", "FIELD_TYPE_MULTI": "Multi-linha", "FIELD_TYPE_DATE": "Data", "FIELD_TYPE_URL": "Url" @@ -623,10 +570,10 @@ "ACTION_ADD": "Adicionar nova gravidade" }, "PROJECT_VALUES_STATUS": { - "TITLE": "Status", + "TITLE": "Statuses", "SUBTITLE": "Especifique os status pelos quais suas histórias de usuários, tarefas e problemas passarão", - "EPIC_TITLE": "Epic Statuses", - "US_TITLE": "User Story Statuses", + "EPIC_TITLE": "Estados do Épico", + "US_TITLE": "Status de história de usuário", "TASK_TITLE": "Estados da Tarefa", "ISSUE_TITLE": "Estados do problema" }, @@ -638,7 +585,7 @@ }, "PROJECT_VALUES_TAGS": { "TITLE": "Tags", - "SUBTITLE": "View and edit the color of your tags", + "SUBTITLE": "Ver e editar as cores das suas tags", "EMPTY": "Atualmente não há tags", "EMPTY_SEARCH": "Parece que nada foi encontrado com os critérios de sua pesquisa.", "ACTION_ADD": "Adicionar tag", @@ -676,8 +623,8 @@ "INFO_VERIFYING_IP": "Requisições do Gitlab não são assinadas, ou seja, a melhor maneira de verificar a origem é por IP. Se o campo estiver vazio não será realizada verificação de IP." }, "GITHUB": { - "SECTION_NAME": "Github", - "PAGE_TITLE": "Github - {{projectName}}" + "SECTION_NAME": "GitHub", + "PAGE_TITLE": "GitHub - {{projectName}}" }, "GOGS": { "SECTION_NAME": "Gogs", @@ -686,7 +633,6 @@ "WEBHOOKS": { "PAGE_TITLE": "Webhooks - {{projectName}}", "SECTION_NAME": "Webhooks", - "SUBTITLE": "Webhooks notificam serviços externos sobre eventos no Taiga, como comentários, histórias de usuários...", "ADD_NEW": "Adicionar um Novo Webhook", "TYPE_NAME": "Digite o nome do serviço", "TYPE_PAYLOAD_URL": "Digite a url do serviço Payload", @@ -732,14 +678,13 @@ "DELETE_MEMBER": "Apagar membro", "RESEND": "Reenviar", "SUCCESS_SEND_INVITATION": "Enviamos novamente um convite para '{{email}}'.", - "ERROR_SEND_INVITATION": "Nós não enviamos o convite.", "SUCCESS_DELETE": "Nós apagamos {{message}}.", "ERROR_DELETE": "Nós não fomos capaz de apagar {{message}}.", "DEFAULT_DELETE_MESSAGE": "o convite para {{email}}" }, "DEFAULT_VALUES": { - "LABEL_EPIC_STATUS": "Default value for epic status selector", - "LABEL_US_STATUS": "Default value for user story status selector", + "LABEL_EPIC_STATUS": "Valor padrão para seletor de status de épico", + "LABEL_US_STATUS": "Valor padrão para seletor de status da história de usuário", "LABEL_POINTS": "Valores padrões para o seletor de pontos", "LABEL_TASK_STATUS": "Valor padrão para seletor de status de tarefa", "LABEL_ISSUE_TYPE": "Valor padrão para seletor de tipo de problema ", @@ -761,16 +706,11 @@ "PLACEHOLDER_WRITE_NAME": "Digite um nome para o novo status" }, "MENU": { - "TITLE": "Administrador", "PROJECT": "Projeto", "ATTRIBUTES": "Atributos", "MEMBERS": "Membros", "PERMISSIONS": "Permissões", - "INTEGRATIONS": "Integrações", - "PLUGINS": "Plugins" - }, - "SUBMENU_PROJECT_ATTRIBUTES": { - "TITLE": "Atributos" + "INTEGRATIONS": "Integrações" }, "SUBMENU_PROJECT_VALUES": { "STATUS": "Status", @@ -781,17 +721,11 @@ "CUSTOM_FIELDS": "Campos personalizados", "TAGS": "Tags" }, - "SUBMENU_PROJECT_PROFILE": { - "TITLE": "Perfil do Projeto" - }, "SUBMENU_ROLES": { "TITLE": "Funções", "ACTION_NEW_ROLE": "+ Nova Função", "TITLE_ACTION_NEW_ROLE": "Adicionar nova função" }, - "SUBMENU_THIDPARTIES": { - "TITLE": "Serviços" - }, "PROJECT_TRANSFER": { "DO_YOU_ACCEPT_PROJECT_OWNERNSHIP": "Você gostaria de se tornar o novo dono do projeto?", "PRIVATE": "Privado", @@ -799,22 +733,20 @@ "REJECTED_PROJECT_OWNERNSHIP": "OK. Entraremos em contato com o atual dono do projeto.", "ACCEPT": "Aceitar", "REJECT": "Rejeitar", - "PROPOSE_OWNERSHIP": "{{owner}}, the current owner of the project {{project}} has asked that you become the new project owner.", - "ADD_COMMENT": "Would you like to add a comment for the project owner?", + "PROPOSE_OWNERSHIP": "{{owner}}, o atual dono do projeto {{project}} te pediu para ser o novo dono do projeto.", + "ADD_COMMENT": "Você gostaria de adicionar um comentário para o dono do projeto?", "UNLIMITED_PROJECTS": "Ilimitado", "OWNER_MESSAGE": { - "PRIVATE": "Please remember that you can own up to {{maxProjects}} private projects. You currently own {{currentProjects}} private projects", - "PUBLIC": "Please remember that you can own up to {{maxProjects}} public projects. You currently own {{currentProjects}} public projects" + "PRIVATE": "Por favor, lembre-se que você pode ser dono de até {{maxProjects}} projetos privados. Você, atualmente, é dono de {{currentProjects}} projetos privados", + "PUBLIC": "Por favor, lembre-se que você pode ser dono de até {{maxProjects}} projetos públicos. Você, atualmente, é dono de {{currentProjects}} projetos públicos" }, - "CANT_BE_OWNED": "At the moment you cannot become an owner of a project of this type. If you would like to become the owner of this project, please contact the administrator so they change your account settings to enable project ownership.", - "CHANGE_MY_PLAN": "Mudar meu plano" + "CANT_BE_OWNED": "No momento, você não pode se tornar dono de um projeto desse tipo. Se você quiser se tornar dono desse projeto, por favor, entre em contato com os administradores para mudarem as configurações da sua conta para habilitar a propriedade do projeto." } }, "USER": { "PROFILE": { "PAGE_TITLE": "{{userFullName}} (@{{userUsername}})", "EDIT": "Editar Perfil", - "FOLLOW": "Seguir", "CLOSED_US": "Histórias Fechadas", "PROJECTS": "Projetos", "PROJECTS_EMPTY": "{{username}} ainda não tem projetos", @@ -822,7 +754,6 @@ "CONTACTS_EMPTY": "{{username}} ainda não tem nenhum contato", "CURRENT_USER_CONTACTS_EMPTY": "Você não tem nenhum contato", "CURRENT_USER_CONTACTS_EMPTY_EXPLAIN": "As pessoas que trabalahm na Taiga serão seus contatos automaticamente", - "REPORT": "Reportar Abuso", "TABS": { "ACTIVITY_TAB": "Linha do Tempo", "ACTIVITY_TAB_TITLE": "Exibir todas as atividade deste usuário", @@ -848,13 +779,13 @@ "FILTER_TYPE_ALL": "Tudo", "FILTER_TYPE_ALL_TITLE": "Mostrar tudo", "FILTER_TYPE_PROJECTS": "Projetos", - "FILTER_TYPE_PROJECT_TITLES": "Mostrar somente projetos", + "FILTER_TYPE_PROJECTS_TITLE": "Mostrar somente projetos", "FILTER_TYPE_EPICS": "Épicos", - "FILTER_TYPE_EPIC_TITLES": "Show only epics", + "FILTER_TYPE_EPICS_TITLE": "Mostrar somente épicos", "FILTER_TYPE_USER_STORIES": "Histórias", - "FILTER_TYPE_USER_STORIES_TITLES": "Mostrar apenas histórias de usuários", + "FILTER_TYPE_USER_STORIES_TITLE": "Mostrar apenas histórias de usuários", "FILTER_TYPE_TASKS": "Tarefas", - "FILTER_TYPE_TASK_TITLES": "Mostrar apenas tarefas", + "FILTER_TYPE_TASKS_TITLE": "Mostrar apenas tarefas", "FILTER_TYPE_ISSUES": "Problemas", "FILTER_TYPE_ISSUES_TITLE": "mostrar apenas apontamentos", "EMPTY_TITLE": "Parece que não há nada para exibir aqui." @@ -862,8 +793,6 @@ }, "PROJECT": { "PAGE_TITLE": "{{projectName}}", - "WELCOME": "Bem vindo", - "SECTION_PROJECTS": "Projetos", "HELP": "Reordene seus projetos para colocar no topo os mais usados.
Os 10 primeiros projetos aparecerão na lista de projetos da barra de navegação superior.", "PRIVATE": "Projeto Privado", "LOOKING_FOR_PEOPLE": "Este projeto esta a procura de colaboradores", @@ -875,12 +804,6 @@ "THIS_PROJECT_IS_BLOCKED": "Este projeto está temporariamente bloqueado", "TO_UNBLOCK_CONTACT_THE_ADMIN_STAFF": "Para desbloquear seus projetos, contate o administrador." }, - "STATS": { - "PROJECT": "projetos
pontos", - "DEFINED": "pontos
definidos", - "ASSIGNED": "pontos
com designação", - "CLOSED": "pontos
fechados" - }, "SECTION": { "SEARCH": "Procurar", "TIMELINE": "Linha do Tempo", @@ -893,15 +816,9 @@ "ADMIN": "Administrador" }, "NAVIGATION": { - "SECTION_TITLE": "Seus projetos", - "PLACEHOLDER_SEARCH": "Procurar em...", "ACTION_CREATE_PROJECT": "Criar projeto", - "ACTION_IMPORT_PROJECT": "Importar projeto", "MANAGE_PROJECTS": "Gerenciar projetos", "TITLE_CREATE_PROJECT": "Criar projeto", - "TITLE_IMPORT_PROJECT": "Importar projeto", - "TITLE_PRVIOUS_PROJECT": "Mostrar projetos prévios", - "TITLE_NEXT_PROJECT": "Mostrar os próximos projetos", "HELP_TITLE": "Página de Suporte do Taiga", "HELP": "Ajuda", "HOMEPAGE": "Página pessoal", @@ -909,10 +826,6 @@ "FEEDBACK": "Feedback", "NOTIFICATIONS_TITLE": "Editar suas configurações de notificações", "NOTIFICATIONS": "Notificações", - "ORGANIZATIONS_TITLE": "Edite suas organizações", - "ORGANIZATIONS": "Editar organizações", - "SETTINGS_TITLE": "Editar suas configurações", - "SETTINGS": "Configurações", "VIEW_PROFILE_TITLE": "Ver perfil", "VIEW_PROFILE": "Ver perfil", "EDIT_PROFILE_TITLE": "Edit seu perfil", @@ -921,47 +834,7 @@ "CHANGE_PASSWORD": "Alterar senha", "DASHBOARD_TITLE": "Painel", "DISCOVER_TITLE": "Descobrir projetos em destaques", - "NEW_ITEM": "Novo", - "DISCOVER": "Descubra", - "ACTION_REORDER": "Seguro e arraste para ordenar" - }, - "IMPORT": { - "TITLE": "Importando Projeto", - "UPLOADING_FILE": "Enviando arquivo de dump", - "DESCRIPTION": "Este processo pode levar algum tempo, mantenha a janela aberta por favor.", - "ASYNC_IN_PROGRESS_TITLE": "Nossos Oompa Loompas estão importando seu projeto", - "ASYNC_IN_PROGRESS_MESSAGE": "Este processo pode levar alguns minutos
Enviaremos um email a você assim que estiver pronto", - "UPLOAD_IN_PROGRESS_MESSAGE": "Enviado {{uploadedSize}} de {{totalSize}}", - "ERROR": "Nossos Oompa Loompas tiveram alguns problemas importando os dados do seu dump. Tente novamente.", - "ERROR_TOO_MANY_REQUEST": "Desculpe, nossos Oompa Loompas estão muito ocupados neste instante. Tente novamente em alguns minutos.", - "ERROR_MESSAGE": "Nossos Oompa Loompas tiveram alguns problemas ao importar seu arquivo de despejo: {{error_message}}", - "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) é muito pesado para nossos Oompa Loompas, tente algo menor que ({{maxFileSize}})", - "SYNC_SUCCESS": "Seu projeto foi importado com sucesso", - "PROJECT_RESTRICTIONS": { - "PROJECT_MEMBERS_DESC": "O projeto que você está tentando importar tem {{members}} membros e infelizmente seu plano atual tem um limite máximo de {{max_memberships}} membros por projeto. Se você deseja aumentar este limite entre em contato com o administrador.", - "PRIVATE_PROJECTS_SPACE": { - "TITLE": "Unfortunately, your current plan does not allow for additional private projects", - "DESC": "The project you are trying to import is private. Unfortunately, your current plan does not allow for additional private projects." - }, - "PUBLIC_PROJECTS_SPACE": { - "TITLE": "Unfortunately, your current plan does not allow for additional public projects", - "DESC": "The project you are trying to import is public. Unfortunately, your current plan does not allow additional public projects." - }, - "PRIVATE_PROJECTS_MEMBERS": { - "TITLE": "Your current plan allows for a maximum of {{max_memberships}} members per private project" - }, - "PUBLIC_PROJECTS_MEMBERS": { - "TITLE": "Your current plan allows for a maximum of {{max_memberships}} members per public project." - }, - "PRIVATE_PROJECTS_SPACE_MEMBERS": { - "TITLE": "Unfortunately your current plan doesn't allow additional private projects or an increase of more than {{max_memberships}} members per private project", - "DESC": "O projeto que você está tentando importar é privado e tem {{members}} membros." - }, - "PUBLIC_PROJECTS_SPACE_MEMBERS": { - "TITLE": "Unfortunately your current plan doesn't allow additional public projects or an increase of more than {{max_memberships}} members per public project", - "DESC": "The project that you are trying to import is public and has more than {{members}} members." - } - } + "DISCOVER": "Descubra" }, "LIKE_BUTTON": { "LIKE": "Curtir", @@ -983,17 +856,160 @@ "UNWATCH": "Deixar de Observar", "UNWATCH_TITLE": "Deixar de observar este projeto" } + }, + "CONTACT_BUTTON": { + "CONTACT_TITLE": "Contact the project team", + "CONTACT_BUTTON": "Contact the project" + }, + "CREATE": { + "TITLE": "Criar Projeto", + "CHOOSE_TEMPLATE": "Which template fits your project better?", + "TEMPLATE_SCRUM": "Scrum", + "TEMPLATE_SCRUM_DESC": "Prioritize and solve your tasks in short time cycles.", + "TEMPLATE_SCRUM_LONGDESC": "Scrum is an iterative and incremental agile software development methodology for managing product development.\nThe product backlog is what will ultimately be delivered, ordered into the sequence in which it should be delivered. Product Backlogs are broken into manageable, executable chunks named sprints. Every certain amount of time the team initiates a new sprint and commits to deliver a certain number of user stories from the backlog, in accordance with their skills, abilities and resources. The project advances as the backlog becomes depleted.", + "TEMPLATE_KANBAN": "Kanban", + "TEMPLATE_KANBAN_DESC": "Keep a constant workflow on independent tasks", + "TEMPLATE_KANBAN_LONGDESC": "The Kanban methodology is used to divide project development (any sort of project) into stages.\nA kanban card is like an index card or post-it note that details every task (or user story) in a project that needs to be completed. The Kanban board is used to move each card from one state of completion to the next and in so doing, helps track progress.", + "DUPLICATE": "Duplicate project", + "DUPLICATE_DESC": "Start clean and keep your configuration", + "IMPORT": "Importar projeto", + "IMPORT_DESC": "Import your project from multiple platforms into Taiga", + "INVITE": "Invite to the project", + "SOLO_PROJECT": "You'll be alone in this project", + "INVITE_LATER": "(You'll be able to invite more members later)", + "BACK": "Back", + "MAX_PRIVATE_PROJECTS": "Unfortunately, You've reached the maximum number of private projects.\nIf you would like to increase the current limit please contact the administrator.", + "MAX_PUBLIC_PROJECTS": "Unfortunately, You've reached the maximum number of public projects.\nIf you would like to increase the current limit please contact the administrator.", + "PUBLIC_PROJECT": "Projeto Público", + "PRIVATE_PROJECT": "Projeto Privado" + }, + "COMMON": { + "DETAILS": "New project details", + "PROJECT_TITLE": "Project Name", + "PROJECT_DESCRIPTION": "Project Description" + }, + "DUPLICATE": { + "TITLE": "Duplicate Project", + "DESCRIPTION": "Start clean and keep your configuration", + "SELECT_PLACEHOLDER": "Choose an existing project to duplicate" + }, + "IMPORT": { + "TITLE": "Import Project", + "DESCRIPTION": "Import your project from multiple platforms into Taiga", + "ASYNC_IN_PROGRESS_TITLE": "Nossos Oompa Loompas estão importando seu projeto", + "ASYNC_IN_PROGRESS_MESSAGE": "Este processo pode levar alguns minutos
Enviaremos um email a você assim que estiver pronto", + "UPLOAD_IN_PROGRESS_MESSAGE": "Enviado {{uploadedSize}} de {{totalSize}}", + "ERROR": "Nossos Oompa Loompas tiveram alguns problemas importando os dados do seu dump. Tente novamente.", + "ERROR_TOO_MANY_REQUEST": "Desculpe, nossos Oompa Loompas estão muito ocupados neste instante. Tente novamente em alguns minutos.", + "ERROR_MESSAGE": "Nossos Oompa Loompas tiveram alguns problemas ao importar seu arquivo de despejo: {{error_message}}", + "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) é muito pesado para nossos Oompa Loompas, tente algo menor que ({{maxFileSize}})", + "SYNC_SUCCESS": "Seu projeto foi importado com sucesso", + "IMPORT": "Import", + "WHO_IS": "Their tasks will be assigned to ...", + "WRITE_EMAIL": "Or if you want, write the email that this user uses in Taiga", + "SEARCH_CONTACT": "Or if you want, search in your contacts", + "WRITE_EMAIL_LABEL": "Write the email that this user uses in Taiga", + "ACCEEDE": "Acceede", + "PROJECT_MEMBERS": "Membros do Projeto", + "PROCESS_DESCRIPTION": "Tell us who from Taiga you want to assign the tasks of {{platform}}", + "MATCH": "Is {{user_external}} the same person as {{user_internal}}?", + "CHOOSE": "Select user", + "LINKS": "Links with {{platform}}", + "LINKS_DESCRIPTION": "Do you want to keep the link of each item with the original {{platform}} card?", + "WARNING_MAIL_USER": "Note that if the user does not have a Taiga account we will not be able to assign the tasks to him.", + "ASSIGN": "Atribuir", + "PROJECT_SELECTOR": { + "NO_RESULTS": "Parece que nada foi encontrado com os critérios de sua pesquisa.", + "ACTION_SEARCH": "procurar", + "ACTION_BACK": "Back" + }, + "PROJECT_RESTRICTIONS": { + "PROJECT_MEMBERS_DESC_PRIVATE": "The project you are trying to import has {{members}} members including you, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per private project. If you would like to increase that limit please contact the administrator.", + "PROJECT_MEMBERS_DESC_PUBLIC": "The project you are trying to import has {{members}} members including you, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per public project. If you would like to increase that limit please contact the administrator.", + "ACCOUNT_ALLOW_MEMBERS": "Your account only allows {{members}} members", + "PRIVATE_PROJECTS_SPACE": { + "TITLE": "Infelizmente, seu plano atual não permite projetos privados adicionais.", + "DESC": "O projeto que você está tentando importar é privado. Infelizmente, seu plano plano atual não permite projetos privados adicionais." + }, + "PUBLIC_PROJECTS_SPACE": { + "TITLE": "Infelizmente, seu plano atual não permite projetos públicos adicionais.", + "DESC": "O projeto que você está tentando importar é público. Infelizmente, seu plano plano atual não permite projetos públicos adicionais." + }, + "PRIVATE_PROJECTS_MEMBERS": { + "TITLE": "Seu plano atual permite um máximo de {{max_memberships}} membros por projeto privado" + }, + "PUBLIC_PROJECTS_MEMBERS": { + "TITLE": "Seu plano atual permite um máximo de {{max_memberships}} membros por projeto público." + }, + "PRIVATE_PROJECTS_SPACE_MEMBERS": { + "TITLE": "Infelizmente, seu plano atual não permite projetos privados adicionais ou um aumento de mais de {{max_memberships}} membros por projeto privado.", + "DESC": "O projeto que você está tentando importar é privado e tem {{members}} membros." + }, + "PUBLIC_PROJECTS_SPACE_MEMBERS": { + "TITLE": "Infelizmente, seu plano atual não permite projetos públicos adicionais ou um aumento de mais de {{max_memberships}} membros por projeto público.", + "DESC": "O projeto que você está tentando importar é público e tem mais que {{members}} membros." + } + }, + "IN_PROGRESS": { + "TITLE": "Importando Projeto", + "DESCRIPTION": "Este processo pode levar algum tempo, mantenha a janela aberta por favor." + }, + "WARNING": { + "TITLE": "Some taks will be unassigned", + "DESCRIPTION": "There are still unidentified people. The cards assigned to these people will remain unassigned. Check all the contacts to not lose that information.", + "CHECK": "Check contacts" + }, + "TAIGA": { + "SELECTOR": "Import your Taiga project" + }, + "TRELLO": { + "SELECTOR": "Import your Trello boards into Taiga", + "CHOOSE_PROJECT": "Choose board that you want to import", + "NO_PROJECTS": "It seems you have no boards in Trello" + }, + "GITHUB": { + "SELECTOR": "Import your GitHub project issues", + "CHOOSE_PROJECT": "Find the project you want to import", + "NO_PROJECTS": "It seems you have no porjects in GitHub", + "HOW_DO_YOU_WANT_TO_IMPORT": "How do you want to import your issues into Taiga?", + "KANBAN_PROJECT": "As user stories in a kanban project", + "KANBAN_PROJECT_DESCRIPTION": "After that you can enable scrum with backlog.", + "SCRUM_PROJECT": "As user stories in a scrum project", + "SCRUM_PROJECT_DESCRIPTION": "After that you can enable kanban mode.", + "ISSUES_PROJECT": "As issues", + "ISSUES_PROJECT_DESCRIPTION": "You will not be able to use your issues in kanban or scrum mode. You will be able to enable kanban or scrum for new user stories" + }, + "ASANA": { + "SELECTOR": "Import your Asana project and choose how to manage it", + "CHOOSE_PROJECT": "Choose project that you want to import", + "NO_PROJECTS": "It seems you have no porjects in Asana", + "KANBAN_PROJECT": "Kanban", + "SCRUM_PROJECT": "Scrum", + "CREATE_AS_SCRUM_DESCRIPTION": "The tasks and sub-tasks of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_KANBAN_DESCRIPTION": "The tasks and sub-tasks of your project will be created as Taiga user stories and tasks." + }, + "JIRA": { + "SELECTOR": "Import your Jira project and choose how to manage it", + "CHOOSE_PROJECT": "Choose project or board that you want to import", + "NO_PROJECTS": "It seems you have no porjects or boards in Jira", + "URL": "Your Jira URL", + "KANBAN_PROJECT": "Kanban", + "SCRUM_PROJECT": "Scrum", + "ISSUES_PROJECT": "Tipos de problemas", + "CREATE_AS_SCRUM_DESCRIPTION": "The issues and sub-issues of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_KANBAN_DESCRIPTION": "The issues and sub-issues of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_ISSUES_DESCRIPTION": "What do you want to do with sub-issues from the Jira project? (Taiga doesn't allow sub-issues)", + "CREATE_NEW_ISSUES": "Convert sub-issues to new Taiga issues", + "NOT_CREATE_NEW_ISSUES": "Do not import sub-issues" + } } }, "LIGHTBOX": { "DELETE_ACCOUNT": { - "SECTION_NAME": "Apagar conta no Taiga", "CONFIRM": "Você tem certeza que quer apagar sua conta Taiga?", - "NEWSLETTER_LABEL_TEXT": "Eu não quero receber mais os informativos", "CANCEL": "Voltar para configurações", "ACCEPT": "Remover conta", - "BLOCK_PROJECT": "Note que todos os projetos em que você é o dono serão bloqueados depois que você apagar sua conta. Se você quer um projeto bloqueado, transfira a posse para outro membro de cada projeto antes de apagar sua conta.", - "SUBTITLE": "É uma pena vê-lo partir. Estaremos aqui se você algum dia considerar-nos novamente! :(" + "BLOCK_PROJECT": "Note que todos os projetos em que você é o dono serão bloqueados depois que você apagar sua conta. Se você quer um projeto bloqueado, transfira a posse para outro membro de cada projeto antes de apagar sua conta." }, "DELETE_PROJECT": { "TITLE": "Apagar projeto", @@ -1007,6 +1023,12 @@ }, "ADD_MEMBER": { "TITLE": "Novo Membro", + "PLACEHOLDER": "Filter users or write an email to invite", + "ADD_EMAIL": "Adicione e-mail.", + "REMOVE": "Remove", + "INVITE": "Invite", + "CHOOSE_ROLE": "Choose a role", + "PLACEHOLDER_INVITATION_TEXT": "(Opcional) Adicione uma mensagem de texto ao convite. Diga algo animador para os novos membros ;-)", "HELP_TEXT": "Se os usuários já estiverem registrados no Taiga, eles serão adicionados automaticamente. Caso contrário, eles receberão um convite." }, "CREATE_ISSUE": { @@ -1050,8 +1072,8 @@ "CREATE_MEMBER": { "PLACEHOLDER_INVITATION_TEXT": "(Opcional) Adicione uma mensagem de texto ao convite. Diga algo animador para os novos membros ;-)", "PLACEHOLDER_TYPE_EMAIL": "Digite um Email", - "LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "You are about to reach the maximum number of members allowed for this project, {{maxMembers}} members. If you would like to increase the current limit, please contact the administrator.", - "LIMIT_USERS_WARNING_MESSAGE": "You are about to reach the maximum number of members allowed for this project, {{maxMembers}} members." + "LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "Você está próximo de atingir o número máximo de membros permitidos para este projeto, {{maxMembers}} membros. Se você deseja aumentar este limite, por favor entre em contato com o administrador.", + "LIMIT_USERS_WARNING_MESSAGE": "Você está próximo de atingir o número máximo de membros permitidos para este projeto, {{maxMembers}} membros." }, "LEAVE_PROJECT_WARNING": { "TITLE": "Infelizmente, este projeto não pode ficar sem um dono", @@ -1068,27 +1090,33 @@ "TITLE": "Quem você quer que seja o novo dono do projeto?", "ADD_COMMENT": "Adicionar comentário", "BUTTON": "Pedir a este membro do projeto para se tornar o novo dono do projeto" + }, + "CONTACT_PROJECT": { + "TITLE": "Send an email to", + "WARNING": "The email will be received by the project admins", + "PLACEHOLDER": "Write your message", + "SEND": "Send" } }, "EPIC": { - "PAGE_TITLE": "{{epicSubject}} - Epic {{epicRef}} - {{projectName}}", - "PAGE_DESCRIPTION": "Status: {{epicStatus }}. Description: {{epicDescription}}", + "PAGE_TITLE": "{{epicSubject}} - Épico {{epicRef}} - {{projectName}}", + "PAGE_DESCRIPTION": "Estado: {{epicStatus }}. Descrição: {{epicDescription}}", "SECTION_NAME": "Épico", - "TITLE_LIGHTBOX_UNLINK_RELATED_USERSTORY": "Unlink related userstory", - "MSG_LIGHTBOX_UNLINK_RELATED_USERSTORY": "It will delete the link to the related userstory '{{subject}}'", - "ERROR_UNLINK_RELATED_USERSTORY": "We have not been able to unlink: {{errorMessage}}", - "CREATE_RELATED_USERSTORIES": "Create a relationship with", + "TITLE_LIGHTBOX_UNLINK_RELATED_USERSTORY": "Separar história de usuário relacionada", + "MSG_LIGHTBOX_UNLINK_RELATED_USERSTORY": "Excluirá a ligação para a história de usuário relacionada '{{subject}}'", + "ERROR_UNLINK_RELATED_USERSTORY": "Não fomos capazes de separar: {{errorMessage}}", + "CREATE_RELATED_USERSTORIES": "Criar um relacionamento com", "NEW_USERSTORY": "Nova história de usuário", - "EXISTING_USERSTORY": "Existing user story", - "CHOOSE_PROJECT_FOR_CREATION": "What's the project?", + "EXISTING_USERSTORY": "História de usuário existente", + "CHOOSE_PROJECT_FOR_CREATION": "Qual é o projeto?", "SUBJECT": "Assunto", - "SUBJECT_BULK_MODE": "Subject (bulk insert)", - "CHOOSE_PROJECT_FROM": "What's the project?", - "CHOOSE_USERSTORY": "What's the user story?", - "NO_USERSTORIES": "This project has no User Stories yet. Please select another project.", - "FILTER_USERSTORIES": "Filter user stories", - "LIGHTBOX_TITLE_BLOKING_EPIC": "Blocking epic", - "ACTION_DELETE": "Delete epic" + "SUBJECT_BULK_MODE": "Sujeito (inserção em lote)", + "CHOOSE_PROJECT_FROM": "Qual é o projeto?", + "CHOOSE_USERSTORY": "Qual é a história de usuário?", + "NO_USERSTORIES": "Esse projeto ainda não possui Histórias de Usuário. Por favor, selecione outro projeto.", + "FILTER_USERSTORIES": "Filtrar histórias de usuário", + "LIGHTBOX_TITLE_BLOKING_EPIC": "Épico bloqueador", + "ACTION_DELETE": "Apagar épico" }, "US": { "PAGE_TITLE": "{{userStorySubject}} - História de Usuário {{userStoryRef}} - {{projectName}}", @@ -1101,15 +1129,9 @@ "ADD_BULK": "Adicionar Histórias de Usuários em lote", "PROMOTED": "Esta História de Usuário foi criada a partir do Problema:", "TITLE_LINK_GO_TO_ISSUE": "Adicionar comentários aos apontamentos", - "EXTERNAL_REFERENCE": "Esta História de Usuário foi criada de", - "GO_TO_EXTERNAL_REFERENCE": "Ir para a origem", - "BLOCKED": "Esta história de usuário está bloqueada", "TITLE_DELETE_ACTION": "Apagar história de usuário", "LIGHTBOX_TITLE_BLOKING_US": "História de usuário bloqueadora", - "TASK_COMPLETED": "{{totalClosedTasks}}/{{totalTasks}} tarefas completas", - "ASSIGN": "Atribuir História de Usuário", "NOT_ESTIMATED": "Não estimado", - "TOTAL_US_POINTS": "Total de pontos de histórias", "TRIBE": { "PUBLISH": "Publicar como Gig no Taiga Tribe", "PUBLISH_INFO": "Mais informações", @@ -1119,23 +1141,19 @@ "CLOSE": "Fechar", "SYNCHRONIZE_LINK": "sincronizar com a Tribo Taiga", "PUBLISH_MORE_INFO_TITLE": "Você precisa de alguém para esta tarefa?", - "PUBLISH_MORE_INFO_TEXT": "

If you need help with a particular piece of work you can easily create gigs on Taiga Tribe and receive help from all over the world. You will be able to control and manage the gig enjoying a great community eager to contribute.

TaigaTribe was born as a Taiga sibling. Both platforms can live separately but we believe that there is much power in using them combined so we are making sure the integration works like a charm.

" + "PUBLISH_MORE_INFO_TEXT": "

If you need help with a particular piece of work you can easily create gigs on Taiga Tribe and receive help from all over the world. You will be able to control and manage the gig enjoying a great community eager to contribute.

TaigaTribe was born as a Taiga sibling. Both platforms can live separately but we believe that there is much power in using them combined so we are making sure the integration works like a charm.

" }, "FIELDS": { "TEAM_REQUIREMENT": "Requisitos da Equipe", - "CLIENT_REQUIREMENT": "Requisitos do Cliente", - "FINISH_DATE": "Data de término" + "CLIENT_REQUIREMENT": "Requisitos do Cliente" } }, "COMMENTS": { "DELETED_INFO": "Comentário apagado por {{user}}", - "TITLE": "Comentários", "COMMENTS_COUNT": "{{comments}} comentários", - "ORDER": "Ordenação", "OLDER_FIRST": "Antigos primeiro", "RECENT_FIRST": "Recentes primeiro", "COMMENT": "Comentário", - "EDIT_COMMENT": "Editar comentário", "EDITED_COMMENT": "Editado:", "SHOW_HISTORY": "Ver histórico", "TYPE_NEW_COMMENT": "Escreva um novo comentário aqui", @@ -1148,13 +1166,8 @@ } }, "ACTIVITY": { - "SHOW_ACTIVITY": "Exibir atividade", - "DATETIME": "DD MMM YYYY HH:mm", - "SHOW_MORE": "+ Mostrar entradas anteriores (mais {{showMore}})", "TITLE": "Atividade", "ACTIVITIES_COUNT": "{{activities}} atividades", - "REMOVED": "removido", - "ADDED": "adicionado", "TAGS_ADDED": "tags adicionadas:", "TAGS_REMOVED": "tags removidas:", "US_POINTS": "{{role}} pontos", @@ -1163,50 +1176,21 @@ "UPDATED_ATTACHMENT": "anexo atualizado ({{filename}}):", "CREATED_CUSTOM_ATTRIBUTE": "atributo personalizado criado", "UPDATED_CUSTOM_ATTRIBUTE": "atributo personalizado atualizado", - "SIZE_CHANGE": "Feito {size, plural, one{one change} other{# changes}}", "BECAME_DEPRECATED": "foi depreciado", "BECAME_UNDEPRECATED": "foi depreciado", "TEAM_REQUIREMENT": "Requisitos da Equipe", "CLIENT_REQUIREMENT": "Requisitos do Cliente", "BLOCKED": "Bloqueado", "VALUES": { - "YES": "sim", - "NO": "não", - "EMPTY": "vazio", "UNASSIGNED": "não atribuído" }, "FIELDS": { "SUBJECT": "assunto", - "NAME": "nome", "DESCRIPTION": "descrição", - "CONTENT": "conteúdo", "STATUS": "status", - "IS_CLOSED": "está fechado", - "FINISH_DATE": "Data de término", "TYPE": "Digite", - "PRIORITY": "prioridade", - "SEVERITY": "gravidade", "ASSIGNED_TO": "Assinado à", - "WATCHERS": "Observadores", "MILESTONE": "sprint", - "USER_STORY": "história de usuário", - "PROJECT": "projeto", - "IS_BLOCKED": "está bloqueada", - "BLOCKED_NOTE": "Nota de bloqueio", - "POINTS": "pontos", - "CLIENT_REQUIREMENT": "requisitos do cliente", - "TEAM_REQUIREMENT": "requisitos da equipe", - "IS_IOCAINE": "É Iocaine", - "TAGS": "tags", - "ATTACHMENTS": "anexos", - "IS_DEPRECATED": "está obsoleto", - "IS_NOT_DEPRECATED": "is not deprecated", - "ORDER": "ordem", - "BACKLOG_ORDER": "requisição do backlog", - "SPRINT_ORDER": "ordem de sprint ", - "KANBAN_ORDER": "pedido kanban", - "TASKBOARD_ORDER": "Ordem de quadro de tarefa", - "US_ORDER": "ordem da história de usuário", "COLOR": "cor" } }, @@ -1220,8 +1204,6 @@ "CUSTOMIZE_GRAPH_TITLE": "Configure os pontos e sprints pelo Administrador", "MOVE_US_TO_CURRENT_SPRINT": "Mover para a Sprint Atual", "MOVE_US_TO_LATEST_SPRINT": "Mover para a última Sprint", - "SHOW_FILTERS": "Mostrar filtros", - "SHOW_TAGS": "Exibir tags", "EMPTY": "O backlog está vazio!", "CREATE_NEW_US": "Criar uma nova História de Usuário", "CREATE_NEW_US_EMPTY_HELP": "Você talvez queira criar uma nova história de usuário", @@ -1248,6 +1230,12 @@ "SHOW": "Exibir tags", "HIDE": "Esconder tags" }, + "FORECASTING": { + "TITLE": "Velocity forecasting", + "BACKLOG": "Display backlog", + "NEW_SPRINT": "Candidate User Stories for your next sprint based on your velocity. Click to create a new sprint.", + "CURRENT_SPRINT": "Candidate User Stories for your sprint based on your velocity. Click to add to current sprint." + }, "TABLE": { "COLUMN_US": "Histórias de Usuários", "TITLE_COLUMN_POINTS": "Selecionar exibição por função" @@ -1260,7 +1248,7 @@ "IOCAINE_DOSES": "iocaine
doses", "SHOW_STATISTICS_TITLE": "Mostrar estatísticas", "TOGGLE_BAKLOG_GRAPH": "Mostrar/Esconder gráfico de burndown", - "POINTS_PER_ROLE": "Points per role" + "POINTS_PER_ROLE": "Pontos por regra" }, "SUMMARY": { "PROJECT_POINTS": "pontos do
projeto", @@ -1270,8 +1258,6 @@ }, "FILTERS": { "TOGGLE": "Alternar visibilidade de filtros", - "TITLE": "Filtros", - "REMOVE": "Remover filtros", "HIDE": "Esconder Filtros", "SHOW": "Mostrar Filtros" }, @@ -1280,7 +1266,6 @@ "DATE": "DD MMM YYYY", "LINK_TASKBOARD": "Quadro de tarefas da Sprint", "TITLE_LINK_TASKBOARD": "ir para quadro de tarefas de \"{{name}}\"", - "NUMBER_SPRINTS": "
sprints", "EMPTY": "Ainda não temos sprints.", "WARNING_EMPTY_SPRINT_ANONYMOUS": "Esta sprint não tem Histórias de Usuário", "WARNING_EMPTY_SPRINT": "Solte aqui Histórias do seu backlog para iniciar uma nova sprint", @@ -1305,7 +1290,6 @@ "TITLE_ACTION_ADD": "Adicionar uma nova Tarefa", "TITLE_ACTION_ADD_BULK": "Adicionar algumas tarefas em lote", "TITLE_ACTION_ASSIGN": "Assinalar tarefa", - "TITLE_ACTION_EDIT": "Editar tarefa", "PLACEHOLDER_CARD_TITLE": "Isto pode ser uma atividade", "PLACEHOLDER_CARD_TEXT": "Separe Histórias de Usuários em atividades para rastreá-las separadamente.", "TABLE": { @@ -1335,17 +1319,11 @@ "TITLE_SELECT_STATUS": "Nome de Status", "OWNER_US": "Esta tarefa pertence a ", "TITLE_LINK_GO_OWNER": "Ir para história de usuário", - "ORIGIN_US": "Essa tarefa foi criada a partir de", - "TITLE_LINK_GO_ORIGIN": "Ir para história de usuário", - "BLOCKED": "Esta tarefa está bloqueada", "TITLE_DELETE_ACTION": "Apagar Tarefa", "LIGHTBOX_TITLE_BLOKING_TASK": "Tarefa bloqueadora", "FIELDS": { - "MILESTONE": "Sprint", - "USER_STORY": "História de usuário", "IS_IOCAINE": "É Iocaine" }, - "ACTION_IOCAINE": "Iocaine", "TITLE_ACTION_IOCAINE": "Se sentindo sobrecarregado por uma tarefa? Assegure-se de que os outros saibam disso clicando em Iocaine quando estiver editando a tarefa. É possível se tornar imune a essse veneno mortal (fictício) consumindo pequenas quantidades ao longo do tempo, assim como é possível ficar melhor no que faz, ocasionalmente, por assumir desafios extras!" }, "NOTIFICATION": { @@ -1374,14 +1352,12 @@ "ISSUES": { "PAGE_TITLE": "Apontamentos - {{projectName}}", "PAGE_DESCRIPTION": "O painel de problemas do projeto {{projectName}}: {{projectDescription}}", - "LIST_SECTION_NAME": "Tipos de problemas", "SECTION_NAME": "Problema", "ACTION_NEW_ISSUE": "+ NOVO PROBLEMA", "ACTION_PROMOTE_TO_US": "Promover para História de Usuário", "PROMOTED": "Esse problema foi promovido para história de usuário", "EXTERNAL_REFERENCE": "Esse problema foi criado a partir de", "GO_TO_EXTERNAL_REFERENCE": "Ir para a origem", - "BLOCKED": "Esse apontamento está bloqueado", "ACTION_DELETE": "Problema apagado", "LIGHTBOX_TITLE_BLOKING_ISSUE": "Problema que está bloqueando", "FIELDS": { @@ -1423,15 +1399,11 @@ "SECTION_NAME": "Kanban", "TITLE_ACTION_FOLD": "Recolher coluna", "TITLE_ACTION_UNFOLD": "Abrir coluna", - "TITLE_ACTION_FOLD_CARDS": "Guardar cartões", - "TITLE_ACTION_UNFOLD_CARDS": "Mostrar cartões", "TITLE_ACTION_ADD_US": "Adicionar Nova História de Usuário", "TITLE_ACTION_ADD_BULK": "Adicionar novo lote", "ACTION_SHOW_ARCHIVED": "Mostrar arquivados", "ACTION_HIDE_ARCHIVED": "esconder arquivados", "HIDDEN_USER_STORIES": "As histórias de usuários nesse status são escondidas por padrão", - "ARCHIVED": "Você arquivou", - "UNDO_ARCHIVED": "Pegue e arraste novamente para desfazer", "PLACEHOLDER_CARD_TITLE": "Estas são suas Histórias de Usuários", "PLACEHOLDER_CARD_TEXT": "Histórias poderão também ter sub-atividades para separar os requisitos" }, @@ -1452,7 +1424,6 @@ "PAGE_TITLE": "Equipe - {{projectName}}", "PAGE_DESCRIPTION": "O painel do time irá exibir todos os membros envolvidos no projeto {{projectName}}: {{projectDescription}}", "SECTION_NAME": "Time", - "APP_TITLE": "EQUIPE - {{projectName}}", "PLACEHOLDER_INPUT_SEARCH": "Procurar pelo nome completo...", "COLUMN_MR_WOLF": "Sr. Wolf", "EXPLANATION_COLUMN_MR_WOLF": "Adicionar apontamentos", @@ -1488,18 +1459,9 @@ "OPTION_ALL": "Tudo", "OPTION_INVOLVED": "Envolvido", "OPTION_NONE": "Nada" - }, - "POPOVER": { - "USER_PROFILE": "Perfil do Usuário", - "CHANGE_PASSWORD": "Alterar Senha", - "NOTIFICATIONS": "Notificações", - "FEEDBACK": "Feedback", - "TITLE_AVATAR": "Preferências do Usuário" } }, "USER_PROFILE": { - "IMAGE_HELP": "A imagem será redimensionada para a escala de 80x80px.", - "ACTION_CHANGE_IMAGE": "Alterar", "ACTION_USE_GRAVATAR": "Usar imagem padrão", "ACTION_DELETE_ACCOUNT": "Apagar conta Taiga", "CHANGE_EMAIL_SUCCESS": "Verifique sua caixa de entrada!
Enviamos um e-mail para sua conta
com as instruções para definir seu novo endereço", @@ -1517,32 +1479,17 @@ "THEME_DEFAULT": "-- usar tema padrão --" } }, - "WIZARD": { - "SECTION_TITLE_CREATE_PROJECT": "Criar Projeto", - "CREATE_PROJECT_TEXT": "Novo em folha. Tão excitante!", - "CHOOSE_TEMPLATE": "Qual template se encaixa melhor no seu projeto?", - "CHOOSE_TEMPLATE_TITLE": "Mais informações sobre templates de projeto", - "CHOOSE_TEMPLATE_INFO": "Mais informações", - "PROJECT_DETAILS": "Detalhes do Projeto", - "PUBLIC_PROJECT": "Projeto Público", - "PRIVATE_PROJECT": "Projeto Privado", - "CREATE_PROJECT": "Criar projeto", - "MAX_PRIVATE_PROJECTS": "You've reached the maximum number of private projects", - "MAX_PUBLIC_PROJECTS": "Infelizmente, você atingiu o número máximo de projetos públicos", - "CHANGE_PLANS": "change plans" - }, "WIKI": { "PAGE_TITLE": "{{wikiPageName}} - Wiki - {{projectName}}", "PAGE_DESCRIPTION": "Ultima edição em {{lastModifiedDate}} ({{totalEditions}} total de edições) Conteúdo: {{ wikiPageContent }}", "DATETIME": "DD MMM YYYY HH:mm", - "PLACEHOLDER_PAGE": "Escreve sua página wiki", "REMOVE": "Remover essa página wiki", "DELETE_LIGHTBOX_TITLE": "Apagar página Wiki", "DELETE_LINK_TITLE": "Remover link de Wiki", "NAVIGATION": { "HOME": "Página principal", - "SECTION_NAME": "BOOKMARKS", - "ACTION_ADD_LINK": "Add bookmark", + "SECTION_NAME": "MARCADORES", + "ACTION_ADD_LINK": "Adicionar marcador", "ALL_PAGES": "Todas as páginas wiki" }, "SUMMARY": { @@ -1569,7 +1516,7 @@ "HINT2_TITLE": "Você sabia que pode criar campos personalizados?", "HINT2_TEXT": "Equipes agora podem personalizar campos, um jeito flexível de inserir dados específicos para uso em seu próprio fluxo de trabalho.", "HINT3_TITLE": "Reordene seus projetos para evidenciar os mais relevantes para você.", - "HINT3_TEXT": "The 10 projects are listed in the direct access bar at the top.", + "HINT3_TEXT": "Os 10 projetos estão listados na barra de acesso direto, no topo.", "HINT4_TITLE": "Você esqueceu onde está trabalhando?", "HINT4_TEXT": "Não se preocupe, no seu painel você vai encontrar suas tarefas abertas, problemas, e histórias de usuários na ordem em que você trabalhou nelas." }, @@ -1581,8 +1528,8 @@ "TASK_CREATED_WITH_US": "{{username}} criou nova tarefa {{obj_name}} em {{project_name}} que pertence a História de Usuário {{us_name}}", "WIKI_CREATED": "{{username}} criou uma página wiki {{obj_name}} em {{project_name}}", "MILESTONE_CREATED": "{{username}} criou uma nova sprint {{obj_name}} em {{project_name}}", - "EPIC_CREATED": "{{username}} has created a new epic {{obj_name}} in {{project_name}}", - "EPIC_RELATED_USERSTORY_CREATED": "{{username}} has related the userstory {{related_us_name}} to the epic {{epic_name}} in {{project_name}}", + "EPIC_CREATED": "{{username}} criou um novo épico {{obj_name}} em {{project_name}}", + "EPIC_RELATED_USERSTORY_CREATED": "{{username}} relacionou a história de usuário {{related_us_name}} ao épico {{epic_name}} em {{project_name}}", "NEW_PROJECT": "{{username}} criou o projeto {{project_name}}", "MILESTONE_UPDATED": "{{username}} atualizou a sprint {{obj_name}}", "US_UPDATED": "{{username}} atualizou o atributo \"{{field_name}}\" da História de Usuário {{obj_name}}", @@ -1595,13 +1542,13 @@ "TASK_UPDATED_WITH_US": "{{username}} atualizou o atributo \"{{field_name}}\" da tarefa {{obj_name}} que pertence à História de Usuário {{us_name}}", "TASK_UPDATED_WITH_US_NEW_VALUE": "{{username}} atualizou o atributo \"{{field_name}}\" da tarefa {{obj_name}} que pertence à História de Usuário {{us_name}} para {{new_value}}", "WIKI_UPDATED": "{{username}} atualizou a página wiki {{obj_name}}", - "EPIC_UPDATED": "{{username}} has updated the attribute \"{{field_name}}\" of the epic {{obj_name}}", - "EPIC_UPDATED_WITH_NEW_VALUE": "{{username}} has updated the attribute \"{{field_name}}\" of the epic {{obj_name}} to {{new_value}}", - "EPIC_UPDATED_WITH_NEW_COLOR": "{{username}} has updated the \"{{field_name}}\" of the epic {{obj_name}} to ", + "EPIC_UPDATED": "{{username}} atualizou o atributo \"{{field_name}}\" do épico {{obj_name}}", + "EPIC_UPDATED_WITH_NEW_VALUE": "{{username}} atualizou o atributo \"{{field_name}}\" do épico {{obj_name}} para {{new_value}}", + "EPIC_UPDATED_WITH_NEW_COLOR": "{{username}} atualizou o \"{{field_name}}\" do épico {{obj_name}} para ", "NEW_COMMENT_US": "{{username}} comentou na História de Usuário {{obj_name}}", "NEW_COMMENT_ISSUE": "{{username}} comentou no problema {{obj_name}}", "NEW_COMMENT_TASK": "{{username}} comentou na tarefa {{obj_name}}", - "NEW_COMMENT_EPIC": "{{username}} has commented in the epic {{obj_name}}", + "NEW_COMMENT_EPIC": "{{username}} comentou no épico {{obj_name}}", "NEW_MEMBER": "{{project_name}} tem um membro novo", "US_ADDED_MILESTONE": "{{username}} adicionou a História de Usuário {{obj_name}} a {{sprint_name}}", "US_MOVED": "{{username}} moveu a História de Usuário {{obj_name}}", @@ -1693,8 +1640,7 @@ "MOST_LIKED": "Mais curtidas", "MOST_LIKED_EMPTY": "Não existe projetos curtidos ainda", "VIEW_MORE": "Visualizar mais", - "RECRUITING": "Este projeto esta procurando colaboradores", - "FEATURED": "Featured Projects", + "FEATURED": "Projetos em destaque", "EMPTY": "Não há projetos para exibir sob esse critério de pesquisa.
Tente novamente!", "FILTERS": { "ALL": "Tudo", diff --git a/app/locales/taiga/locale-ru.json b/app/locales/taiga/locale-ru.json index fa49835a..3d6e5e62 100644 --- a/app/locales/taiga/locale-ru.json +++ b/app/locales/taiga/locale-ru.json @@ -4,14 +4,13 @@ "NO": "Нет", "OR": "или", "LOADING": "Пожалуйста, подождите...", - "LOADING_PROJECT": "Проект загружается...", "DATE": "DD MMM YYYY", "DATETIME": "DD MMM YYYY HH:mm", "SAVE": "Сохранить", "CANCEL": "Отмена", "ACCEPT": "Принимаю", "DELETE": "Удалить", - "UNLINK": "Unlink", + "UNLINK": "Отсоединить", "CREATE": "Создать", "ADD": "Добавить", "COPY_TO_CLIPBOARD": "Копировать: Ctrl+C", @@ -27,12 +26,9 @@ "BLOCKED_NOTE": "Почему это заблокировано?", "BLOCKED_REASON": "Пожалуйста разъясните причину", "CREATED_BY": "Создано {{fullDisplayName}}", - "FROM": "от", - "TO": "к", "CLOSE": "закрыть", "GO_HOME": "Домой", "PLUGINS": "Плагины", - "BETA": "Программа тестируется!", "ONE_ITEM_LINE": "Один объект на строку...", "NEW_BULK": "Добавить пакетно", "RELATED_TASKS": "Связанные задачи", @@ -41,14 +37,14 @@ "LOGOUT": "Выйти", "EXTERNAL_USER": "внешний пользователь", "GENERIC_ERROR": "Один из Умпа-Лумп говорит {{error}}.", - "IOCAINE_TEXT": "Чувствуете, что задание берет верх над вами? Дайте другим знать об этом, нажав на \"Иокаин\", когда редактируете задание. Возможно стать неуязвимым к этому (выдуманному) смертельном яду, потребляя небольшие количества время от времени, так же как возможно стать лучше в том, что вы делаете, временами беря на себя дополнительные препятствия!", + "IOCAINE_TEXT": "This member is feeling a bit overwhelmed by this task. Will become immune to the iocaine poison over time with your help. For now, may need a hug.", "CLIENT_REQUIREMENT": "Client requirement is new requirement that was not previously expected and it is required to be part of the project", "TEAM_REQUIREMENT": "Team requirement is a requirement that must exist in the project but should have no cost for the client", "OWNER": "Владелец проекта", "CAPSLOCK_WARNING": "Be careful! You are using capital letters in an input field that is case sensitive.", "CONFIRM_CLOSE_EDIT_MODE_TITLE": "Are you sure you want to close the edit mode?", "CONFIRM_CLOSE_EDIT_MODE_MESSAGE": "Remember that if you close the edit mode without saving all the changes will be lost", - "RELATED_USERSTORIES": "Related user stories", + "RELATED_USERSTORIES": "Связанные пользовательские истории", "CARD": { "ASSIGN_TO": "Assign To", "EDIT": "Edit card" @@ -125,7 +121,7 @@ "ISSUE": "Запрос", "EPIC": "Epic", "TAGS": { - "PLACEHOLDER": "Enter tag", + "PLACEHOLDER": "Ввести тэг", "DELETE": "Удалить тэг", "ADD": "Добавить тэг" }, @@ -148,7 +144,6 @@ "PRIORITY": "Приоритет", "ASSIGNED_TO": "Назначено", "POINTS": "Очки", - "BLOCKED_NOTE": "Пояснение блокировки", "IS_BLOCKED": "заблокирован", "REF": "Ссылка", "VOTES": "Голоса", @@ -187,10 +182,6 @@ "COUNTER_TITLE": "{total, plural, one{один наблюдатель} other{# наблюдателя (-ей)}}" }, "VOTE_BUTTON": { - "UPVOTE": "Повысить", - "UPVOTED": "Повышено", - "DOWNVOTE": "Понизить", - "VOTERS": "Проголосовавшие", "BUTTON_TITLE": "Повысить/понизить", "COUNTER_TITLE": "{total, plural, one{один голос} other{# голоса (-ов)}}" }, @@ -202,10 +193,9 @@ "CONFIRM_DELETE": "Remeber that all values in this custom field will be deleted.\n Are you sure you want to continue?" }, "FILTERS": { - "TITLE": "Фильтры", "INPUT_PLACEHOLDER": "Название ссылки", "TITLE_ACTION_FILTER_BUTTON": "поиск", - "INPUT_SEARCH_PLACEHOLDER": "Название ссылки", + "TITLE": "Фильтры", "TITLE_ACTION_SEARCH": "Поиск", "ACTION_SAVE_CUSTOM_FILTER": "сохранить как специальный фильтр", "PLACEHOLDER_FILTER_NAME": "Введите название фильтра и нажмите \"ввод\"", @@ -220,51 +210,20 @@ "CREATED_BY": "Создано", "CUSTOM_FILTERS": "Собственные фильтры", "EPIC": "Epic" - }, - "CONFIRM_DELETE": { - "TITLE": "Удалить фильтр", - "MESSAGE": "специальный фильтр '{{customFilterName}}'" } }, "WYSIWYG": { - "H1_BUTTON": "Заголовок первого уровня", - "H1_SAMPLE_TEXT": "Ваш заголовок здесь...", - "H2_BUTTON": "Заголовок второго уровня", - "H2_SAMPLE_TEXT": "Ваш заголовок здесь...", - "H3_BUTTON": "Заголовок третьего уровня", - "H3_SAMPLE_TEXT": "Ваш заголовок здесь...", - "BOLD_BUTTON": "Полужирный", - "BOLD_BUTTON_SAMPLE_TEXT": "Ваш текст здесь...", - "ITALIC_BUTTON": "Курсив", - "ITALIC_SAMPLE_TEXT": "Ваш текст здесь...", - "STRIKE_BUTTON": "Зачёркнутый", - "STRIKE_SAMPLE_TEXT": "Ваш текст здесь...", - "BULLETED_LIST_BUTTON": "Маркированный список", - "BULLETED_LIST_SAMPLE_TEXT": "Ваш текст здесь...", - "NUMERIC_LIST_BUTTON": "Нумерованный список", - "NUMERIC_LIST_SAMPLE_TEXT": "Ваш текст здесь...", - "PICTURE_BUTTON": "Изображение", - "PICTURE_SAMPLE_TEXT": "Альтернативный текст для изображения...", - "LINK_BUTTON": "Ссылка", - "LINK_SAMPLE_TEXT": "Ваш текст для ссылки здесь...", - "QUOTE_BLOCK_BUTTON": "Блок с цитатой", - "QUOTE_BLOCK_SAMPLE_TEXT": "Ваш текст здесь...", - "CODE_BLOCK_BUTTON": "Блок кода", - "CODE_BLOCK_SAMPLE_TEXT": "Ваш текст здесь...", - "PREVIEW_BUTTON": "Предварительный просмотр", - "EDIT_BUTTON": "Редактировать", - "ATTACH_FILE_HELP": "Attach files by dragging & dropping on the textarea above.", - "ATTACH_FILE_HELP_SAVE_FIRST": "Save first before if you want to attach files by dragging & dropping on the textarea above.", + "OUTDATED": "Another person has made changes while you were editing. Check the new version on the activiy tab before you save your changes.", "MARKDOWN_HELP": "Помощь по синтаксису Markdown" }, "PERMISIONS_CATEGORIES": { "EPICS": { "NAME": "Epics", - "VIEW_EPICS": "View epics", - "ADD_EPICS": "Add epics", - "MODIFY_EPICS": "Modify epics", + "VIEW_EPICS": "Посмотреть эпосы", + "ADD_EPICS": "Добавить эпосы", + "MODIFY_EPICS": "Изменить эпосы", "COMMENT_EPICS": "Comment epics", - "DELETE_EPICS": "Delete epics" + "DELETE_EPICS": "Удалить эпосы" }, "SPRINTS": { "NAME": "Спринты", @@ -307,10 +266,6 @@ "ADD_WIKI_LINKS": "Добавить wiki-ссылки", "DELETE_WIKI_LINKS": "Удалить wiki-ссылки" } - }, - "META": { - "PAGE_TITLE": "Taiga", - "PAGE_DESCRIPTION": "Taiga - это платформа по управлению проектами для стартапов и agile-разработчиков/дизайнеров, которые хотят пользоваться простым и красивым инструментом, делающим их жизнь по-настоящему приятной." } }, "LOGIN": { @@ -366,7 +321,6 @@ }, "CHANGE_PASSWORD": { "PAGE_TITLE": "Изменить пароль - Taiga", - "PAGE_DESCRIPTION": "Введите новый пароль для Вашего Taiga аккаунта и кстати, еда богатая железом — полезна для мозгов :P", "SECTION_NAME": "Изменить пароль", "FIELD_CURRENT_PASSWORD": "Текущий пароль", "PLACEHOLDER_CURRENT_PASSWORD": "Ваш текущий пароль (или оставьте пустым, если пароль еще не задан)", @@ -391,8 +345,7 @@ }, "INVITATION_LOGIN_FORM": { "NOT_FOUND": "У наших Умпа-Лумп не получается найти ваше приглашение.", - "SUCCESS": "Вы успешно добавлены к проекту. Добро пожаловать в {{project_name}}", - "ERROR": "Умпа-Лумпы говорят, что вы не зарегистрированы или ввели неверный пароль." + "SUCCESS": "Вы успешно добавлены к проекту. Добро пожаловать в {{project_name}}" }, "HOME": { "PAGE_TITLE": "Домашняя страница - Taiga", @@ -408,15 +361,15 @@ "TITLE": "EPICS", "SECTION_NAME": "Epics", "EPIC": "EPIC", - "PAGE_TITLE": "Epics - {{projectName}}", - "PAGE_DESCRIPTION": "The epics list of the project {{projectName}}: {{projectDescription}}", + "PAGE_TITLE": "Эпосы - {{projectName}}", + "PAGE_DESCRIPTION": "Список эпосов этого проекта {{projectName}}: {{projectDescription}}", "DASHBOARD": { "ADD": "+ ADD EPIC", "UNASSIGNED": "Не назначено" }, "EMPTY": { - "TITLE": "It looks like there aren't any epics yet", - "EXPLANATION": "Epics are items at a higher level that encompass user stories.
Epics are at the top of the hierarchy and can be used to group user stories together.", + "TITLE": "Похоже, здесь пока нет ни одного эпоса ", + "EXPLANATION": "Эпосы - это сущности высокого уровня, которые направляют пользовательские истории.
Эпосы находятся на вершине иерархии и могут быть использованы, чтобы связывать вместе пользовательские истории.", "HELP": "Learn more about epics" }, "TABLE": { @@ -431,7 +384,7 @@ }, "CREATE": { "TITLE": "New Epic", - "PLACEHOLDER_DESCRIPTION": "Please add descriptive text to help others better understand this epic", + "PLACEHOLDER_DESCRIPTION": "Пожалуйста, добавьте описание, чтобы другие лучше поняли этот эпос", "TEAM_REQUIREMENT": "Team requirement", "CLIENT_REQUIREMENT": "Client requirement", "BLOCKED": "Заблокирован", @@ -463,10 +416,7 @@ "TITLE_LIGHTBOX_DELETE_ATTACHMENT": "Удалить вложение...", "MSG_LIGHTBOX_DELETE_ATTACHMENT": "приложение '{{fileName}}'", "ERROR_DELETE_ATTACHMENT": "Мы не смогли провести удаление: {{errorMessage}}", - "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) это слишком много для наших Умпа-Лумп, попробуйте еще раз с размером меньшим, чем ({{maxFileSize}})", - "FIELDS": { - "IS_DEPRECATED": "рекомендовано" - } + "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) это слишком много для наших Умпа-Лумп, попробуйте еще раз с размером меньшим, чем ({{maxFileSize}})" }, "PAGINATION": { "PREVIOUS": "Пред.", @@ -502,13 +452,10 @@ "ASYNC_MESSAGE": "Мы отправим вам письмо когда будет готово.", "SYNC_MESSAGE": "Если загрузка не начинается самостоятельно, нажмите здесь.", "ERROR": "У Oompa Loompas возникли проблемы при создании резервной копии. Повторите еще раз.", - "ERROR_BUSY": "Извините, Oompa Loompas очень загружен сейчас. Повторите через несколько минут.", - "ERROR_MESSAGE": "Умпа-Лумпы не смогли создать для вас дамп: {{message}}" + "ERROR_BUSY": "Извините, Oompa Loompas очень загружен сейчас. Повторите через несколько минут." }, "MODULES": { "TITLE": "Модули", - "ENABLE": "Включить", - "DISABLE": "Выключить", "EPICS": "Epics", "EPICS_DESCRIPTION": "Visualize and manage the most strategic part of your project", "BACKLOG": "Список задач", @@ -537,17 +484,16 @@ "PAGE_TITLE": "{{sectionName}} - профиль Проекта - {{projectName}}", "PROJECT_DETAILS": "Детали проекта", "PROJECT_NAME": "Название проекта", - "PROJECT_SLUG": "Ссылочное имя проекта", "TAGS": "Тэги", "DESCRIPTION": "Описание", "RECRUITING": "Этот проект ищет людей?", "RECRUITING_MESSAGE": "Кого вы ищете?", "RECRUITING_PLACEHOLDER": "Уточните, какие профили вы ищете", + "FEEDBACK": "Receive feedback from Taiga users?", "PUBLIC_PROJECT": "Публичный проект", "PRIVATE_PROJECT": "Закрытый проект", "PRIVATE_OR_PUBLIC": "В чём разница между публичными и приватными проектами?", "DELETE": "Удалить проект", - "LOGO_HELP": "Изображение будет отмасштабировано до 80x80px.", "CHANGE_LOGO": "Изменить лого", "ACTION_USE_DEFAULT_LOGO": "Использовать картинку по умолчанию", "MAX_PRIVATE_PROJECTS": "Вы достигли максимального числа приватных проектов которое разрешено вашим планом.", @@ -573,7 +519,7 @@ "REGENERATE_SUBTITLE": "Вы собираетесь изменить ссылку доступа к данным CSV. Прежний вариант ссылки перестанет работать. Вы уверены?" }, "CSV": { - "SECTION_TITLE_EPIC": "epics reports", + "SECTION_TITLE_EPIC": "отчёты о эпосах", "SECTION_TITLE_US": "Отчёты по пользовательским историям", "SECTION_TITLE_TASK": "отчёты о задачах", "SECTION_TITLE_ISSUE": "отчёты о запросах", @@ -586,8 +532,8 @@ "CUSTOM_FIELDS": { "TITLE": "Пользовательские поля", "SUBTITLE": "Укажите специальные поля для ваших пользовательских историй, задач и запросов", - "EPIC_DESCRIPTION": "Epics custom fields", - "EPIC_ADD": "Add a custom field in epics", + "EPIC_DESCRIPTION": "Специальные поля эпосов", + "EPIC_ADD": "Добавить специальное поле для эпосов", "US_DESCRIPTION": "Специальные поля для пользовательских историй", "US_ADD": "Добавить специальное поле для пользовательских историй", "TASK_DESCRIPTION": "Специальные поля задач", @@ -595,6 +541,7 @@ "ISSUE_DESCRIPTION": "Специальные поля запросов", "ISSUE_ADD": "Добавить специальное поле для запросов", "FIELD_TYPE_TEXT": "Текст", + "FIELD_TYPE_RICHTEXT": "Rich text", "FIELD_TYPE_MULTI": "Многостроковое", "FIELD_TYPE_DATE": "Дата", "FIELD_TYPE_URL": "Url" @@ -623,10 +570,10 @@ "ACTION_ADD": "Добавить новую степень важности" }, "PROJECT_VALUES_STATUS": { - "TITLE": "Статус", + "TITLE": "Statuses", "SUBTITLE": "Укажите, какие статусы будут принимать ваши пользовательские истории, задачи и запросы", - "EPIC_TITLE": "Epic Statuses", - "US_TITLE": "User Story Statuses", + "EPIC_TITLE": "Статусы Эпоса", + "US_TITLE": "Статусы пользовательских историй", "TASK_TITLE": "Статус задач", "ISSUE_TITLE": "Статусы запроса" }, @@ -676,8 +623,8 @@ "INFO_VERIFYING_IP": "Запросы к Gitlab не подписаны, так что лучший способ их проверки - это проверка по IP-адресу. Если это поле пустое, IP-адрес не будет проверяться." }, "GITHUB": { - "SECTION_NAME": "Github", - "PAGE_TITLE": "Github - {{projectName}}" + "SECTION_NAME": "GitHub", + "PAGE_TITLE": "GitHub - {{projectName}}" }, "GOGS": { "SECTION_NAME": "Gogs", @@ -686,7 +633,6 @@ "WEBHOOKS": { "PAGE_TITLE": "Веб-хуки - {{projectName}}", "SECTION_NAME": "Веб-хуки", - "SUBTITLE": "Веб-хуки рассказывают внешним сервисам о событиях в Taiga, таких как комментарии, новые пользовательские истории и т.д.", "ADD_NEW": "Добавить новый веб-хук", "TYPE_NAME": "Укажите имя сервиса", "TYPE_PAYLOAD_URL": "Укажите нагрузочную ссылку сервиса", @@ -732,7 +678,6 @@ "DELETE_MEMBER": "Удалить участника", "RESEND": "Переотправить", "SUCCESS_SEND_INVITATION": "Мы отправили ещё одно приглашение на адрес '{{email}}'.", - "ERROR_SEND_INVITATION": "Мы не выслали приглашение.", "SUCCESS_DELETE": "Мы удалили {{message}}.", "ERROR_DELETE": "Мы не смогли удалить {{message}}", "DEFAULT_DELETE_MESSAGE": "приглашение на {{email}}" @@ -755,22 +700,17 @@ }, "US_STATUS": { "ACTION_ADD_STATUS": "Добавить новый статус", - "IS_ARCHIVED_COLUMN": "Архивирована", + "IS_ARCHIVED_COLUMN": "В архиве", "IS_CLOSED_COLUMN": "Закрыта", "WIP_LIMIT_COLUMN": "Лимит текущей работы", "PLACEHOLDER_WRITE_NAME": "Укажите название для нового статуса" }, "MENU": { - "TITLE": "Админка", "PROJECT": "Проект", "ATTRIBUTES": "Атрибуты", "MEMBERS": "Участники", "PERMISSIONS": "Разрешения", - "INTEGRATIONS": "Интеграции", - "PLUGINS": "Плагины" - }, - "SUBMENU_PROJECT_ATTRIBUTES": { - "TITLE": "Атрибуты" + "INTEGRATIONS": "Интеграции" }, "SUBMENU_PROJECT_VALUES": { "STATUS": "Статус", @@ -781,17 +721,11 @@ "CUSTOM_FIELDS": "Собственные поля", "TAGS": "Тэги" }, - "SUBMENU_PROJECT_PROFILE": { - "TITLE": "Профиль проекта" - }, "SUBMENU_ROLES": { "TITLE": "Роли", "ACTION_NEW_ROLE": "+ Новая роль", "TITLE_ACTION_NEW_ROLE": "Добавить новую роль" }, - "SUBMENU_THIDPARTIES": { - "TITLE": "Сервисы" - }, "PROJECT_TRANSFER": { "DO_YOU_ACCEPT_PROJECT_OWNERNSHIP": "Would you like to become the new project owner?", "PRIVATE": "Private", @@ -806,15 +740,13 @@ "PRIVATE": "Please remember that you can own up to {{maxProjects}} private projects. You currently own {{currentProjects}} private projects", "PUBLIC": "Please remember that you can own up to {{maxProjects}} public projects. You currently own {{currentProjects}} public projects" }, - "CANT_BE_OWNED": "At the moment you cannot become an owner of a project of this type. If you would like to become the owner of this project, please contact the administrator so they change your account settings to enable project ownership.", - "CHANGE_MY_PLAN": "Change my plan" + "CANT_BE_OWNED": "At the moment you cannot become an owner of a project of this type. If you would like to become the owner of this project, please contact the administrator so they change your account settings to enable project ownership." } }, "USER": { "PROFILE": { "PAGE_TITLE": "{{userFullName}} (@{{userUsername}})", "EDIT": "Изменить профиль", - "FOLLOW": "Следить", "CLOSED_US": "Закрытые ПИ", "PROJECTS": "Проекты", "PROJECTS_EMPTY": "{{username}} пока не имеет проектов", @@ -822,7 +754,6 @@ "CONTACTS_EMPTY": "{{username}} ещё не имеет контактов", "CURRENT_USER_CONTACTS_EMPTY": "У вас пока нет контактов", "CURRENT_USER_CONTACTS_EMPTY_EXPLAIN": "Люди, с которыми вы работаете в Taiga, будут отмечены как ваши контакты автоматически", - "REPORT": "Пожаловаться", "TABS": { "ACTIVITY_TAB": "График работ", "ACTIVITY_TAB_TITLE": "Показать все действия пользователя", @@ -848,13 +779,13 @@ "FILTER_TYPE_ALL": "Все", "FILTER_TYPE_ALL_TITLE": "Показать все", "FILTER_TYPE_PROJECTS": "Проекты", - "FILTER_TYPE_PROJECT_TITLES": "Показать только проекты", + "FILTER_TYPE_PROJECTS_TITLE": "Показать только проекты", "FILTER_TYPE_EPICS": "Epics", - "FILTER_TYPE_EPIC_TITLES": "Show only epics", + "FILTER_TYPE_EPICS_TITLE": "Показывать только эпосы", "FILTER_TYPE_USER_STORIES": "Истории", - "FILTER_TYPE_USER_STORIES_TITLES": "Показывать только пользовательские истории", + "FILTER_TYPE_USER_STORIES_TITLE": "Показывать только пользовательские истории", "FILTER_TYPE_TASKS": "Задачи", - "FILTER_TYPE_TASK_TITLES": "Показывать только задачи", + "FILTER_TYPE_TASKS_TITLE": "Показывать только задачи", "FILTER_TYPE_ISSUES": "Запросы", "FILTER_TYPE_ISSUES_TITLE": "Показывать только запросы", "EMPTY_TITLE": "Похоже, здесь ничего нет." @@ -862,8 +793,6 @@ }, "PROJECT": { "PAGE_TITLE": "{{projectName}}", - "WELCOME": "Добро пожаловать", - "SECTION_PROJECTS": "Проекты", "HELP": "Реорганизуйте свои проекты так чтобы часто используемые были бы наверху.
Первые 10 проектов будут находится вверху списка проектов.", "PRIVATE": "Закрытый проект", "LOOKING_FOR_PEOPLE": "Этот проект ищет людей", @@ -875,12 +804,6 @@ "THIS_PROJECT_IS_BLOCKED": "Этот проект временно заблокирован", "TO_UNBLOCK_CONTACT_THE_ADMIN_STAFF": "In order to unblock your projects, contact the administrator." }, - "STATS": { - "PROJECT": "проекта
очки", - "DEFINED": "заданные
очки", - "ASSIGNED": "назначенные
очки", - "CLOSED": "закрытые
очки" - }, "SECTION": { "SEARCH": "Поиск", "TIMELINE": "График работ", @@ -893,15 +816,9 @@ "ADMIN": "Админка" }, "NAVIGATION": { - "SECTION_TITLE": "Ваши проекты", - "PLACEHOLDER_SEARCH": "Искать в...", "ACTION_CREATE_PROJECT": "Создать проект", - "ACTION_IMPORT_PROJECT": "Импортировать проект", "MANAGE_PROJECTS": "Управлять проектами", "TITLE_CREATE_PROJECT": "Создать проект", - "TITLE_IMPORT_PROJECT": "Импортировать проект", - "TITLE_PRVIOUS_PROJECT": "Показать предыдущие проекты", - "TITLE_NEXT_PROJECT": "Показать следующие проекты", "HELP_TITLE": "Страница поддержки Taiga", "HELP": "Помощь", "HOMEPAGE": "Домашняя страница", @@ -909,10 +826,6 @@ "FEEDBACK": "Обратная связь", "NOTIFICATIONS_TITLE": "Настроить уведомления", "NOTIFICATIONS": "Уведомления", - "ORGANIZATIONS_TITLE": "Редактировать Ваши организации", - "ORGANIZATIONS": "Настроить организации", - "SETTINGS_TITLE": "Редактировать настройки", - "SETTINGS": "Настройки", "VIEW_PROFILE_TITLE": "Посмотреть профиль", "VIEW_PROFILE": "Посмотреть профиль", "EDIT_PROFILE_TITLE": "Править свой профиль", @@ -921,14 +834,68 @@ "CHANGE_PASSWORD": "Изменить пароль", "DASHBOARD_TITLE": "Рабочий стол", "DISCOVER_TITLE": "Найти проекты в тренде", - "NEW_ITEM": "Новая", - "DISCOVER": "Найти", - "ACTION_REORDER": "Можно перетаскивать мышкой" + "DISCOVER": "Найти" + }, + "LIKE_BUTTON": { + "LIKE": "Мне нравится", + "LIKED": "Понравилось", + "UNLIKE": "Не нравится", + "BUTTON_TITLE": "Оценить проект", + "COUNTER_TITLE": "{total, plural, one{один фанат} other{# фаната (-ов)}}" + }, + "WATCH_BUTTON": { + "BUTTON_TITLE": "Отслеживать этот проект и настроить уведомления", + "WATCH": "Отслеживать", + "WATCHING": "Отслеживаемое", + "COUNTER_TITLE": "{total, plural, one{один наблюдатель} other{# наблюдателя (-ей)}}", + "OPTIONS": { + "NOTIFY_ALL": "Получать все уведомления", + "NOTIFY_ALL_TITLE": "Получать все уведомления для этого проекта", + "NOTIFY_INVOLVED": "Только вовлечённые", + "NOTIFY_INVOLVED_TITLE": "Получать уведомления только если вовлечён в работу", + "UNWATCH": "Прекратить отслеживание", + "UNWATCH_TITLE": "Прекратить отслеживание этого проекта" + } + }, + "CONTACT_BUTTON": { + "CONTACT_TITLE": "Contact the project team", + "CONTACT_BUTTON": "Contact the project" + }, + "CREATE": { + "TITLE": "Создать проект", + "CHOOSE_TEMPLATE": "Which template fits your project better?", + "TEMPLATE_SCRUM": "Scrum", + "TEMPLATE_SCRUM_DESC": "Prioritize and solve your tasks in short time cycles.", + "TEMPLATE_SCRUM_LONGDESC": "Scrum is an iterative and incremental agile software development methodology for managing product development.\nThe product backlog is what will ultimately be delivered, ordered into the sequence in which it should be delivered. Product Backlogs are broken into manageable, executable chunks named sprints. Every certain amount of time the team initiates a new sprint and commits to deliver a certain number of user stories from the backlog, in accordance with their skills, abilities and resources. The project advances as the backlog becomes depleted.", + "TEMPLATE_KANBAN": "Kanban", + "TEMPLATE_KANBAN_DESC": "Keep a constant workflow on independent tasks", + "TEMPLATE_KANBAN_LONGDESC": "The Kanban methodology is used to divide project development (any sort of project) into stages.\nA kanban card is like an index card or post-it note that details every task (or user story) in a project that needs to be completed. The Kanban board is used to move each card from one state of completion to the next and in so doing, helps track progress.", + "DUPLICATE": "Duplicate project", + "DUPLICATE_DESC": "Start clean and keep your configuration", + "IMPORT": "Импортировать проект", + "IMPORT_DESC": "Import your project from multiple platforms into Taiga", + "INVITE": "Invite to the project", + "SOLO_PROJECT": "You'll be alone in this project", + "INVITE_LATER": "(You'll be able to invite more members later)", + "BACK": "Бэкенд разработчик", + "MAX_PRIVATE_PROJECTS": "Unfortunately, You've reached the maximum number of private projects.\nIf you would like to increase the current limit please contact the administrator.", + "MAX_PUBLIC_PROJECTS": "Unfortunately, You've reached the maximum number of public projects.\nIf you would like to increase the current limit please contact the administrator.", + "PUBLIC_PROJECT": "Public Project", + "PRIVATE_PROJECT": "Частный проект" + }, + "COMMON": { + "DETAILS": "New project details", + "PROJECT_TITLE": "Project Name", + "PROJECT_DESCRIPTION": "Project Description" + }, + "DUPLICATE": { + "TITLE": "Duplicate Project", + "DESCRIPTION": "Start clean and keep your configuration", + "SELECT_PLACEHOLDER": "Choose an existing project to duplicate" }, "IMPORT": { - "TITLE": "Импорт проекта", - "UPLOADING_FILE": "Загрузить свалочный файл", - "DESCRIPTION": "Этот процесс может занять некоторое время. Пожалуйста, сохраняйте это окно открытым.", + "TITLE": "Import Project", + "DESCRIPTION": "Import your project from multiple platforms into Taiga", "ASYNC_IN_PROGRESS_TITLE": "Oompa Loompas импортирует ваш проект", "ASYNC_IN_PROGRESS_MESSAGE": "Этот процесс может занять несколько минут
Мы отправим вам email, когда всё будет готово", "UPLOAD_IN_PROGRESS_MESSAGE": "Загружено {{uploadedSize}} размера {{totalSize}}", @@ -937,8 +904,29 @@ "ERROR_MESSAGE": "У Oompa Loompas возникли проблемы при импорте резервной копии: {{error_message}}", "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) это слишком много для наших Умпа-Лумп, попробуйте еще раз с размером меньшим, чем ({{maxFileSize}})", "SYNC_SUCCESS": "Импорт проекта выполнен успешно", + "IMPORT": "Import", + "WHO_IS": "Their tasks will be assigned to ...", + "WRITE_EMAIL": "Or if you want, write the email that this user uses in Taiga", + "SEARCH_CONTACT": "Or if you want, search in your contacts", + "WRITE_EMAIL_LABEL": "Write the email that this user uses in Taiga", + "ACCEEDE": "Acceede", + "PROJECT_MEMBERS": "Участники проекта", + "PROCESS_DESCRIPTION": "Tell us who from Taiga you want to assign the tasks of {{platform}}", + "MATCH": "Is {{user_external}} the same person as {{user_internal}}?", + "CHOOSE": "Select user", + "LINKS": "Links with {{platform}}", + "LINKS_DESCRIPTION": "Do you want to keep the link of each item with the original {{platform}} card?", + "WARNING_MAIL_USER": "Note that if the user does not have a Taiga account we will not be able to assign the tasks to him.", + "ASSIGN": "Назначить", + "PROJECT_SELECTOR": { + "NO_RESULTS": "It looks like nothing was found with your search criteria", + "ACTION_SEARCH": "поиск", + "ACTION_BACK": "Бэкенд разработчик" + }, "PROJECT_RESTRICTIONS": { - "PROJECT_MEMBERS_DESC": "The project you are trying to import has {{members}} members, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per project. If you would like to increase that limit please contact the administrator.", + "PROJECT_MEMBERS_DESC_PRIVATE": "The project you are trying to import has {{members}} members including you, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per private project. If you would like to increase that limit please contact the administrator.", + "PROJECT_MEMBERS_DESC_PUBLIC": "The project you are trying to import has {{members}} members including you, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per public project. If you would like to increase that limit please contact the administrator.", + "ACCOUNT_ALLOW_MEMBERS": "Your account only allows {{members}} members", "PRIVATE_PROJECTS_SPACE": { "TITLE": "Unfortunately, your current plan does not allow for additional private projects", "DESC": "The project you are trying to import is private. Unfortunately, your current plan does not allow for additional private projects." @@ -961,39 +949,67 @@ "TITLE": "Unfortunately your current plan doesn't allow additional public projects or an increase of more than {{max_memberships}} members per public project", "DESC": "The project that you are trying to import is public and has more than {{members}} members." } - } - }, - "LIKE_BUTTON": { - "LIKE": "Мне нравится", - "LIKED": "Понравилось", - "UNLIKE": "Не нравится", - "BUTTON_TITLE": "Оценить проект", - "COUNTER_TITLE": "{total, plural, one{один фанат} other{# фаната (-ов)}}" - }, - "WATCH_BUTTON": { - "BUTTON_TITLE": "Отслеживать этот проект и настроить уведомления", - "WATCH": "Отслеживать", - "WATCHING": "Отслеживаемое", - "COUNTER_TITLE": "{total, plural, one{один наблюдатель} other{# наблюдателя (-ей)}}", - "OPTIONS": { - "NOTIFY_ALL": "Получать все уведомления", - "NOTIFY_ALL_TITLE": "Получать все уведомления для этого проекта", - "NOTIFY_INVOLVED": "Только вовлечённые", - "NOTIFY_INVOLVED_TITLE": "Получать уведомления только если вовлечён в работу", - "UNWATCH": "Прекратить отслеживание", - "UNWATCH_TITLE": "Прекратить отслеживание этого проекта" + }, + "IN_PROGRESS": { + "TITLE": "Импорт проекта", + "DESCRIPTION": "Этот процесс может занять некоторое время. Пожалуйста, сохраняйте это окно открытым." + }, + "WARNING": { + "TITLE": "Some taks will be unassigned", + "DESCRIPTION": "There are still unidentified people. The cards assigned to these people will remain unassigned. Check all the contacts to not lose that information.", + "CHECK": "Check contacts" + }, + "TAIGA": { + "SELECTOR": "Import your Taiga project" + }, + "TRELLO": { + "SELECTOR": "Import your Trello boards into Taiga", + "CHOOSE_PROJECT": "Choose board that you want to import", + "NO_PROJECTS": "It seems you have no boards in Trello" + }, + "GITHUB": { + "SELECTOR": "Import your GitHub project issues", + "CHOOSE_PROJECT": "Find the project you want to import", + "NO_PROJECTS": "It seems you have no porjects in GitHub", + "HOW_DO_YOU_WANT_TO_IMPORT": "How do you want to import your issues into Taiga?", + "KANBAN_PROJECT": "As user stories in a kanban project", + "KANBAN_PROJECT_DESCRIPTION": "After that you can enable scrum with backlog.", + "SCRUM_PROJECT": "As user stories in a scrum project", + "SCRUM_PROJECT_DESCRIPTION": "After that you can enable kanban mode.", + "ISSUES_PROJECT": "As issues", + "ISSUES_PROJECT_DESCRIPTION": "You will not be able to use your issues in kanban or scrum mode. You will be able to enable kanban or scrum for new user stories" + }, + "ASANA": { + "SELECTOR": "Import your Asana project and choose how to manage it", + "CHOOSE_PROJECT": "Choose project that you want to import", + "NO_PROJECTS": "It seems you have no porjects in Asana", + "KANBAN_PROJECT": "Kanban", + "SCRUM_PROJECT": "Scrum", + "CREATE_AS_SCRUM_DESCRIPTION": "The tasks and sub-tasks of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_KANBAN_DESCRIPTION": "The tasks and sub-tasks of your project will be created as Taiga user stories and tasks." + }, + "JIRA": { + "SELECTOR": "Import your Jira project and choose how to manage it", + "CHOOSE_PROJECT": "Choose project or board that you want to import", + "NO_PROJECTS": "It seems you have no porjects or boards in Jira", + "URL": "Your Jira URL", + "KANBAN_PROJECT": "Kanban", + "SCRUM_PROJECT": "Scrum", + "ISSUES_PROJECT": "Запросы", + "CREATE_AS_SCRUM_DESCRIPTION": "The issues and sub-issues of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_KANBAN_DESCRIPTION": "The issues and sub-issues of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_ISSUES_DESCRIPTION": "What do you want to do with sub-issues from the Jira project? (Taiga doesn't allow sub-issues)", + "CREATE_NEW_ISSUES": "Convert sub-issues to new Taiga issues", + "NOT_CREATE_NEW_ISSUES": "Do not import sub-issues" } } }, "LIGHTBOX": { "DELETE_ACCOUNT": { - "SECTION_NAME": "Удалить аккаунт", "CONFIRM": "Вы уверены, что хотите удалить ваш аккаунт?", - "NEWSLETTER_LABEL_TEXT": "Я больше не хочу получать вашу новостную рассылку", "CANCEL": "Вернуться к настройкам", "ACCEPT": "Удалить аккаунт", - "BLOCK_PROJECT": "Note that all the projects you own projects will be blocked after you delete your account. If you do want a project blocked, transfer ownership to another member of each project prior to deleting your account.", - "SUBTITLE": "Sorry to see you go. We'll be here if you should ever consider us again! :(" + "BLOCK_PROJECT": "Note that all the projects you own projects will be blocked after you delete your account. If you do want a project blocked, transfer ownership to another member of each project prior to deleting your account." }, "DELETE_PROJECT": { "TITLE": "Удалить проект", @@ -1007,6 +1023,12 @@ }, "ADD_MEMBER": { "TITLE": "Новый участник", + "PLACEHOLDER": "Filter users or write an email to invite", + "ADD_EMAIL": "Add email", + "REMOVE": "Remove", + "INVITE": "Invite", + "CHOOSE_ROLE": "Choose a role", + "PLACEHOLDER_INVITATION_TEXT": "(Необязательно) Добавьте персональный текст в приглашение. Скажите что-нибудь приятное вашим новым участникам ;-)", "HELP_TEXT": "Если пользователи уже зарегистрированы в Тайге они добавятся автоматически. В противном случае им будет отправлено приглашение." }, "CREATE_ISSUE": { @@ -1068,18 +1090,24 @@ "TITLE": "Кого вы хотите назначить новым владельцем проекта?", "ADD_COMMENT": "Добавить комментарий", "BUTTON": "Предложить участнику проекта стать его новым владельцем" + }, + "CONTACT_PROJECT": { + "TITLE": "Send an email to", + "WARNING": "The email will be received by the project admins", + "PLACEHOLDER": "Write your message", + "SEND": "Send" } }, "EPIC": { - "PAGE_TITLE": "{{epicSubject}} - Epic {{epicRef}} - {{projectName}}", - "PAGE_DESCRIPTION": "Status: {{epicStatus }}. Description: {{epicDescription}}", + "PAGE_TITLE": "{{epicSubject}} - Эпос {{epicRef}} - {{projectName}}", + "PAGE_DESCRIPTION": "Статус: {{epicStatus }}. Описание: {{epicDescription}}", "SECTION_NAME": "Epic", "TITLE_LIGHTBOX_UNLINK_RELATED_USERSTORY": "Unlink related userstory", "MSG_LIGHTBOX_UNLINK_RELATED_USERSTORY": "It will delete the link to the related userstory '{{subject}}'", "ERROR_UNLINK_RELATED_USERSTORY": "We have not been able to unlink: {{errorMessage}}", - "CREATE_RELATED_USERSTORIES": "Create a relationship with", + "CREATE_RELATED_USERSTORIES": "Создать связь с", "NEW_USERSTORY": "Новая пользовательская история", - "EXISTING_USERSTORY": "Existing user story", + "EXISTING_USERSTORY": "Существующая пользовательская история", "CHOOSE_PROJECT_FOR_CREATION": "What's the project?", "SUBJECT": "Тема", "SUBJECT_BULK_MODE": "Subject (bulk insert)", @@ -1088,7 +1116,7 @@ "NO_USERSTORIES": "This project has no User Stories yet. Please select another project.", "FILTER_USERSTORIES": "Filter user stories", "LIGHTBOX_TITLE_BLOKING_EPIC": "Blocking epic", - "ACTION_DELETE": "Delete epic" + "ACTION_DELETE": "Удалить эпос" }, "US": { "PAGE_TITLE": "{{userStorySubject}} - Пользовательская История {{userStoryRef}} - {{projectName}}", @@ -1101,15 +1129,9 @@ "ADD_BULK": "Добавить Пользовательские Истории пакетно", "PROMOTED": "Эта ПИ была сформирована из запроса:", "TITLE_LINK_GO_TO_ISSUE": "Перейти к запросу", - "EXTERNAL_REFERENCE": "Эта ПИ была создана из:", - "GO_TO_EXTERNAL_REFERENCE": "Перейти в начало", - "BLOCKED": "Эта пользовательская история заблокирована", "TITLE_DELETE_ACTION": "Удалить пользовательскую историю", "LIGHTBOX_TITLE_BLOKING_US": "Блокирующая ПИ", - "TASK_COMPLETED": "{{totalClosedTasks}}/{{totalTasks}} задач выполнено", - "ASSIGN": "Поручить пользовательскую историю", "NOT_ESTIMATED": "Не оценено", - "TOTAL_US_POINTS": "Всего очков за ПИ", "TRIBE": { "PUBLISH": "Publish as Gig in Taiga Tribe", "PUBLISH_INFO": "Больше инфо", @@ -1119,23 +1141,19 @@ "CLOSE": "Закрыть", "SYNCHRONIZE_LINK": "synchronize with Taiga Tribe", "PUBLISH_MORE_INFO_TITLE": "Do you need somebody for this task?", - "PUBLISH_MORE_INFO_TEXT": "

If you need help with a particular piece of work you can easily create gigs on Taiga Tribe and receive help from all over the world. You will be able to control and manage the gig enjoying a great community eager to contribute.

TaigaTribe was born as a Taiga sibling. Both platforms can live separately but we believe that there is much power in using them combined so we are making sure the integration works like a charm.

" + "PUBLISH_MORE_INFO_TEXT": "

If you need help with a particular piece of work you can easily create gigs on Taiga Tribe and receive help from all over the world. You will be able to control and manage the gig enjoying a great community eager to contribute.

TaigaTribe was born as a Taiga sibling. Both platforms can live separately but we believe that there is much power in using them combined so we are making sure the integration works like a charm.

" }, "FIELDS": { "TEAM_REQUIREMENT": "Требование от Команды", - "CLIENT_REQUIREMENT": "Требование клиента", - "FINISH_DATE": "Дата завершения" + "CLIENT_REQUIREMENT": "Требование клиента" } }, "COMMENTS": { "DELETED_INFO": "Комментарий удалён {{user}}", - "TITLE": "Комментарии", "COMMENTS_COUNT": "{{comments}} Comments", - "ORDER": "Порядок", "OLDER_FIRST": "Сначала старые", "RECENT_FIRST": "Сначала новые", "COMMENT": "Комментарий", - "EDIT_COMMENT": "Редактировать комментарий", "EDITED_COMMENT": "Изменено:", "SHOW_HISTORY": "View historic", "TYPE_NEW_COMMENT": "Добавить комментарий", @@ -1148,13 +1166,8 @@ } }, "ACTIVITY": { - "SHOW_ACTIVITY": "Показать действия", - "DATETIME": "DD MMM YYYY HH:mm", - "SHOW_MORE": "+ Показать предыдущие записи (ещё {{showMore}})", "TITLE": "Действия", "ACTIVITIES_COUNT": "{{activities}} Activities", - "REMOVED": "удален", - "ADDED": "добавлено", "TAGS_ADDED": "тэги добавлены:", "TAGS_REMOVED": "tags removed:", "US_POINTS": "{{role}} points", @@ -1163,50 +1176,21 @@ "UPDATED_ATTACHMENT": "updated attachment ({{filename}}):", "CREATED_CUSTOM_ATTRIBUTE": "created custom attribute", "UPDATED_CUSTOM_ATTRIBUTE": "updated custom attribute", - "SIZE_CHANGE": "Сделано {size, plural, one{изменение} other{# изменений}}", "BECAME_DEPRECATED": "became deprecated", "BECAME_UNDEPRECATED": "became undeprecated", "TEAM_REQUIREMENT": "Требование от Команды", "CLIENT_REQUIREMENT": "Требование клиента", "BLOCKED": "Заблокирован", "VALUES": { - "YES": "да", - "NO": "нет", - "EMPTY": "пусто", "UNASSIGNED": "нет ответственного" }, "FIELDS": { "SUBJECT": "название", - "NAME": "имя", "DESCRIPTION": "описание", - "CONTENT": "контент", "STATUS": "cтатус", - "IS_CLOSED": "закрыто", - "FINISH_DATE": "дата окончания", "TYPE": "тип", - "PRIORITY": "приоритет", - "SEVERITY": "важность", "ASSIGNED_TO": "назначено на", - "WATCHERS": "наблюдатели", "MILESTONE": "спринт", - "USER_STORY": "пользовательская история", - "PROJECT": "проект", - "IS_BLOCKED": "заблокирован", - "BLOCKED_NOTE": "Пояснение блокировки", - "POINTS": "очков", - "CLIENT_REQUIREMENT": "требование клиента", - "TEAM_REQUIREMENT": "требование команды", - "IS_IOCAINE": "- иокаин", - "TAGS": "тэги", - "ATTACHMENTS": "Вложения", - "IS_DEPRECATED": "рекомендовано", - "IS_NOT_DEPRECATED": "is not deprecated", - "ORDER": "порядок", - "BACKLOG_ORDER": "порядок списка задач", - "SPRINT_ORDER": "порядок спринтов", - "KANBAN_ORDER": "порядок kanban", - "TASKBOARD_ORDER": "порядок панели задач", - "US_ORDER": "порядок ПИ", "COLOR": "цвет" } }, @@ -1220,8 +1204,6 @@ "CUSTOMIZE_GRAPH_TITLE": "Настройте очки и спринты в админке", "MOVE_US_TO_CURRENT_SPRINT": "Перейти к текущему спринту", "MOVE_US_TO_LATEST_SPRINT": "Перейти к последнему спринту", - "SHOW_FILTERS": "Показать фильтры", - "SHOW_TAGS": "Показать теги", "EMPTY": "Список задач пуст!", "CREATE_NEW_US": "Создать новую ПИ", "CREATE_NEW_US_EMPTY_HELP": "Вы можете создать пользовательскую историю", @@ -1248,6 +1230,12 @@ "SHOW": "Показать теги", "HIDE": "Скрыть тэги" }, + "FORECASTING": { + "TITLE": "Velocity forecasting", + "BACKLOG": "Display backlog", + "NEW_SPRINT": "Candidate User Stories for your next sprint based on your velocity. Click to create a new sprint.", + "CURRENT_SPRINT": "Candidate User Stories for your sprint based on your velocity. Click to add to current sprint." + }, "TABLE": { "COLUMN_US": "Пользовательские Истории", "TITLE_COLUMN_POINTS": "Выберите вид для Роли" @@ -1255,9 +1243,9 @@ "SPRINT_SUMMARY": { "TOTAL_POINTS": "всего
очков", "COMPLETED_POINTS": "получено
очков", - "OPEN_TASKS": "открыть
задачи", + "OPEN_TASKS": "открытые
задачи", "CLOSED_TASKS": "завершённые
задачи", - "IOCAINE_DOSES": "иокаина
дозы", + "IOCAINE_DOSES": "дозы
иокаина", "SHOW_STATISTICS_TITLE": "Показать статистику", "TOGGLE_BAKLOG_GRAPH": "Показать/Скрыть график решения задач", "POINTS_PER_ROLE": "Points per role" @@ -1270,8 +1258,6 @@ }, "FILTERS": { "TOGGLE": "Переключить видимость фильтров", - "TITLE": "Фильтры", - "REMOVE": "Сбросить фильтры", "HIDE": "Спрятать фильтры", "SHOW": "Показать фильтры" }, @@ -1280,7 +1266,6 @@ "DATE": "DD MMM YYYY", "LINK_TASKBOARD": "Панель задач Спринта", "TITLE_LINK_TASKBOARD": "Перейти к Панели Задач \"{{name}}\"", - "NUMBER_SPRINTS": "
спринты", "EMPTY": "Спринтов пока что нет", "WARNING_EMPTY_SPRINT_ANONYMOUS": "У этого спринта нет пользовательских историй", "WARNING_EMPTY_SPRINT": "Накидайте сюда ПИ из списка задач чтобы начать новый спринт", @@ -1305,7 +1290,6 @@ "TITLE_ACTION_ADD": "Добавить новую Задачу", "TITLE_ACTION_ADD_BULK": "Добавить новые задачи пакетно", "TITLE_ACTION_ASSIGN": "Назначить задачу", - "TITLE_ACTION_EDIT": "Редактировать задачу", "PLACEHOLDER_CARD_TITLE": "Это может быть задачей", "PLACEHOLDER_CARD_TEXT": "Разделяйте ПИ в задачи чтобы отслеживать их по отдельности", "TABLE": { @@ -1335,17 +1319,11 @@ "TITLE_SELECT_STATUS": "Статус", "OWNER_US": "Эта задача принадлежит:", "TITLE_LINK_GO_OWNER": "Перейти к пользовательской истории", - "ORIGIN_US": "Эта задача была создана из", - "TITLE_LINK_GO_ORIGIN": "Перейти к пользовательской истории", - "BLOCKED": "Эта задача заблокирована", "TITLE_DELETE_ACTION": "Удалить задачу", "LIGHTBOX_TITLE_BLOKING_TASK": "Блокирующее задание", "FIELDS": { - "MILESTONE": "Спринт", - "USER_STORY": "Пользовательская история", "IS_IOCAINE": "- иокаин" }, - "ACTION_IOCAINE": "иокаин", "TITLE_ACTION_IOCAINE": "Чувствуете, что задание берет верх над вами? Дайте другим знать об этом, нажав на \"Иокаин\", когда редактируете задание. Возможно стать неуязвимым к этому (выдуманному) смертельном яду, потребляя небольшие количества время от времени, так же как возможно стать лучше в том, что вы делаете, временами беря на себя дополнительные препятствия!" }, "NOTIFICATION": { @@ -1374,14 +1352,12 @@ "ISSUES": { "PAGE_TITLE": "Запросы - {{projectName}}", "PAGE_DESCRIPTION": "Панель запросов проекта {{projectName}}: {{projectDescription}}", - "LIST_SECTION_NAME": "Запросы", "SECTION_NAME": "Запрос", "ACTION_NEW_ISSUE": "+НОВЫЙ ЗАПРОС", "ACTION_PROMOTE_TO_US": "Повысить до пользовательской истории", "PROMOTED": "Этот запрос был переделан в ПИ:", "EXTERNAL_REFERENCE": "Этот запрос был создан из", "GO_TO_EXTERNAL_REFERENCE": "Перейти в начало", - "BLOCKED": "Этот запрос заблокирована", "ACTION_DELETE": "Удалить запрос", "LIGHTBOX_TITLE_BLOKING_ISSUE": "Блокирующий запрос", "FIELDS": { @@ -1423,15 +1399,11 @@ "SECTION_NAME": "Kanban", "TITLE_ACTION_FOLD": "Свернуть колонку", "TITLE_ACTION_UNFOLD": "Развернуть колонку", - "TITLE_ACTION_FOLD_CARDS": "Свернуть карточки", - "TITLE_ACTION_UNFOLD_CARDS": "Развернуть карточки", "TITLE_ACTION_ADD_US": "Добавить Пользовательскую Историю", "TITLE_ACTION_ADD_BULK": "Добавить пакетно", "ACTION_SHOW_ARCHIVED": "Показать архивные", "ACTION_HIDE_ARCHIVED": "Спрятать архив", "HIDDEN_USER_STORIES": "Пользовательские истории в этом статусе скрыты по умолчанию", - "ARCHIVED": "Вы заархивировали", - "UNDO_ARCHIVED": "Для отмены надо перетащить и сбросить ещё раз", "PLACEHOLDER_CARD_TITLE": "Это - ваши Пользовательские Истории.", "PLACEHOLDER_CARD_TEXT": "У ПИ также могут быть подзадачи чтобы можно было разделять требования" }, @@ -1452,7 +1424,6 @@ "PAGE_TITLE": "Команда - {{projectName}}", "PAGE_DESCRIPTION": "Панель команды показывает всех участников проекта {{projectName}}: {{projectDescription}}", "SECTION_NAME": "Команда", - "APP_TITLE": "КОМАНДА - {{projectName}}", "PLACEHOLDER_INPUT_SEARCH": "Искать по имени", "COLUMN_MR_WOLF": "Мр. Вульф", "EXPLANATION_COLUMN_MR_WOLF": "Закрытые запросы", @@ -1488,18 +1459,9 @@ "OPTION_ALL": "Все", "OPTION_INVOLVED": "Вовлечен", "OPTION_NONE": "Нет" - }, - "POPOVER": { - "USER_PROFILE": "Профиль пользователя", - "CHANGE_PASSWORD": "Изменить пароль", - "NOTIFICATIONS": "Уведомления", - "FEEDBACK": "Обратная связь", - "TITLE_AVATAR": "Настройки пользователя" } }, "USER_PROFILE": { - "IMAGE_HELP": "Изображение будет отмасштабировано до 80x80px.", - "ACTION_CHANGE_IMAGE": "Изменить", "ACTION_USE_GRAVATAR": "Использовать картинку по умолчанию", "ACTION_DELETE_ACCOUNT": "Удалить аккаунт", "CHANGE_EMAIL_SUCCESS": "Проверьте входящие письма!
Мы послали письмо на ваш аккаунт
с инструкциями по установке вашего нового адреса.", @@ -1517,25 +1479,10 @@ "THEME_DEFAULT": "-- использовать тему по умолчанию --" } }, - "WIZARD": { - "SECTION_TITLE_CREATE_PROJECT": "Создать проект", - "CREATE_PROJECT_TEXT": "Свежий и чистый! Так здóрово!", - "CHOOSE_TEMPLATE": "Which template fits your project best?", - "CHOOSE_TEMPLATE_TITLE": "More info about project templates", - "CHOOSE_TEMPLATE_INFO": "Больше инфо", - "PROJECT_DETAILS": "Project Details", - "PUBLIC_PROJECT": "Public Project", - "PRIVATE_PROJECT": "Частный проект", - "CREATE_PROJECT": "Создать проект", - "MAX_PRIVATE_PROJECTS": "You've reached the maximum number of private projects", - "MAX_PUBLIC_PROJECTS": "Unfortunately, you've reached the maximum number of public projects", - "CHANGE_PLANS": "change plans" - }, "WIKI": { "PAGE_TITLE": "{{wikiPageName}} - Вики - {{projectName}}", "PAGE_DESCRIPTION": "Последнее редактирование: {{lastModifiedDate}} ({{totalEditions}} - всего правок) Контент: {{ wikiPageContent }}", "DATETIME": "DD MMM YYYY HH:mm", - "PLACEHOLDER_PAGE": "Создать вики страницу", "REMOVE": "Удалить эту вики страницу", "DELETE_LIGHTBOX_TITLE": "Удалить вики страницу", "DELETE_LINK_TITLE": "Удалить ссылку wiki", @@ -1543,7 +1490,7 @@ "HOME": "Главная страница", "SECTION_NAME": "ЗАКЛАДКИ", "ACTION_ADD_LINK": "Добавить закладку", - "ALL_PAGES": "All wiki pages" + "ALL_PAGES": "Все wiki-страницы" }, "SUMMARY": { "TIMES_EDITED": "раз
отредактировано", @@ -1693,7 +1640,6 @@ "MOST_LIKED": "Больше всего лайков", "MOST_LIKED_EMPTY": "There are no LIKED projects yet", "VIEW_MORE": "Показать больше", - "RECRUITING": "Этот проект ищет людей", "FEATURED": "Популярные проекты", "EMPTY": "Нету проектов, удовлетворяющих заданным критериям поиска.
Попробуйте снова!", "FILTERS": { diff --git a/app/locales/taiga/locale-sv.json b/app/locales/taiga/locale-sv.json index 8419f1cf..d38f9e0f 100644 --- a/app/locales/taiga/locale-sv.json +++ b/app/locales/taiga/locale-sv.json @@ -4,7 +4,6 @@ "NO": "Nej", "OR": "eller", "LOADING": "Laddar...", - "LOADING_PROJECT": "Laddar projekt...", "DATE": "YYYY-MM-DD", "DATETIME": "YYYY-MM-DD HH:mm", "SAVE": "Spara", @@ -27,21 +26,18 @@ "BLOCKED_NOTE": "Varför är denna blockerad?", "BLOCKED_REASON": "Vänligen förklara orsaken", "CREATED_BY": "Skapad av {{fullDisplayName}}", - "FROM": "från", - "TO": "till ", "CLOSE": "stäng", "GO_HOME": "Ta mig hem", "PLUGINS": "Insticksprogram", - "BETA": "Vi betatestar!", "ONE_ITEM_LINE": "En post per rad ...", "NEW_BULK": "Lägg till flera nya", "RELATED_TASKS": "Besläktade uppgifter", - "PREVIOUS": "Previous", + "PREVIOUS": "Föregående", "NEXT": "Nästa", "LOGOUT": "Logga ut", "EXTERNAL_USER": "en extern användare", "GENERIC_ERROR": "En av våra Oompa Loompier säger {{error}}.", - "IOCAINE_TEXT": "Känner du dig lite bortkommen med en uppgift? Försäkra dig om att andra känner till uppgiften när du klickar på Iocaine-knappen när du ändrar uppgiften. Det är möjligt att bli immun till det här (påhittade) dödliga giftet om du tar små mängder över tid - och du kan även så småningom om bli bättre på vad du gör när du då och då tar på dig större utmaningar!", + "IOCAINE_TEXT": "This member is feeling a bit overwhelmed by this task. Will become immune to the iocaine poison over time with your help. For now, may need a hug.", "CLIENT_REQUIREMENT": "Client requirement is new requirement that was not previously expected and it is required to be part of the project", "TEAM_REQUIREMENT": "Team requirement is a requirement that must exist in the project but should have no cost for the client", "OWNER": "Project Owner", @@ -148,7 +144,6 @@ "PRIORITY": "Prioritet", "ASSIGNED_TO": "Tilldelad till", "POINTS": "Poäng", - "BLOCKED_NOTE": "blockerad notering", "IS_BLOCKED": "är blockerad", "REF": "Ref. ", "VOTES": "Röster", @@ -187,10 +182,6 @@ "COUNTER_TITLE": "{total, plural, one{one watcher} other{# watchers}}" }, "VOTE_BUTTON": { - "UPVOTE": "Rösta för", - "UPVOTED": "Rösta för", - "DOWNVOTE": "Rösta emot", - "VOTERS": "Röstande", "BUTTON_TITLE": "Rösta för / Rösta emot den här posten", "COUNTER_TITLE": "{total, plural, one{one vote} other{# votes}}" }, @@ -202,10 +193,9 @@ "CONFIRM_DELETE": "Remeber that all values in this custom field will be deleted.\n Are you sure you want to continue?" }, "FILTERS": { - "TITLE": "Filter", "INPUT_PLACEHOLDER": "Titel eller referens", "TITLE_ACTION_FILTER_BUTTON": "sök", - "INPUT_SEARCH_PLACEHOLDER": "Titel eller referens", + "TITLE": "Filter", "TITLE_ACTION_SEARCH": "Sök", "ACTION_SAVE_CUSTOM_FILTER": "spara som anpassad filter", "PLACEHOLDER_FILTER_NAME": "Skriv filternamnet och tryck på ", @@ -220,41 +210,10 @@ "CREATED_BY": "Skapad av", "CUSTOM_FILTERS": "Anpassad filter", "EPIC": "Epost" - }, - "CONFIRM_DELETE": { - "TITLE": "Ta bort anpassad filter.", - "MESSAGE": "anpassad filter '{{customFilterName}}'" } }, "WYSIWYG": { - "H1_BUTTON": "Första nivån snart klar", - "H1_SAMPLE_TEXT": "Din titel här", - "H2_BUTTON": "Andra nivåns rubrik", - "H2_SAMPLE_TEXT": "Din titel här", - "H3_BUTTON": "Tredje nivåns rubrik", - "H3_SAMPLE_TEXT": "Din titel här", - "BOLD_BUTTON": "Fet", - "BOLD_BUTTON_SAMPLE_TEXT": "Din text här", - "ITALIC_BUTTON": "Kursiv", - "ITALIC_SAMPLE_TEXT": "Din text här", - "STRIKE_BUTTON": "Slag", - "STRIKE_SAMPLE_TEXT": "Din text här", - "BULLETED_LIST_BUTTON": "Punktlista", - "BULLETED_LIST_SAMPLE_TEXT": "Din text här", - "NUMERIC_LIST_BUTTON": "Numrerad lista", - "NUMERIC_LIST_SAMPLE_TEXT": "Din text här", - "PICTURE_BUTTON": "Bild", - "PICTURE_SAMPLE_TEXT": "Din alternativa text till bilden här ...", - "LINK_BUTTON": "Länk", - "LINK_SAMPLE_TEXT": "Din text till länken här ...", - "QUOTE_BLOCK_BUTTON": "Citatblock", - "QUOTE_BLOCK_SAMPLE_TEXT": "Din text här", - "CODE_BLOCK_BUTTON": "Kodblock", - "CODE_BLOCK_SAMPLE_TEXT": "Din text här", - "PREVIEW_BUTTON": "Förhandsvisa", - "EDIT_BUTTON": "Redigera", - "ATTACH_FILE_HELP": "Attach files by dragging & dropping on the textarea above.", - "ATTACH_FILE_HELP_SAVE_FIRST": "Save first before if you want to attach files by dragging & dropping on the textarea above.", + "OUTDATED": "Another person has made changes while you were editing. Check the new version on the activiy tab before you save your changes.", "MARKDOWN_HELP": "Hjälp för markeringssyntax" }, "PERMISIONS_CATEGORIES": { @@ -307,10 +266,6 @@ "ADD_WIKI_LINKS": "Lägg till wiki-länkar", "DELETE_WIKI_LINKS": "Ta bort wiki-länkar" } - }, - "META": { - "PAGE_TITLE": "Taiga", - "PAGE_DESCRIPTION": "Taiga är ett projekthanteringsverktyg för nystartade företag och agila utvecklings- och designteam som behöver enkla, vackra verktyg som det är trevligt att jobba med. " } }, "LOGIN": { @@ -366,7 +321,6 @@ }, "CHANGE_PASSWORD": { "PAGE_TITLE": "Byt ditt lösenord - Taiga", - "PAGE_DESCRIPTION": "Skapa ett nytt lösenord för din Taiga-konto och hej! du kanske behöver äta något järnrik kost. Det är bra för hjärnan. :P", "SECTION_NAME": "Byt lösenord", "FIELD_CURRENT_PASSWORD": "Befintligt lösenord", "PLACEHOLDER_CURRENT_PASSWORD": "Ditt nuvarande lösenord (eller tomt om du inte har något lösenord än)", @@ -391,8 +345,7 @@ }, "INVITATION_LOGIN_FORM": { "NOT_FOUND": "Våra Oompa Loompier kan inte hitta din invitation.", - "SUCCESS": "Du har nu blitt medlem i det här projektet. Välkommen till {{project_name}}", - "ERROR": "Enligt våra Oompa Loompier är du inte registrerad än eller ditt lösenord är fel. " + "SUCCESS": "Du har nu blitt medlem i det här projektet. Välkommen till {{project_name}}" }, "HOME": { "PAGE_TITLE": "Hem - Taiga", @@ -463,10 +416,7 @@ "TITLE_LIGHTBOX_DELETE_ATTACHMENT": "Ta bort bilagan ...", "MSG_LIGHTBOX_DELETE_ATTACHMENT": "bifogad '{{fileName}}'", "ERROR_DELETE_ATTACHMENT": "Vi klarade inte att ta bort: {{errorMessage}}", - "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) är för tungt för våra Oompa Loompier. Försök med något mindre än ({{maxFileSize}})", - "FIELDS": { - "IS_DEPRECATED": "undviks" - } + "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) är för tungt för våra Oompa Loompier. Försök med något mindre än ({{maxFileSize}})" }, "PAGINATION": { "PREVIOUS": "Förra", @@ -502,13 +452,10 @@ "ASYNC_MESSAGE": "Vi vill skicka dig ett e-postmeddelande när vi är klara.", "SYNC_MESSAGE": "Om hämtningen inte startar automatiskt, klick här.", "ERROR": "Våra Oompa Loompier har vissa problemer med att skapa din hämtningsfil. Vänligen försök på nytt!", - "ERROR_BUSY": "Beklagar. Våra oompa loompier är mycket upptagna. Vänligen försök på nytt om några minuter. ", - "ERROR_MESSAGE": "Våra Oompa Loompier har vissa problem med att skapa din hämtfil: {{message}}" + "ERROR_BUSY": "Beklagar. Våra oompa loompier är mycket upptagna. Vänligen försök på nytt om några minuter. " }, "MODULES": { "TITLE": "Moduler", - "ENABLE": "Aktivera", - "DISABLE": "Avvaktivera", "EPICS": "Epos", "EPICS_DESCRIPTION": "Visualisera och hantera den mest strategiska delen av ditt projekt", "BACKLOG": "Inkorg", @@ -537,17 +484,16 @@ "PAGE_TITLE": "{{sectionName}} - Projektprofil - {{projectName}}", "PROJECT_DETAILS": "Projektdetaljer", "PROJECT_NAME": "Projektnamn", - "PROJECT_SLUG": "Projektslugg", "TAGS": "Etiketter", "DESCRIPTION": "Beskrivning", "RECRUITING": "Letar detta projekt efter personer? ", "RECRUITING_MESSAGE": "Vem letar du efter?", "RECRUITING_PLACEHOLDER": "Definiera profilerna du letar efter", + "FEEDBACK": "Receive feedback from Taiga users?", "PUBLIC_PROJECT": "Publika projekt", "PRIVATE_PROJECT": "Privata projekt", "PRIVATE_OR_PUBLIC": "Vad är skillnaden mellan publika och privata projekt?", "DELETE": "Ta bort projekt", - "LOGO_HELP": "Bilden kommer skalas till 80x80px.", "CHANGE_LOGO": "Ändra logga", "ACTION_USE_DEFAULT_LOGO": "Use default image", "MAX_PRIVATE_PROJECTS": "You've reached the maximum number of private projects allowed by your current plan", @@ -595,6 +541,7 @@ "ISSUE_DESCRIPTION": "Anpassade fält för ärenden", "ISSUE_ADD": "Anpassade fält för ärenden", "FIELD_TYPE_TEXT": "Text", + "FIELD_TYPE_RICHTEXT": "Rich text", "FIELD_TYPE_MULTI": "Flerradig", "FIELD_TYPE_DATE": "Datum", "FIELD_TYPE_URL": "Url" @@ -623,9 +570,9 @@ "ACTION_ADD": "Lägg till ny allvarlighetsgrad" }, "PROJECT_VALUES_STATUS": { - "TITLE": "Status", + "TITLE": "Statuses", "SUBTITLE": "Specificera status för dina användarhistorier, uppgifter och ärenden ska ha i olika faser. ", - "EPIC_TITLE": "Epic Statuses", + "EPIC_TITLE": "Status för Epics", "US_TITLE": "User Story Statuses", "TASK_TITLE": "Status för uppgifter", "ISSUE_TITLE": "Status för ärenden" @@ -676,8 +623,8 @@ "INFO_VERIFYING_IP": "Gitlab-förfrågningar är inte signerade. Det bästa är att kontrollera ursprunglig IP-adress. Om fältet är tomt vill det inte bli någon IP-kontroll." }, "GITHUB": { - "SECTION_NAME": "Github", - "PAGE_TITLE": "Github - {{projectName}}" + "SECTION_NAME": "GitHub", + "PAGE_TITLE": "GitHub - {{projectName}}" }, "GOGS": { "SECTION_NAME": "Gogs", @@ -686,7 +633,6 @@ "WEBHOOKS": { "PAGE_TITLE": "Webbkrok - {{projectName}}", "SECTION_NAME": "Webbkrokar", - "SUBTITLE": "Webbkrokar notifierar externa tjänster om händelser i Taiga, till exempel kommentarer, användarhistorier ...", "ADD_NEW": "Lägg till en ny Webbkrok", "TYPE_NAME": "Skriv in tjänstens namn", "TYPE_PAYLOAD_URL": "Skriv in länken till tjänsten", @@ -732,7 +678,6 @@ "DELETE_MEMBER": "Ta bort medlem", "RESEND": "Skicka på nytt", "SUCCESS_SEND_INVITATION": "Vi har skickat på nytt invitationen till '{{email}}'.", - "ERROR_SEND_INVITATION": "Vi har inte skickat invitationen", "SUCCESS_DELETE": "Vi har tagit bort {{message}}.", "ERROR_DELETE": "Vi har inte lyckats att ta bort {{message}}.", "DEFAULT_DELETE_MESSAGE": "den här invitationen till {{email}}" @@ -761,16 +706,11 @@ "PLACEHOLDER_WRITE_NAME": "Skriv ett namn för den nya statusen" }, "MENU": { - "TITLE": "Administrator", "PROJECT": "Projekt", "ATTRIBUTES": "Egenskaper", "MEMBERS": "Medlemmar", "PERMISSIONS": "Behörigheter", - "INTEGRATIONS": "Integrationer", - "PLUGINS": "Insticksprogram" - }, - "SUBMENU_PROJECT_ATTRIBUTES": { - "TITLE": "Egenskaper" + "INTEGRATIONS": "Integrationer" }, "SUBMENU_PROJECT_VALUES": { "STATUS": "Status", @@ -781,17 +721,11 @@ "CUSTOM_FIELDS": "Anpassade fält", "TAGS": "Etiketter" }, - "SUBMENU_PROJECT_PROFILE": { - "TITLE": "Projektprofil" - }, "SUBMENU_ROLES": { "TITLE": "Roller", "ACTION_NEW_ROLE": "+ Ny roll", "TITLE_ACTION_NEW_ROLE": "Lägg till ny roll" }, - "SUBMENU_THIDPARTIES": { - "TITLE": "Tjänster" - }, "PROJECT_TRANSFER": { "DO_YOU_ACCEPT_PROJECT_OWNERNSHIP": "Would you like to become the new project owner?", "PRIVATE": "Privat", @@ -806,15 +740,13 @@ "PRIVATE": "Please remember that you can own up to {{maxProjects}} private projects. You currently own {{currentProjects}} private projects", "PUBLIC": "Please remember that you can own up to {{maxProjects}} public projects. You currently own {{currentProjects}} public projects" }, - "CANT_BE_OWNED": "At the moment you cannot become an owner of a project of this type. If you would like to become the owner of this project, please contact the administrator so they change your account settings to enable project ownership.", - "CHANGE_MY_PLAN": "Ändra min plan" + "CANT_BE_OWNED": "At the moment you cannot become an owner of a project of this type. If you would like to become the owner of this project, please contact the administrator so they change your account settings to enable project ownership." } }, "USER": { "PROFILE": { "PAGE_TITLE": "{{userFullName}} (@{{userUsername}})", "EDIT": "Ändra profil", - "FOLLOW": "Följ", "CLOSED_US": "Stängd US", "PROJECTS": "Projekt", "PROJECTS_EMPTY": "{{username}} har inga projekt än", @@ -822,7 +754,6 @@ "CONTACTS_EMPTY": "{{username}} har inte några kontakter än", "CURRENT_USER_CONTACTS_EMPTY": "Du har inga kontakter än", "CURRENT_USER_CONTACTS_EMPTY_EXPLAIN": "De du arbetar med på Taiga vill automatiskt bli dina kontakter. ", - "REPORT": "Rapportera misbruk", "TABS": { "ACTIVITY_TAB": "Tidslinje", "ACTIVITY_TAB_TITLE": "Visa alla aktiviteter för den här användaren", @@ -848,13 +779,13 @@ "FILTER_TYPE_ALL": "Alla", "FILTER_TYPE_ALL_TITLE": "Visa alla", "FILTER_TYPE_PROJECTS": "Projekt", - "FILTER_TYPE_PROJECT_TITLES": "Visa bara projekt", + "FILTER_TYPE_PROJECTS_TITLE": "Visa bara projekt", "FILTER_TYPE_EPICS": "Epos", - "FILTER_TYPE_EPIC_TITLES": "Visa endast epos", + "FILTER_TYPE_EPICS_TITLE": "Visa endast epos", "FILTER_TYPE_USER_STORIES": "Berättelser", - "FILTER_TYPE_USER_STORIES_TITLES": "Visa endast användarhistorier", + "FILTER_TYPE_USER_STORIES_TITLE": "Visa endast användarhistorier", "FILTER_TYPE_TASKS": "Uppgift", - "FILTER_TYPE_TASK_TITLES": "Visar endast uppgifter", + "FILTER_TYPE_TASKS_TITLE": "Visar endast uppgifter", "FILTER_TYPE_ISSUES": "Ärenden", "FILTER_TYPE_ISSUES_TITLE": "Visa bara ärenden ", "EMPTY_TITLE": "Det verkar som om vi inte har något att visa just nu" @@ -862,8 +793,6 @@ }, "PROJECT": { "PAGE_TITLE": "{{projectName}}", - "WELCOME": "Välkommen", - "SECTION_PROJECTS": "Projekt", "HELP": "Organisera dina projekt och sätt in de mest använda här.
De första 10 toppprojekten vill visas i toppnavigeringens projektlista. ", "PRIVATE": "Privata projekt", "LOOKING_FOR_PEOPLE": "Detta projekt söker efter fler personer", @@ -875,12 +804,6 @@ "THIS_PROJECT_IS_BLOCKED": "Detta projekt är tillfälligt blockerat", "TO_UNBLOCK_CONTACT_THE_ADMIN_STAFF": "Kontakta administratören för att avblockera dina projekt." }, - "STATS": { - "PROJECT": "projekt
poäng", - "DEFINED": "definierad
poäng", - "ASSIGNED": "tilldelad
poäng", - "CLOSED": "stängd
poäng" - }, "SECTION": { "SEARCH": "Sök", "TIMELINE": "Tidslinje", @@ -893,15 +816,9 @@ "ADMIN": "Administrator" }, "NAVIGATION": { - "SECTION_TITLE": "Dina projekt", - "PLACEHOLDER_SEARCH": "Sök i ...", "ACTION_CREATE_PROJECT": "Skapa projekt", - "ACTION_IMPORT_PROJECT": "Importerar projekt", "MANAGE_PROJECTS": "Hantera projekt", "TITLE_CREATE_PROJECT": "Skapa projekt", - "TITLE_IMPORT_PROJECT": "Importerar projekt", - "TITLE_PRVIOUS_PROJECT": "Visa tidigare projekt", - "TITLE_NEXT_PROJECT": "Visa nästa projekt", "HELP_TITLE": "Taiga hjälpsida", "HELP": "Hjälp", "HOMEPAGE": "Webbplats", @@ -909,10 +826,6 @@ "FEEDBACK": "Återkoppling", "NOTIFICATIONS_TITLE": "Ändra inställningar för dina notifieringar", "NOTIFICATIONS": "Notifieringar", - "ORGANIZATIONS_TITLE": "Ändra dina organisationer", - "ORGANIZATIONS": "Ändra organizationer", - "SETTINGS_TITLE": "Ändra inställningarna", - "SETTINGS": "Inställningar", "VIEW_PROFILE_TITLE": "Visa profil", "VIEW_PROFILE": "Visa profil", "EDIT_PROFILE_TITLE": "Ändra din profil", @@ -921,14 +834,68 @@ "CHANGE_PASSWORD": "Byt lösenord", "DASHBOARD_TITLE": "Instrumentpanel", "DISCOVER_TITLE": "Upptäck nya rörliga projekt", - "NEW_ITEM": "Ny", - "DISCOVER": "Upptäck", - "ACTION_REORDER": "Dra & släpp för att sortera" + "DISCOVER": "Upptäck" + }, + "LIKE_BUTTON": { + "LIKE": "Gillar", + "LIKED": "Likte", + "UNLIKE": "Ogillar", + "BUTTON_TITLE": "Gilla eller ogilla projektet", + "COUNTER_TITLE": "{total, plural, one{one fan} other{# fans}}" + }, + "WATCH_BUTTON": { + "BUTTON_TITLE": "Visa projektet och lägg till egenskaper för avisering", + "WATCH": "Visa", + "WATCHING": "Bevakar", + "COUNTER_TITLE": "{total, plural, en{one watcher} other{# watchers}}", + "OPTIONS": { + "NOTIFY_ALL": "Motta alla notifieringar", + "NOTIFY_ALL_TITLE": "Motta alla notifieringar för det här projektet", + "NOTIFY_INVOLVED": "Endast involverad", + "NOTIFY_INVOLVED_TITLE": "Motta notifieringar bara när du är involverad", + "UNWATCH": "Frånkoppla visning", + "UNWATCH_TITLE": "Visa inte projektet" + } + }, + "CONTACT_BUTTON": { + "CONTACT_TITLE": "Contact the project team", + "CONTACT_BUTTON": "Kontakta projektet" + }, + "CREATE": { + "TITLE": "Skapa projekt", + "CHOOSE_TEMPLATE": "Which template fits your project better?", + "TEMPLATE_SCRUM": "Scrum", + "TEMPLATE_SCRUM_DESC": "Prioritize and solve your tasks in short time cycles.", + "TEMPLATE_SCRUM_LONGDESC": "Scrum is an iterative and incremental agile software development methodology for managing product development.\nThe product backlog is what will ultimately be delivered, ordered into the sequence in which it should be delivered. Product Backlogs are broken into manageable, executable chunks named sprints. Every certain amount of time the team initiates a new sprint and commits to deliver a certain number of user stories from the backlog, in accordance with their skills, abilities and resources. The project advances as the backlog becomes depleted.", + "TEMPLATE_KANBAN": "Kanban", + "TEMPLATE_KANBAN_DESC": "Keep a constant workflow on independent tasks", + "TEMPLATE_KANBAN_LONGDESC": "The Kanban methodology is used to divide project development (any sort of project) into stages.\nA kanban card is like an index card or post-it note that details every task (or user story) in a project that needs to be completed. The Kanban board is used to move each card from one state of completion to the next and in so doing, helps track progress.", + "DUPLICATE": "Duplicate project", + "DUPLICATE_DESC": "Start clean and keep your configuration", + "IMPORT": "Importerar projekt", + "IMPORT_DESC": "Import your project from multiple platforms into Taiga", + "INVITE": "Invite to the project", + "SOLO_PROJECT": "You'll be alone in this project", + "INVITE_LATER": "(You'll be able to invite more members later)", + "BACK": "Baksida", + "MAX_PRIVATE_PROJECTS": "Unfortunately, You've reached the maximum number of private projects.\nIf you would like to increase the current limit please contact the administrator.", + "MAX_PUBLIC_PROJECTS": "Unfortunately, You've reached the maximum number of public projects.\nIf you would like to increase the current limit please contact the administrator.", + "PUBLIC_PROJECT": "Public Project", + "PRIVATE_PROJECT": "Privat Projekt" + }, + "COMMON": { + "DETAILS": "New project details", + "PROJECT_TITLE": "Project Name", + "PROJECT_DESCRIPTION": "Project Description" + }, + "DUPLICATE": { + "TITLE": "Duplicate Project", + "DESCRIPTION": "Start clean and keep your configuration", + "SELECT_PLACEHOLDER": "Choose an existing project to duplicate" }, "IMPORT": { - "TITLE": "Importerar projekt", - "UPLOADING_FILE": "Ladda hämtningsfilen", - "DESCRIPTION": "Den här processen kan ta en liten stund, vänligen försök med fönstret öppet. ", + "TITLE": "Import Project", + "DESCRIPTION": "Import your project from multiple platforms into Taiga", "ASYNC_IN_PROGRESS_TITLE": "Våra Oompa Loompier importerar ditt projekt", "ASYNC_IN_PROGRESS_MESSAGE": "Den här processen kan ta några minuter
. Vi vill skicka dig en e-post när det blir klart. ", "UPLOAD_IN_PROGRESS_MESSAGE": "Laddat upp {{uploadedSize}} av {{totalSize}}", @@ -937,8 +904,29 @@ "ERROR_MESSAGE": "Våra Oompa Loompier har lite problem med att importera dina hämtningsdata: {{error_message}}", "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) är för tungt för våra Oompa Loompier. Försök med något mindre än ({{maxFileSize}})", "SYNC_SUCCESS": "Ditt projekt är korrekt importerad", + "IMPORT": "Import", + "WHO_IS": "Their tasks will be assigned to ...", + "WRITE_EMAIL": "Or if you want, write the email that this user uses in Taiga", + "SEARCH_CONTACT": "Or if you want, search in your contacts", + "WRITE_EMAIL_LABEL": "Write the email that this user uses in Taiga", + "ACCEEDE": "Acceede", + "PROJECT_MEMBERS": "Project Members", + "PROCESS_DESCRIPTION": "Tell us who from Taiga you want to assign the tasks of {{platform}}", + "MATCH": "Is {{user_external}} the same person as {{user_internal}}?", + "CHOOSE": "Select user", + "LINKS": "Links with {{platform}}", + "LINKS_DESCRIPTION": "Do you want to keep the link of each item with the original {{platform}} card?", + "WARNING_MAIL_USER": "Note that if the user does not have a Taiga account we will not be able to assign the tasks to him.", + "ASSIGN": "Tilldela", + "PROJECT_SELECTOR": { + "NO_RESULTS": "It looks like nothing was found with your search criteria", + "ACTION_SEARCH": "sök", + "ACTION_BACK": "Baksida" + }, "PROJECT_RESTRICTIONS": { - "PROJECT_MEMBERS_DESC": "The project you are trying to import has {{members}} members, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per project. If you would like to increase that limit please contact the administrator.", + "PROJECT_MEMBERS_DESC_PRIVATE": "The project you are trying to import has {{members}} members including you, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per private project. If you would like to increase that limit please contact the administrator.", + "PROJECT_MEMBERS_DESC_PUBLIC": "The project you are trying to import has {{members}} members including you, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per public project. If you would like to increase that limit please contact the administrator.", + "ACCOUNT_ALLOW_MEMBERS": "Your account only allows {{members}} members", "PRIVATE_PROJECTS_SPACE": { "TITLE": "Unfortunately, your current plan does not allow for additional private projects", "DESC": "The project you are trying to import is private. Unfortunately, your current plan does not allow for additional private projects." @@ -961,39 +949,67 @@ "TITLE": "Unfortunately your current plan doesn't allow additional public projects or an increase of more than {{max_memberships}} members per public project", "DESC": "The project that you are trying to import is public and has more than {{members}} members." } - } - }, - "LIKE_BUTTON": { - "LIKE": "Gillar", - "LIKED": "Likte", - "UNLIKE": "Ogillar", - "BUTTON_TITLE": "Gilla eller ogilla projektet", - "COUNTER_TITLE": "{total, plural, one{one fan} other{# fans}}" - }, - "WATCH_BUTTON": { - "BUTTON_TITLE": "Visa projektet och lägg till egenskaper för avisering", - "WATCH": "Visa", - "WATCHING": "Bevakar", - "COUNTER_TITLE": "{total, plural, en{one watcher} other{# watchers}}", - "OPTIONS": { - "NOTIFY_ALL": "Motta alla notifieringar", - "NOTIFY_ALL_TITLE": "Motta alla notifieringar för det här projektet", - "NOTIFY_INVOLVED": "Endast involverad", - "NOTIFY_INVOLVED_TITLE": "Motta notifieringar bara när du är involverad", - "UNWATCH": "Frånkoppla visning", - "UNWATCH_TITLE": "Visa inte projektet" + }, + "IN_PROGRESS": { + "TITLE": "Importerar projekt", + "DESCRIPTION": "Den här processen kan ta en liten stund, vänligen försök med fönstret öppet. " + }, + "WARNING": { + "TITLE": "Some taks will be unassigned", + "DESCRIPTION": "There are still unidentified people. The cards assigned to these people will remain unassigned. Check all the contacts to not lose that information.", + "CHECK": "Check contacts" + }, + "TAIGA": { + "SELECTOR": "Import your Taiga project" + }, + "TRELLO": { + "SELECTOR": "Import your Trello boards into Taiga", + "CHOOSE_PROJECT": "Choose board that you want to import", + "NO_PROJECTS": "It seems you have no boards in Trello" + }, + "GITHUB": { + "SELECTOR": "Import your GitHub project issues", + "CHOOSE_PROJECT": "Find the project you want to import", + "NO_PROJECTS": "It seems you have no porjects in GitHub", + "HOW_DO_YOU_WANT_TO_IMPORT": "How do you want to import your issues into Taiga?", + "KANBAN_PROJECT": "As user stories in a kanban project", + "KANBAN_PROJECT_DESCRIPTION": "After that you can enable scrum with backlog.", + "SCRUM_PROJECT": "As user stories in a scrum project", + "SCRUM_PROJECT_DESCRIPTION": "After that you can enable kanban mode.", + "ISSUES_PROJECT": "As issues", + "ISSUES_PROJECT_DESCRIPTION": "You will not be able to use your issues in kanban or scrum mode. You will be able to enable kanban or scrum for new user stories" + }, + "ASANA": { + "SELECTOR": "Import your Asana project and choose how to manage it", + "CHOOSE_PROJECT": "Choose project that you want to import", + "NO_PROJECTS": "It seems you have no porjects in Asana", + "KANBAN_PROJECT": "Kanban", + "SCRUM_PROJECT": "Scrum", + "CREATE_AS_SCRUM_DESCRIPTION": "The tasks and sub-tasks of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_KANBAN_DESCRIPTION": "The tasks and sub-tasks of your project will be created as Taiga user stories and tasks." + }, + "JIRA": { + "SELECTOR": "Import your Jira project and choose how to manage it", + "CHOOSE_PROJECT": "Choose project or board that you want to import", + "NO_PROJECTS": "It seems you have no porjects or boards in Jira", + "URL": "Your Jira URL", + "KANBAN_PROJECT": "Kanban", + "SCRUM_PROJECT": "Scrum", + "ISSUES_PROJECT": "Frågor", + "CREATE_AS_SCRUM_DESCRIPTION": "The issues and sub-issues of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_KANBAN_DESCRIPTION": "The issues and sub-issues of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_ISSUES_DESCRIPTION": "What do you want to do with sub-issues from the Jira project? (Taiga doesn't allow sub-issues)", + "CREATE_NEW_ISSUES": "Convert sub-issues to new Taiga issues", + "NOT_CREATE_NEW_ISSUES": "Do not import sub-issues" } } }, "LIGHTBOX": { "DELETE_ACCOUNT": { - "SECTION_NAME": "Ta bort konto", "CONFIRM": "Är du säker på att du vill radera kontot?", - "NEWSLETTER_LABEL_TEXT": "Jag vill inte motta flera nyhetsbrev", "CANCEL": "Tillbaka till inställningar", "ACCEPT": "Ta bort konto", - "BLOCK_PROJECT": "Notera att alla projekt du äger kommer bli blockerade efter att du raderar ditt konto. Om du vill blockera ett projekt, överför ägandet till en annan medlem för respektive projekt innan du raderar ditt konto. ", - "SUBTITLE": "Vad tråkigt att du lämnar. Vi kommer finnas här om du någonsin skulle överväga oss igen! :(" + "BLOCK_PROJECT": "Notera att alla projekt du äger kommer bli blockerade efter att du raderar ditt konto. Om du vill blockera ett projekt, överför ägandet till en annan medlem för respektive projekt innan du raderar ditt konto. " }, "DELETE_PROJECT": { "TITLE": "Ta bort projekt", @@ -1007,6 +1023,12 @@ }, "ADD_MEMBER": { "TITLE": "Ny medlem", + "PLACEHOLDER": "Filter users or write an email to invite", + "ADD_EMAIL": "Add email", + "REMOVE": "Remove", + "INVITE": "Invite", + "CHOOSE_ROLE": "Choose a role", + "PLACEHOLDER_INVITATION_TEXT": "(Valfritt) Lägg till en personlig hälsning till invitationen. Berätta något trevligt till din nya projektmedlem ;-)", "HELP_TEXT": "Om användaren redan är registrerad på Taiga vill hen bli lagt till automatiskt. I annat fall vill de motta en invitation. " }, "CREATE_ISSUE": { @@ -1057,7 +1079,7 @@ "TITLE": "Unfortunately, this project can't be left without an owner", "CURRENT_USER_OWNER": { "DESC": "You are the current owner of this project. Before leaving, please transfer ownership to someone else.", - "BUTTON": "Change the project owner" + "BUTTON": "Ändra projektägaren" }, "OTHER_USER_OWNER": { "DESC": "Unfortunately, you can't delete a member who is also the current project owner. First, please assign a new project owner.", @@ -1068,6 +1090,12 @@ "TITLE": "Who do you want to be the new project owner?", "ADD_COMMENT": "Lägg till kommentar", "BUTTON": "Ask this project member to become the new project owner" + }, + "CONTACT_PROJECT": { + "TITLE": "Skicka ett e-postmeddelande till", + "WARNING": "The email will be received by the project admins", + "PLACEHOLDER": "Skriv ditt meddelande", + "SEND": "Send" } }, "EPIC": { @@ -1101,15 +1129,9 @@ "ADD_BULK": "Lägg till flera nya användarhistorier", "PROMOTED": "Denna US har blivit flyttat från ärende: ", "TITLE_LINK_GO_TO_ISSUE": "Gå till ärende", - "EXTERNAL_REFERENCE": "Denna användarhistorien är skapat från", - "GO_TO_EXTERNAL_REFERENCE": "Gå till början", - "BLOCKED": "Användarhistorien är blockerad", "TITLE_DELETE_ACTION": "Ta bort användarhistorien", "LIGHTBOX_TITLE_BLOKING_US": "Blockera oss", - "TASK_COMPLETED": "{{totalClosedTasks}}/{{totalTasks}} uppgifter kompletta", - "ASSIGN": "Lägg till användarhistorie", "NOT_ESTIMATED": "Ej beräknad", - "TOTAL_US_POINTS": "Total US-poäng", "TRIBE": { "PUBLISH": "Publish as Gig in Taiga Tribe", "PUBLISH_INFO": "More info", @@ -1119,25 +1141,21 @@ "CLOSE": "Stäng", "SYNCHRONIZE_LINK": "synkronisera med Taiga Tribe", "PUBLISH_MORE_INFO_TITLE": "Behöver du någon för den här uppgiften?", - "PUBLISH_MORE_INFO_TEXT": "

If you need help with a particular piece of work you can easily create gigs on Taiga Tribe and receive help from all over the world. You will be able to control and manage the gig enjoying a great community eager to contribute.

TaigaTribe was born as a Taiga sibling. Both platforms can live separately but we believe that there is much power in using them combined so we are making sure the integration works like a charm.

" + "PUBLISH_MORE_INFO_TEXT": "

If you need help with a particular piece of work you can easily create gigs on Taiga Tribe and receive help from all over the world. You will be able to control and manage the gig enjoying a great community eager to contribute.

TaigaTribe was born as a Taiga sibling. Both platforms can live separately but we believe that there is much power in using them combined so we are making sure the integration works like a charm.

" }, "FIELDS": { "TEAM_REQUIREMENT": "Teamets behov", - "CLIENT_REQUIREMENT": "Kräver beställare", - "FINISH_DATE": "Färdig datum" + "CLIENT_REQUIREMENT": "Kräver beställare" } }, "COMMENTS": { "DELETED_INFO": "Kommentar raderad av {{user}}", - "TITLE": "Kommentarer", "COMMENTS_COUNT": "{{comments}} Kommentarer", - "ORDER": "Sortera", "OLDER_FIRST": "Äldre först", "RECENT_FIRST": "Senast först", "COMMENT": "Kommentarer", - "EDIT_COMMENT": "Redigera kommentar", "EDITED_COMMENT": "Redigerad:", - "SHOW_HISTORY": "View historic", + "SHOW_HISTORY": "Se historik", "TYPE_NEW_COMMENT": "Skriv en ny kommentar här", "SHOW_DELETED": "Visa raderade kommentarer", "HIDE_DELETED": "Dölj raderade kommentarer", @@ -1148,13 +1166,8 @@ } }, "ACTIVITY": { - "SHOW_ACTIVITY": "Visa aktiviteter", - "DATETIME": "YYYY-MM-DD HH:mm", - "SHOW_MORE": "+ Visa tidigare poster ({{showMore}} more)", "TITLE": "Aktiviteter", "ACTIVITIES_COUNT": "{{activities}} Aktiviteter", - "REMOVED": "borttaget", - "ADDED": "lagt till", "TAGS_ADDED": "taggar tillagda", "TAGS_REMOVED": "tags removed:", "US_POINTS": "{{role}} points", @@ -1163,50 +1176,21 @@ "UPDATED_ATTACHMENT": "updated attachment ({{filename}}):", "CREATED_CUSTOM_ATTRIBUTE": "created custom attribute", "UPDATED_CUSTOM_ATTRIBUTE": "updated custom attribute", - "SIZE_CHANGE": "Gjorde {size, plural, one{one change} other{# changes}}", "BECAME_DEPRECATED": "became deprecated", "BECAME_UNDEPRECATED": "became undeprecated", "TEAM_REQUIREMENT": "Teamets behov", "CLIENT_REQUIREMENT": "Kräver beställare", "BLOCKED": "Blockerad", "VALUES": { - "YES": "ja", - "NO": "nej", - "EMPTY": "tom", "UNASSIGNED": "otilldelad" }, "FIELDS": { "SUBJECT": "titel", - "NAME": "namn", "DESCRIPTION": "beskrivning", - "CONTENT": "innehåll", "STATUS": "status", - "IS_CLOSED": "är stängd", - "FINISH_DATE": "färdig datum", "TYPE": "typ", - "PRIORITY": "prioritet", - "SEVERITY": "Allvarsgrad", "ASSIGNED_TO": "tilldelad till", - "WATCHERS": "bevakare", "MILESTONE": "sprint", - "USER_STORY": "Användarhistorie", - "PROJECT": "projekt", - "IS_BLOCKED": "är blockerad", - "BLOCKED_NOTE": "blockerad notering", - "POINTS": "poäng", - "CLIENT_REQUIREMENT": "kräver beställare", - "TEAM_REQUIREMENT": "krav arbetsgrupp", - "IS_IOCAINE": "är Iocaine", - "TAGS": "etiketter", - "ATTACHMENTS": "bilagor", - "IS_DEPRECATED": "undviks", - "IS_NOT_DEPRECATED": "is not deprecated", - "ORDER": "sortera", - "BACKLOG_ORDER": "sortera inkorgen", - "SPRINT_ORDER": "sortera sprintar", - "KANBAN_ORDER": "kanban-sortering", - "TASKBOARD_ORDER": "Sortera uppgiftstavlan", - "US_ORDER": "sortera US", "COLOR": "färg" } }, @@ -1220,8 +1204,6 @@ "CUSTOMIZE_GRAPH_TITLE": "Lägg till poäng och sprintar via Administratorn", "MOVE_US_TO_CURRENT_SPRINT": "Flytta till nuvarande sprint", "MOVE_US_TO_LATEST_SPRINT": "Move to latest Sprint", - "SHOW_FILTERS": "Visa filter", - "SHOW_TAGS": "Visa etiketter", "EMPTY": "Inkorgen är tom!", "CREATE_NEW_US": "Skapa en ny US", "CREATE_NEW_US_EMPTY_HELP": "Du kanske vill skapa en ny användarhistorie", @@ -1248,6 +1230,12 @@ "SHOW": "Visa etiketter", "HIDE": "Dölj etiketter" }, + "FORECASTING": { + "TITLE": "Velocity forecasting", + "BACKLOG": "Display backlog", + "NEW_SPRINT": "Candidate User Stories for your next sprint based on your velocity. Click to create a new sprint.", + "CURRENT_SPRINT": "Candidate User Stories for your sprint based on your velocity. Click to add to current sprint." + }, "TABLE": { "COLUMN_US": "Användarhistorie", "TITLE_COLUMN_POINTS": "Välj visning per roll" @@ -1270,8 +1258,6 @@ }, "FILTERS": { "TOGGLE": "Växla filtrens synlighet", - "TITLE": "Filter", - "REMOVE": "Ta bort filter", "HIDE": "Dölj filter", "SHOW": "Visa filter" }, @@ -1280,7 +1266,6 @@ "DATE": "YYYY-MM-DD", "LINK_TASKBOARD": "Sprint uppgiftspanel", "TITLE_LINK_TASKBOARD": "Gå till uppgiftspanelen för \"{{name}}\"", - "NUMBER_SPRINTS": "
sprintar\n", "EMPTY": "Det är inga sprintar än", "WARNING_EMPTY_SPRINT_ANONYMOUS": "Den här sprinten har inga användarhistorier", "WARNING_EMPTY_SPRINT": "Här kan du föra in användarhistorier från inkorgen för att starta en ny sprint", @@ -1305,7 +1290,6 @@ "TITLE_ACTION_ADD": "Lägg till en ny uppgift", "TITLE_ACTION_ADD_BULK": "Lägg till några flera nya uppgifter", "TITLE_ACTION_ASSIGN": "Tilldela uppgift", - "TITLE_ACTION_EDIT": "Ändra uppgiften", "PLACEHOLDER_CARD_TITLE": "Det har kan vara en uppgift", "PLACEHOLDER_CARD_TEXT": "Dela användarhistorier upp i uppgifter och spåra dem separat", "TABLE": { @@ -1335,17 +1319,11 @@ "TITLE_SELECT_STATUS": "Status namn", "OWNER_US": "Den här uppgiften tillhör", "TITLE_LINK_GO_OWNER": "Gå till användarhistorie", - "ORIGIN_US": "Den här uppgiften är skapad från", - "TITLE_LINK_GO_ORIGIN": "Gå till användarhistorie", - "BLOCKED": "Uppgiften är blockerad", "TITLE_DELETE_ACTION": "Ta bort uppgift", "LIGHTBOX_TITLE_BLOKING_TASK": "Blockerad uppgift", "FIELDS": { - "MILESTONE": "Sprint", - "USER_STORY": "Användarhistorie", "IS_IOCAINE": "Är iocaine" }, - "ACTION_IOCAINE": "Iocaine", "TITLE_ACTION_IOCAINE": "Känner du dig lite bortkommen med en uppgift? Försäkra dig om att andra känner till uppgiften när du klickar på Iocaine-knappen när du ändrar uppgiften. Det är möjligt att bli immun till det här (påhittade) dödliga giftet om du tar små mängder över tid - och du kan även så småningom om bli bättre på vad du gör när du då och då tar på dig större utmaningar!" }, "NOTIFICATION": { @@ -1374,14 +1352,12 @@ "ISSUES": { "PAGE_TITLE": "Ärenden - {{projectName}}", "PAGE_DESCRIPTION": "Ärenden som listas för projektet {{projectName}}: {{projectDescription}}", - "LIST_SECTION_NAME": "Ärenden", "SECTION_NAME": "ärende", "ACTION_NEW_ISSUE": "+ NYTT ÄRENDE", "ACTION_PROMOTE_TO_US": "Flytta till användarhistorie", "PROMOTED": "Ärendet har flyttats till US:", "EXTERNAL_REFERENCE": "Den här uppgiften är skapat från", "GO_TO_EXTERNAL_REFERENCE": "Gå till början", - "BLOCKED": "Det här ärendet är blockerad", "ACTION_DELETE": "Ta bort ärende", "LIGHTBOX_TITLE_BLOKING_ISSUE": "Blockerad ärende", "FIELDS": { @@ -1423,15 +1399,11 @@ "SECTION_NAME": "Kanban", "TITLE_ACTION_FOLD": "Vika i hop kolumnen", "TITLE_ACTION_UNFOLD": "Veckla ut kolumnen", - "TITLE_ACTION_FOLD_CARDS": "Vika ut kortet", - "TITLE_ACTION_UNFOLD_CARDS": "Vika ut korten", "TITLE_ACTION_ADD_US": "Lägg till ny användarhistorie", "TITLE_ACTION_ADD_BULK": "Lägg till flera nya", "ACTION_SHOW_ARCHIVED": "Visa arkiverad", "ACTION_HIDE_ARCHIVED": "Dölj arkiverad", "HIDDEN_USER_STORIES": "Användarhistorien för den här statusen är dolt som standard", - "ARCHIVED": "Du har arkiverad", - "UNDO_ARCHIVED": "Dra & släpp på nytt för att göra om", "PLACEHOLDER_CARD_TITLE": "Detta är dina användarhistorier", "PLACEHOLDER_CARD_TEXT": "Användarhistorier behöver även underuppgifter för att separera kraven." }, @@ -1452,7 +1424,6 @@ "PAGE_TITLE": "Team - {{projectName}}", "PAGE_DESCRIPTION": "Panelen för arbetsgrupper visar alla medlemmar i projektet {{projectName}}: {{projectDescription}}", "SECTION_NAME": "Arbetsgrupp", - "APP_TITLE": "Arbetsgrupp - {{projectName}}", "PLACEHOLDER_INPUT_SEARCH": "Sök på hela namnet ...", "COLUMN_MR_WOLF": "Herr Hansson", "EXPLANATION_COLUMN_MR_WOLF": "Stängda ärenden", @@ -1488,18 +1459,9 @@ "OPTION_ALL": "Alla", "OPTION_INVOLVED": "Involverad", "OPTION_NONE": "Ingen" - }, - "POPOVER": { - "USER_PROFILE": "Användarprofil", - "CHANGE_PASSWORD": "Ändra lösenord", - "NOTIFICATIONS": "Notifieringar", - "FEEDBACK": "Återkoppling", - "TITLE_AVATAR": "Inställningar för användare" } }, "USER_PROFILE": { - "IMAGE_HELP": "Bilden kommer skalas till 80x80px.", - "ACTION_CHANGE_IMAGE": "Ändra", "ACTION_USE_GRAVATAR": "Use default image", "ACTION_DELETE_ACCOUNT": "Ta bort Taiga-kontot", "CHANGE_EMAIL_SUCCESS": "Kontrollera din inbox!
Vi har skickad dig ett e-postmeddelande
med instruktioner för hur du sätter upp din nya adress", @@ -1517,25 +1479,10 @@ "THEME_DEFAULT": "-- använd standardtema --" } }, - "WIZARD": { - "SECTION_TITLE_CREATE_PROJECT": "Skapa projekt", - "CREATE_PROJECT_TEXT": "Fräscht och rent. Så trevligt!", - "CHOOSE_TEMPLATE": "Which template fits your project best?", - "CHOOSE_TEMPLATE_TITLE": "More info about project templates", - "CHOOSE_TEMPLATE_INFO": "More info", - "PROJECT_DETAILS": "Project Details", - "PUBLIC_PROJECT": "Public Project", - "PRIVATE_PROJECT": "Privat Projekt", - "CREATE_PROJECT": "Skapa projekt", - "MAX_PRIVATE_PROJECTS": "You've reached the maximum number of private projects", - "MAX_PUBLIC_PROJECTS": "Unfortunately, you've reached the maximum number of public projects", - "CHANGE_PLANS": "change plans" - }, "WIKI": { "PAGE_TITLE": "{{wikiPageName}} - Wiki - {{projectName}}", "PAGE_DESCRIPTION": "Senaste ändringar utförd {{lastModifiedDate}} ({{totalEditions}} editions in total) Innehållt: {{ wikiPageContent }}", "DATETIME": "YYYY-MM-DD HH:mm", - "PLACEHOLDER_PAGE": "Skriv din wiki-sida", "REMOVE": "Ta bort den här wiki-sidan", "DELETE_LIGHTBOX_TITLE": "Ta bort Wiki-sida", "DELETE_LINK_TITLE": "Ta bort wiki-länk", @@ -1693,7 +1640,6 @@ "MOST_LIKED": "Most liked", "MOST_LIKED_EMPTY": "There are no LIKED projects yet", "VIEW_MORE": "View more", - "RECRUITING": "Detta projekt söker efter personer", "FEATURED": "Featured Projects", "EMPTY": "There are no projects to show with this search criteria.
Try again!", "FILTERS": { diff --git a/app/locales/taiga/locale-tr.json b/app/locales/taiga/locale-tr.json index 0d981ca4..012e6255 100644 --- a/app/locales/taiga/locale-tr.json +++ b/app/locales/taiga/locale-tr.json @@ -4,7 +4,6 @@ "NO": "Hayır", "OR": "veya", "LOADING": "Yükleniyor...", - "LOADING_PROJECT": "Proje yükleniyor...", "DATE": "DD MM YYYY", "DATETIME": "DD MM YYYY HH:mm", "SAVE": "Kaydet", @@ -27,12 +26,9 @@ "BLOCKED_NOTE": "Bu niye engelli?", "BLOCKED_REASON": "Lütfen sebebini açıklayın", "CREATED_BY": "{{fullDisplayName}} tarafından oluşturuldu", - "FROM": "den", - "TO": "kime", "CLOSE": "kapat", "GO_HOME": "Ana sayfaya götür beni", "PLUGINS": "Eklentiler", - "BETA": "Betadayız!", "ONE_ITEM_LINE": "Her satıra bir kalem...", "NEW_BULK": "Yeni toplu ekleme", "RELATED_TASKS": "İlişkili görevler", @@ -41,7 +37,7 @@ "LOGOUT": "Çıkış", "EXTERNAL_USER": "bir dış kullanıcı", "GENERIC_ERROR": "Honki ponkilerimizden biri derki; {{error}}.", - "IOCAINE_TEXT": "Bir görev size ağır geldi ve bunaldınız mı? Diğerlerinin bu durumdan haberi olması için bir görevi düzenlerken baldıran zehrinin üzerine tıklayın. Nasıl ki zaman zaman ekstra meydan okumalarla bir işte gittikce iyi olmanız mümkünse, zaman içerisinde küçük dozlar alarak bu ölümcül zehre de bağışıklık kazanabilmek mümkün!", + "IOCAINE_TEXT": "This member is feeling a bit overwhelmed by this task. Will become immune to the iocaine poison over time with your help. For now, may need a hug.", "CLIENT_REQUIREMENT": "Müşteri gereksinimi, daha önceden belli olmayan ama projeye dahil olması gereken bir gereksinimdir", "TEAM_REQUIREMENT": "Takım gereksinimi, müsteriyi ilgilendirmeyen, ama projede yer alması zorunlu olan bir gereksinimdir.", "OWNER": "Project Owner", @@ -148,7 +144,6 @@ "PRIORITY": "Öncelik", "ASSIGNED_TO": "Atanmış", "POINTS": "Puanlar", - "BLOCKED_NOTE": "engel notu", "IS_BLOCKED": "engellendi ", "REF": "Ref", "VOTES": "Oylar", @@ -187,10 +182,6 @@ "COUNTER_TITLE": "{total, plural, one{bir takipçi} other{# takipçi}}" }, "VOTE_BUTTON": { - "UPVOTE": "Oy ver", - "UPVOTED": "Oy verildi", - "DOWNVOTE": "Karşı oy ver", - "VOTERS": "Oylayıcılar", "BUTTON_TITLE": "Bu konuya oy/karşı oy ver", "COUNTER_TITLE": "{total, plural, one{bir oy} other{# oy}}" }, @@ -202,10 +193,9 @@ "CONFIRM_DELETE": "Bu özel alandaki tüm bilgiler silinecek.\nDevam etmek istediğinize emin misiniz?" }, "FILTERS": { - "TITLE": "Filtreler", "INPUT_PLACEHOLDER": "Konu yada referans", "TITLE_ACTION_FILTER_BUTTON": "ara", - "INPUT_SEARCH_PLACEHOLDER": "Konu ya da ref", + "TITLE": "Filtreler", "TITLE_ACTION_SEARCH": "Ara", "ACTION_SAVE_CUSTOM_FILTER": "özel filtre olarak kaydet", "PLACEHOLDER_FILTER_NAME": "Filtre adı yazın ve enter a basın", @@ -220,41 +210,10 @@ "CREATED_BY": "Oluşturan", "CUSTOM_FILTERS": "Özel filtreler", "EPIC": "Epic" - }, - "CONFIRM_DELETE": { - "TITLE": "Özel filtre sil", - "MESSAGE": "'{{customFilterName}}' özel filtresi" } }, "WYSIWYG": { - "H1_BUTTON": "İlk Düzey Başlık", - "H1_SAMPLE_TEXT": "Başlığınız...", - "H2_BUTTON": "İkinci Düzey Başlık", - "H2_SAMPLE_TEXT": "Başlığınız...", - "H3_BUTTON": "Üçüncü Düzey Başlık", - "H3_SAMPLE_TEXT": "Başlığınız...", - "BOLD_BUTTON": "Kalın", - "BOLD_BUTTON_SAMPLE_TEXT": "Yazınız buraya...", - "ITALIC_BUTTON": "Eğik", - "ITALIC_SAMPLE_TEXT": "Yazınız buraya...", - "STRIKE_BUTTON": "Üstünü çiz", - "STRIKE_SAMPLE_TEXT": "Yazınız buraya..", - "BULLETED_LIST_BUTTON": "Maddeler", - "BULLETED_LIST_SAMPLE_TEXT": "Yazınız buraya...", - "NUMERIC_LIST_BUTTON": "Sayısal Liste", - "NUMERIC_LIST_SAMPLE_TEXT": "Yazınız buraya..", - "PICTURE_BUTTON": "Resim", - "PICTURE_SAMPLE_TEXT": "Resminize alternatif yazıyı buraya...", - "LINK_BUTTON": "Bağlantı", - "LINK_SAMPLE_TEXT": "Bağlantınız...", - "QUOTE_BLOCK_BUTTON": "Alıntı Bloku", - "QUOTE_BLOCK_SAMPLE_TEXT": "Metni buraya yazın...", - "CODE_BLOCK_BUTTON": "Kod Bloğu", - "CODE_BLOCK_SAMPLE_TEXT": "Yazınız buraya..", - "PREVIEW_BUTTON": "Ön izleme", - "EDIT_BUTTON": "Düzenle", - "ATTACH_FILE_HELP": "Attach files by dragging & dropping on the textarea above.", - "ATTACH_FILE_HELP_SAVE_FIRST": "Save first before if you want to attach files by dragging & dropping on the textarea above.", + "OUTDATED": "Another person has made changes while you were editing. Check the new version on the activiy tab before you save your changes.", "MARKDOWN_HELP": "Markdown yazım kılavuzu" }, "PERMISIONS_CATEGORIES": { @@ -307,10 +266,6 @@ "ADD_WIKI_LINKS": "Wiki bağlantıları ekle", "DELETE_WIKI_LINKS": "Wiki bağlantılarını sil" } - }, - "META": { - "PAGE_TITLE": "Taiga", - "PAGE_DESCRIPTION": "Taiga; yeni girişimciler, çevik geliştiriciler ve tasarımcılar için çalışmaları gerçekten eğlenceli hale getiren basit, güzel bir proje yönetim platformudur." } }, "LOGIN": { @@ -366,7 +321,6 @@ }, "CHANGE_PASSWORD": { "PAGE_TITLE": "Parolayı değiştirin - Taiga", - "PAGE_DESCRIPTION": "Taiga hesabınız için yeni bir parola belirleyin, ha bir de, bol demirli besinlere yönelmek isteyebilirisiniz belki, beyine iyi gelir :P", "SECTION_NAME": "Parolayı değiştir", "FIELD_CURRENT_PASSWORD": "Şimdiki parola", "PLACEHOLDER_CURRENT_PASSWORD": "Şimdiki parolanız (boş da olabilir eger parola belirlemediyseniz)", @@ -391,8 +345,7 @@ }, "INVITATION_LOGIN_FORM": { "NOT_FOUND": "Umpa Lumpalarımız davetiyenize ulaşamıyor.", - "SUCCESS": "Projeye katılımınız başarıyla gerçekleşti. {{project_name}} 'ye hoş geldiniz.", - "ERROR": "Honki ponkilerimize göre, ya henüz kayıtlı değilsiniz ya da gerçersiz bir parola girdiniz" + "SUCCESS": "Projeye katılımınız başarıyla gerçekleşti. {{project_name}} 'ye hoş geldiniz." }, "HOME": { "PAGE_TITLE": "AnaSayfa - Taiga", @@ -463,10 +416,7 @@ "TITLE_LIGHTBOX_DELETE_ATTACHMENT": "Ek sil", "MSG_LIGHTBOX_DELETE_ATTACHMENT": "ek '{{fileName}}'", "ERROR_DELETE_ATTACHMENT": "Silemiyoruz: {{errorMessage}}", - "ERROR_MAX_SIZE_EXCEEDED": "({{fileSize}}) boyutundaki '{{fileName}}' dosya honki ponkilerimiz için oldukça ağır geldi, ({{maxFileSize}}) boyutundan daha küçük bir şeylerle deneyin", - "FIELDS": { - "IS_DEPRECATED": "kaldırıldı" - } + "ERROR_MAX_SIZE_EXCEEDED": "({{fileSize}}) boyutundaki '{{fileName}}' dosya honki ponkilerimiz için oldukça ağır geldi, ({{maxFileSize}}) boyutundan daha küçük bir şeylerle deneyin" }, "PAGINATION": { "PREVIOUS": "Önceki", @@ -502,13 +452,10 @@ "ASYNC_MESSAGE": "Hazır olduğunda size bir e-posta göndereceğiz.", "SYNC_MESSAGE": "Eğer indirme otomatik olarak başlamıyor ise buraya tıklayın.", "ERROR": "Bizim Honki ponkiler döküm dosyasını oluştururken birkaç hata ile karşılaştı. Lütfen yeniden deneyin.", - "ERROR_BUSY": "Üzgünüz, bizim honki ponkiler şu anda çok meşgul. Lütfen bir kaç dakika içinde yeniden deneyin.", - "ERROR_MESSAGE": "Honki ponkiler döküm dosyanızı oluştururken birkaç problem yaşadı: {{message}}" + "ERROR_BUSY": "Üzgünüz, bizim honki ponkiler şu anda çok meşgul. Lütfen bir kaç dakika içinde yeniden deneyin." }, "MODULES": { "TITLE": "Modüller", - "ENABLE": "Etkinleştir", - "DISABLE": "Pasifleştir", "EPICS": "Epics", "EPICS_DESCRIPTION": "Visualize and manage the most strategic part of your project", "BACKLOG": "Havuz", @@ -537,17 +484,16 @@ "PAGE_TITLE": "{{sectionName}} - Proje profili- {{projectName}}", "PROJECT_DETAILS": "Proje detayları", "PROJECT_NAME": "Proje adı", - "PROJECT_SLUG": "Proje satırı", "TAGS": "Etiketler", "DESCRIPTION": "Tanım", "RECRUITING": "Bu proje insan arıyor mu?", "RECRUITING_MESSAGE": "Ne aramıştınız?", "RECRUITING_PLACEHOLDER": "Aradığınız özellikleri yazın", + "FEEDBACK": "Receive feedback from Taiga users?", "PUBLIC_PROJECT": "Açık Proje", "PRIVATE_PROJECT": "Gizli proje", "PRIVATE_OR_PUBLIC": "Açık ve özel projeler arasındaki fark nedir?", "DELETE": "Bu projeyi sil", - "LOGO_HELP": "Resim 80×80 piksel boyutuna ölçeklenecek. ", "CHANGE_LOGO": "Logoyu değiştir", "ACTION_USE_DEFAULT_LOGO": "Varsayılan resmi kullan", "MAX_PRIVATE_PROJECTS": "You've reached the maximum number of private projects allowed by your current plan", @@ -595,6 +541,7 @@ "ISSUE_DESCRIPTION": "Sorunlar için özel alanlar", "ISSUE_ADD": "Sorunlara yeni bir özel alan ekle", "FIELD_TYPE_TEXT": "Metin", + "FIELD_TYPE_RICHTEXT": "Rich text", "FIELD_TYPE_MULTI": "Çoklu-satır", "FIELD_TYPE_DATE": "Tarih", "FIELD_TYPE_URL": "Url" @@ -623,7 +570,7 @@ "ACTION_ADD": "Yeni önem derecesi ekle" }, "PROJECT_VALUES_STATUS": { - "TITLE": "Durum", + "TITLE": "Statuses", "SUBTITLE": "Hikayeleriniz, işleriniz ve sorunlarınızın alabileceği durumları tanımlayın", "EPIC_TITLE": "Epic Statuses", "US_TITLE": "User Story Statuses", @@ -676,8 +623,8 @@ "INFO_VERIFYING_IP": "Gitlab istekleri imzalı değiller bu yüzden IP kaynağını doğrulamak en iyi yol. Eğer alan boş bırakılırsa IP doğrulaması yapılmayacak." }, "GITHUB": { - "SECTION_NAME": "Github", - "PAGE_TITLE": "Github - {{projectName}}" + "SECTION_NAME": "GitHub", + "PAGE_TITLE": "GitHub - {{projectName}}" }, "GOGS": { "SECTION_NAME": "Gogs", @@ -686,7 +633,6 @@ "WEBHOOKS": { "PAGE_TITLE": "Webhooks - {{projectName}}", "SECTION_NAME": "Webhooks", - "SUBTITLE": "Webhook, Taiga da meydana gelen yorum, kullanıcı hikayeleri gibi olaylar hakkında dış servisleri bilgilendirir...", "ADD_NEW": "Yeni bir Webhook Ekle", "TYPE_NAME": "Servis adını girin", "TYPE_PAYLOAD_URL": "Servis paket URL'sini yazın", @@ -732,7 +678,6 @@ "DELETE_MEMBER": "Üye sil", "RESEND": "Yeniden gönder", "SUCCESS_SEND_INVITATION": "Davetiyeyi '{{email}}' adresine yeniden gönderdik.", - "ERROR_SEND_INVITATION": "Henüz bir davetiye göndermedik", "SUCCESS_DELETE": "{{message}} 'i sildik", "ERROR_DELETE": "Silemiyoruz {{message}}.", "DEFAULT_DELETE_MESSAGE": "davetiye {{email}} " @@ -761,16 +706,11 @@ "PLACEHOLDER_WRITE_NAME": "Yeni durum için bir isim yaz" }, "MENU": { - "TITLE": "Yönetim", "PROJECT": "Proje", "ATTRIBUTES": "Öznitelikler", "MEMBERS": "Üyeler", "PERMISSIONS": "İzinler", - "INTEGRATIONS": "Bütünleştirmeler", - "PLUGINS": "Eklentiler" - }, - "SUBMENU_PROJECT_ATTRIBUTES": { - "TITLE": "Öznitelikler" + "INTEGRATIONS": "Bütünleştirmeler" }, "SUBMENU_PROJECT_VALUES": { "STATUS": "Durum", @@ -781,17 +721,11 @@ "CUSTOM_FIELDS": "Özel alanlar", "TAGS": "Etiketler " }, - "SUBMENU_PROJECT_PROFILE": { - "TITLE": "Proje Profili" - }, "SUBMENU_ROLES": { "TITLE": "Roller", "ACTION_NEW_ROLE": "+ Yeni rol", "TITLE_ACTION_NEW_ROLE": "Yeni rol ekle" }, - "SUBMENU_THIDPARTIES": { - "TITLE": "Servisler" - }, "PROJECT_TRANSFER": { "DO_YOU_ACCEPT_PROJECT_OWNERNSHIP": "Would you like to become the new project owner?", "PRIVATE": "Private", @@ -806,15 +740,13 @@ "PRIVATE": "Please remember that you can own up to {{maxProjects}} private projects. You currently own {{currentProjects}} private projects", "PUBLIC": "Please remember that you can own up to {{maxProjects}} public projects. You currently own {{currentProjects}} public projects" }, - "CANT_BE_OWNED": "At the moment you cannot become an owner of a project of this type. If you would like to become the owner of this project, please contact the administrator so they change your account settings to enable project ownership.", - "CHANGE_MY_PLAN": "Change my plan" + "CANT_BE_OWNED": "At the moment you cannot become an owner of a project of this type. If you would like to become the owner of this project, please contact the administrator so they change your account settings to enable project ownership." } }, "USER": { "PROFILE": { "PAGE_TITLE": "{{userFullName}} (@{{userUsername}})", "EDIT": "Profili Düzenle", - "FOLLOW": "Takip et", "CLOSED_US": "Kapatılmış KH", "PROJECTS": "Projeler", "PROJECTS_EMPTY": "{{username}} kullanıcısının henüz bir projesi yok", @@ -822,7 +754,6 @@ "CONTACTS_EMPTY": "{{username}} kullanıcısının henüz irtibat kişileri yok", "CURRENT_USER_CONTACTS_EMPTY": "Henüz irtibat kişileriniz yok", "CURRENT_USER_CONTACTS_EMPTY_EXPLAIN": "Taiga ile çalışan kişiler otomatik olarak irtibat kişileriniz olacaktır", - "REPORT": "Kötüye Kullanımı Raporla", "TABS": { "ACTIVITY_TAB": "Zaman Çizelgesi", "ACTIVITY_TAB_TITLE": "Bu kullanıcı için tüm eylemleri göster", @@ -848,13 +779,13 @@ "FILTER_TYPE_ALL": "Hepsi", "FILTER_TYPE_ALL_TITLE": "Hepsini göster", "FILTER_TYPE_PROJECTS": "Projeler", - "FILTER_TYPE_PROJECT_TITLES": "Sadece projeleri görüntüle", + "FILTER_TYPE_PROJECTS_TITLE": "Sadece projeleri görüntüle", "FILTER_TYPE_EPICS": "Epics", - "FILTER_TYPE_EPIC_TITLES": "Show only epics", + "FILTER_TYPE_EPICS_TITLE": "Show only epics", "FILTER_TYPE_USER_STORIES": "Hikayeler", - "FILTER_TYPE_USER_STORIES_TITLES": "Sadece kullanıcı hikayelerini göster", + "FILTER_TYPE_USER_STORIES_TITLE": "Sadece kullanıcı hikayelerini göster", "FILTER_TYPE_TASKS": "Görevler", - "FILTER_TYPE_TASK_TITLES": "Sadece görevleri göster", + "FILTER_TYPE_TASKS_TITLE": "Sadece görevleri göster", "FILTER_TYPE_ISSUES": "Sorunlar ", "FILTER_TYPE_ISSUES_TITLE": "Sadece sorunları göster", "EMPTY_TITLE": "Görünüşe göre burada gösterilecek bir şey yok." @@ -862,8 +793,6 @@ }, "PROJECT": { "PAGE_TITLE": "{{projectName}}", - "WELCOME": "Hoşgeldiniz", - "SECTION_PROJECTS": "Projeler", "HELP": "En çok kullanılan projelerinizi en üste koymak için yeniden sıralayın.
Top 10 projeler gezinti çubuğunun proje listesinin başında gösterilecektir.", "PRIVATE": "Gizli proje", "LOOKING_FOR_PEOPLE": "Bu proje ahalisini arıyor", @@ -875,12 +804,6 @@ "THIS_PROJECT_IS_BLOCKED": "This project is temporarily blocked", "TO_UNBLOCK_CONTACT_THE_ADMIN_STAFF": "In order to unblock your projects, contact the administrator." }, - "STATS": { - "PROJECT": "proje
puanlar", - "DEFINED": "tanımlı
puanlar", - "ASSIGNED": "atanmış
puanlar", - "CLOSED": "kapatılmış
puanlar" - }, "SECTION": { "SEARCH": "Ara", "TIMELINE": "Zaman Çizelgesi", @@ -893,15 +816,9 @@ "ADMIN": "Yönetim" }, "NAVIGATION": { - "SECTION_TITLE": "Projeleriniz", - "PLACEHOLDER_SEARCH": "Aranan konum...", "ACTION_CREATE_PROJECT": "Proje Oluştur", - "ACTION_IMPORT_PROJECT": "Projeyi İçe Aktar", "MANAGE_PROJECTS": "Projeleri yönet", "TITLE_CREATE_PROJECT": "Proje oluştur", - "TITLE_IMPORT_PROJECT": "Projeyi İçe Aktar", - "TITLE_PRVIOUS_PROJECT": "Önceki projeleri göster", - "TITLE_NEXT_PROJECT": "Sonraki projeleri göster", "HELP_TITLE": "Taiga Destek Sayfası", "HELP": "Yardım", "HOMEPAGE": "Ana sayfa", @@ -909,10 +826,6 @@ "FEEDBACK": "Geribildirim", "NOTIFICATIONS_TITLE": "Bildirim ayarlarını düzenle", "NOTIFICATIONS": "Bildirimler", - "ORGANIZATIONS_TITLE": "Organizasyonunuzu düzenleyin", - "ORGANIZATIONS": "Organizasyonları düzenle", - "SETTINGS_TITLE": "Ayarlarınızı düzenleyin", - "SETTINGS": "Ayarlar", "VIEW_PROFILE_TITLE": "Profili Görüntüle", "VIEW_PROFILE": "Profili Görüntüle", "EDIT_PROFILE_TITLE": "Profilini düzenle", @@ -921,14 +834,68 @@ "CHANGE_PASSWORD": "Parolayı değiştir", "DASHBOARD_TITLE": "Pano", "DISCOVER_TITLE": "Trend projeleri keşfet", - "NEW_ITEM": "Yeni", - "DISCOVER": "Keşfet", - "ACTION_REORDER": "Yeniden sıralamak için sürükleyin ve bırakın" + "DISCOVER": "Keşfet" + }, + "LIKE_BUTTON": { + "LIKE": "Beğen", + "LIKED": "Beğendi", + "UNLIKE": "Beğenme", + "BUTTON_TITLE": "Bu projeyi beğen ya da beğenme", + "COUNTER_TITLE": "{total, plural, one{bir meraklı} other{# meraklı}}" + }, + "WATCH_BUTTON": { + "BUTTON_TITLE": "Bu projeyi izle ve bildirim politikasını ayarla", + "WATCH": "İzle", + "WATCHING": "İzliyor", + "COUNTER_TITLE": "{total, plural, one{bir takipçi} other{# takipçi}}", + "OPTIONS": { + "NOTIFY_ALL": "Bütün bildirimleri al", + "NOTIFY_ALL_TITLE": "Bu proje için tüm bildirimleri al", + "NOTIFY_INVOLVED": "Sadece ilgililer", + "NOTIFY_INVOLVED_TITLE": "Sadece ilgilendiğiniz bildirimleri alın", + "UNWATCH": "İzleme", + "UNWATCH_TITLE": "Bu projeyi izleme" + } + }, + "CONTACT_BUTTON": { + "CONTACT_TITLE": "Contact the project team", + "CONTACT_BUTTON": "Contact the project" + }, + "CREATE": { + "TITLE": "Proje Oluştur", + "CHOOSE_TEMPLATE": "Which template fits your project better?", + "TEMPLATE_SCRUM": "Scrum", + "TEMPLATE_SCRUM_DESC": "Prioritize and solve your tasks in short time cycles.", + "TEMPLATE_SCRUM_LONGDESC": "Scrum is an iterative and incremental agile software development methodology for managing product development.\nThe product backlog is what will ultimately be delivered, ordered into the sequence in which it should be delivered. Product Backlogs are broken into manageable, executable chunks named sprints. Every certain amount of time the team initiates a new sprint and commits to deliver a certain number of user stories from the backlog, in accordance with their skills, abilities and resources. The project advances as the backlog becomes depleted.", + "TEMPLATE_KANBAN": "Kanban", + "TEMPLATE_KANBAN_DESC": "Keep a constant workflow on independent tasks", + "TEMPLATE_KANBAN_LONGDESC": "The Kanban methodology is used to divide project development (any sort of project) into stages.\nA kanban card is like an index card or post-it note that details every task (or user story) in a project that needs to be completed. The Kanban board is used to move each card from one state of completion to the next and in so doing, helps track progress.", + "DUPLICATE": "Duplicate project", + "DUPLICATE_DESC": "Start clean and keep your configuration", + "IMPORT": "Projeyi İçe Aktar", + "IMPORT_DESC": "Import your project from multiple platforms into Taiga", + "INVITE": "Invite to the project", + "SOLO_PROJECT": "You'll be alone in this project", + "INVITE_LATER": "(You'll be able to invite more members later)", + "BACK": "Arka", + "MAX_PRIVATE_PROJECTS": "Unfortunately, You've reached the maximum number of private projects.\nIf you would like to increase the current limit please contact the administrator.", + "MAX_PUBLIC_PROJECTS": "Unfortunately, You've reached the maximum number of public projects.\nIf you would like to increase the current limit please contact the administrator.", + "PUBLIC_PROJECT": "Public Project", + "PRIVATE_PROJECT": "Private Project" + }, + "COMMON": { + "DETAILS": "New project details", + "PROJECT_TITLE": "Project Name", + "PROJECT_DESCRIPTION": "Project Description" + }, + "DUPLICATE": { + "TITLE": "Duplicate Project", + "DESCRIPTION": "Start clean and keep your configuration", + "SELECT_PLACEHOLDER": "Choose an existing project to duplicate" }, "IMPORT": { - "TITLE": "Proje İçe Aktarılıyor", - "UPLOADING_FILE": "Döküm dosyanız karşıya yükleniyor", - "DESCRIPTION": "Bu işlem biraz sürecek, lütfen pencereyi kapatmayın.", + "TITLE": "Import Project", + "DESCRIPTION": "Import your project from multiple platforms into Taiga", "ASYNC_IN_PROGRESS_TITLE": "Bizim honki ponkiler projenizi içeriye aktarıyor", "ASYNC_IN_PROGRESS_MESSAGE": "Bu işlem bir kaç dakika sürecek
Hazır olduğunda bir e-posta göndereceğiz", "UPLOAD_IN_PROGRESS_MESSAGE": "{{totalSize}} in {{uploadedSize}} kadarı karşıya yüklendi", @@ -937,8 +904,29 @@ "ERROR_MESSAGE": "Honki ponkilerimiz döküm dosyanızı içeri aktarırken birkaç problem yaşadı: {{error_message}}", "ERROR_MAX_SIZE_EXCEEDED": "({{fileSize}}) boyutundaki '{{fileName}}' dosya honki ponkilerimiz için oldukça ağır geldi, ({{maxFileSize}}) boyutundan daha küçük bir şeylerle deneyin", "SYNC_SUCCESS": "Projeniz başarıyla içe aktarıldı", + "IMPORT": "Import", + "WHO_IS": "Their tasks will be assigned to ...", + "WRITE_EMAIL": "Or if you want, write the email that this user uses in Taiga", + "SEARCH_CONTACT": "Or if you want, search in your contacts", + "WRITE_EMAIL_LABEL": "Write the email that this user uses in Taiga", + "ACCEEDE": "Acceede", + "PROJECT_MEMBERS": "Project Members", + "PROCESS_DESCRIPTION": "Tell us who from Taiga you want to assign the tasks of {{platform}}", + "MATCH": "Is {{user_external}} the same person as {{user_internal}}?", + "CHOOSE": "Select user", + "LINKS": "Links with {{platform}}", + "LINKS_DESCRIPTION": "Do you want to keep the link of each item with the original {{platform}} card?", + "WARNING_MAIL_USER": "Note that if the user does not have a Taiga account we will not be able to assign the tasks to him.", + "ASSIGN": "Ata", + "PROJECT_SELECTOR": { + "NO_RESULTS": "It looks like nothing was found with your search criteria", + "ACTION_SEARCH": "ara", + "ACTION_BACK": "Arka" + }, "PROJECT_RESTRICTIONS": { - "PROJECT_MEMBERS_DESC": "The project you are trying to import has {{members}} members, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per project. If you would like to increase that limit please contact the administrator.", + "PROJECT_MEMBERS_DESC_PRIVATE": "The project you are trying to import has {{members}} members including you, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per private project. If you would like to increase that limit please contact the administrator.", + "PROJECT_MEMBERS_DESC_PUBLIC": "The project you are trying to import has {{members}} members including you, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per public project. If you would like to increase that limit please contact the administrator.", + "ACCOUNT_ALLOW_MEMBERS": "Your account only allows {{members}} members", "PRIVATE_PROJECTS_SPACE": { "TITLE": "Unfortunately, your current plan does not allow for additional private projects", "DESC": "The project you are trying to import is private. Unfortunately, your current plan does not allow for additional private projects." @@ -961,39 +949,67 @@ "TITLE": "Unfortunately your current plan doesn't allow additional public projects or an increase of more than {{max_memberships}} members per public project", "DESC": "The project that you are trying to import is public and has more than {{members}} members." } - } - }, - "LIKE_BUTTON": { - "LIKE": "Beğen", - "LIKED": "Beğendi", - "UNLIKE": "Beğenme", - "BUTTON_TITLE": "Bu projeyi beğen ya da beğenme", - "COUNTER_TITLE": "{total, plural, one{bir meraklı} other{# meraklı}}" - }, - "WATCH_BUTTON": { - "BUTTON_TITLE": "Bu projeyi izle ve bildirim politikasını ayarla", - "WATCH": "İzle", - "WATCHING": "İzliyor", - "COUNTER_TITLE": "{total, plural, one{bir takipçi} other{# takipçi}}", - "OPTIONS": { - "NOTIFY_ALL": "Bütün bildirimleri al", - "NOTIFY_ALL_TITLE": "Bu proje için tüm bildirimleri al", - "NOTIFY_INVOLVED": "Sadece ilgililer", - "NOTIFY_INVOLVED_TITLE": "Sadece ilgilendiğiniz bildirimleri alın", - "UNWATCH": "İzleme", - "UNWATCH_TITLE": "Bu projeyi izleme" + }, + "IN_PROGRESS": { + "TITLE": "Proje İçe Aktarılıyor", + "DESCRIPTION": "Bu işlem biraz sürecek, lütfen pencereyi kapatmayın." + }, + "WARNING": { + "TITLE": "Some taks will be unassigned", + "DESCRIPTION": "There are still unidentified people. The cards assigned to these people will remain unassigned. Check all the contacts to not lose that information.", + "CHECK": "Check contacts" + }, + "TAIGA": { + "SELECTOR": "Import your Taiga project" + }, + "TRELLO": { + "SELECTOR": "Import your Trello boards into Taiga", + "CHOOSE_PROJECT": "Choose board that you want to import", + "NO_PROJECTS": "It seems you have no boards in Trello" + }, + "GITHUB": { + "SELECTOR": "Import your GitHub project issues", + "CHOOSE_PROJECT": "Find the project you want to import", + "NO_PROJECTS": "It seems you have no porjects in GitHub", + "HOW_DO_YOU_WANT_TO_IMPORT": "How do you want to import your issues into Taiga?", + "KANBAN_PROJECT": "As user stories in a kanban project", + "KANBAN_PROJECT_DESCRIPTION": "After that you can enable scrum with backlog.", + "SCRUM_PROJECT": "As user stories in a scrum project", + "SCRUM_PROJECT_DESCRIPTION": "After that you can enable kanban mode.", + "ISSUES_PROJECT": "As issues", + "ISSUES_PROJECT_DESCRIPTION": "You will not be able to use your issues in kanban or scrum mode. You will be able to enable kanban or scrum for new user stories" + }, + "ASANA": { + "SELECTOR": "Import your Asana project and choose how to manage it", + "CHOOSE_PROJECT": "Choose project that you want to import", + "NO_PROJECTS": "It seems you have no porjects in Asana", + "KANBAN_PROJECT": "Kanban", + "SCRUM_PROJECT": "Scrum", + "CREATE_AS_SCRUM_DESCRIPTION": "The tasks and sub-tasks of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_KANBAN_DESCRIPTION": "The tasks and sub-tasks of your project will be created as Taiga user stories and tasks." + }, + "JIRA": { + "SELECTOR": "Import your Jira project and choose how to manage it", + "CHOOSE_PROJECT": "Choose project or board that you want to import", + "NO_PROJECTS": "It seems you have no porjects or boards in Jira", + "URL": "Your Jira URL", + "KANBAN_PROJECT": "Kanban", + "SCRUM_PROJECT": "Scrum", + "ISSUES_PROJECT": "Sorunlar", + "CREATE_AS_SCRUM_DESCRIPTION": "The issues and sub-issues of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_KANBAN_DESCRIPTION": "The issues and sub-issues of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_ISSUES_DESCRIPTION": "What do you want to do with sub-issues from the Jira project? (Taiga doesn't allow sub-issues)", + "CREATE_NEW_ISSUES": "Convert sub-issues to new Taiga issues", + "NOT_CREATE_NEW_ISSUES": "Do not import sub-issues" } } }, "LIGHTBOX": { "DELETE_ACCOUNT": { - "SECTION_NAME": "Taiga Hesabını Sil", "CONFIRM": "Taiga hesabınızı silmek istediğinizden emin misiniz?", - "NEWSLETTER_LABEL_TEXT": "Bundan böyle bülteninizi almak istemiyorum.", "CANCEL": "Back to settings", "ACCEPT": "Delete account", - "BLOCK_PROJECT": "Note that all the projects you own projects will be blocked after you delete your account. If you do want a project blocked, transfer ownership to another member of each project prior to deleting your account.", - "SUBTITLE": "Sorry to see you go. We'll be here if you should ever consider us again! :(" + "BLOCK_PROJECT": "Note that all the projects you own projects will be blocked after you delete your account. If you do want a project blocked, transfer ownership to another member of each project prior to deleting your account." }, "DELETE_PROJECT": { "TITLE": "Proje Sil", @@ -1007,6 +1023,12 @@ }, "ADD_MEMBER": { "TITLE": "Yeni üye", + "PLACEHOLDER": "Filter users or write an email to invite", + "ADD_EMAIL": "Add email", + "REMOVE": "Remove", + "INVITE": "Invite", + "CHOOSE_ROLE": "Choose a role", + "PLACEHOLDER_INVITATION_TEXT": "(Opsiyonel) Davetinize kişiselleştirilmiş bir metin ekleyin. Yeni üyelerinize tatlı bir şeyler söyleyin ;-)", "HELP_TEXT": "Eğer kullanıcılar önceden Taigaya kayıt olmuşlarsa, otomatik olarak ekleneceklerdir. Eğer olmamışlarsa bir davet mektubu alacaklardır." }, "CREATE_ISSUE": { @@ -1068,6 +1090,12 @@ "TITLE": "Who do you want to be the new project owner?", "ADD_COMMENT": "Add comment", "BUTTON": "Ask this project member to become the new project owner" + }, + "CONTACT_PROJECT": { + "TITLE": "Send an email to", + "WARNING": "The email will be received by the project admins", + "PLACEHOLDER": "Write your message", + "SEND": "Send" } }, "EPIC": { @@ -1101,15 +1129,9 @@ "ADD_BULK": "Toplu halde yeni Kullanıcı Hikayeleri ekle", "PROMOTED": "Bu hikayenin temelindeki sorun:", "TITLE_LINK_GO_TO_ISSUE": "Talebe git", - "EXTERNAL_REFERENCE": "Bu KH 'ni oluşturulduğu", - "GO_TO_EXTERNAL_REFERENCE": "Kökenine git ", - "BLOCKED": "Bu kullanıcı hikayesi engelli", "TITLE_DELETE_ACTION": "Kullanıcı Hikayesi Sil", "LIGHTBOX_TITLE_BLOKING_US": "Bizi engelleyen", - "TASK_COMPLETED": "{{totalClosedTasks}}/{{totalTasks}} tamamlanan görevler", - "ASSIGN": "Kullanıcı Hikayesini Ata", "NOT_ESTIMATED": "Kestirim yapılmamış", - "TOTAL_US_POINTS": "Toplam KH puanları", "TRIBE": { "PUBLISH": "Publish as Gig in Taiga Tribe", "PUBLISH_INFO": "More info", @@ -1119,23 +1141,19 @@ "CLOSE": "Close", "SYNCHRONIZE_LINK": "synchronize with Taiga Tribe", "PUBLISH_MORE_INFO_TITLE": "Do you need somebody for this task?", - "PUBLISH_MORE_INFO_TEXT": "

If you need help with a particular piece of work you can easily create gigs on Taiga Tribe and receive help from all over the world. You will be able to control and manage the gig enjoying a great community eager to contribute.

TaigaTribe was born as a Taiga sibling. Both platforms can live separately but we believe that there is much power in using them combined so we are making sure the integration works like a charm.

" + "PUBLISH_MORE_INFO_TEXT": "

If you need help with a particular piece of work you can easily create gigs on Taiga Tribe and receive help from all over the world. You will be able to control and manage the gig enjoying a great community eager to contribute.

TaigaTribe was born as a Taiga sibling. Both platforms can live separately but we believe that there is much power in using them combined so we are making sure the integration works like a charm.

" }, "FIELDS": { "TEAM_REQUIREMENT": "Takım Gereksinimi", - "CLIENT_REQUIREMENT": "İstemci Gereksinimi", - "FINISH_DATE": "Bitiş tarihi" + "CLIENT_REQUIREMENT": "İstemci Gereksinimi" } }, "COMMENTS": { "DELETED_INFO": "Comment deleted by {{user}}", - "TITLE": "Yorumlar", "COMMENTS_COUNT": "{{comments}} Comments", - "ORDER": "Order", "OLDER_FIRST": "Older first", "RECENT_FIRST": "Recent first", "COMMENT": "Yorum Yap", - "EDIT_COMMENT": "Edit comment", "EDITED_COMMENT": "Edited:", "SHOW_HISTORY": "View historic", "TYPE_NEW_COMMENT": "Buraya yeni bir yorum yazın", @@ -1148,13 +1166,8 @@ } }, "ACTIVITY": { - "SHOW_ACTIVITY": "Eylemleri göster", - "DATETIME": "DD MMM YYYY HH:mm", - "SHOW_MORE": "+ Önceki girdileri göster ({{showMore}} daha fazla)", "TITLE": "Aktivite", "ACTIVITIES_COUNT": "{{activities}} Activities", - "REMOVED": "silindi", - "ADDED": "eklendi", "TAGS_ADDED": "tags added:", "TAGS_REMOVED": "tags removed:", "US_POINTS": "{{role}} points", @@ -1163,50 +1176,21 @@ "UPDATED_ATTACHMENT": "updated attachment ({{filename}}):", "CREATED_CUSTOM_ATTRIBUTE": "created custom attribute", "UPDATED_CUSTOM_ATTRIBUTE": "updated custom attribute", - "SIZE_CHANGE": "Yapılan {size, plural, one{tek değişiklik} other{# değişiklikler}}", "BECAME_DEPRECATED": "became deprecated", "BECAME_UNDEPRECATED": "became undeprecated", "TEAM_REQUIREMENT": "Takım Gereksinimi", "CLIENT_REQUIREMENT": "İstemci Gereksinimi", "BLOCKED": "Engelli", "VALUES": { - "YES": "evet", - "NO": "hayır", - "EMPTY": "boş", "UNASSIGNED": "atama yok" }, "FIELDS": { "SUBJECT": "konu", - "NAME": "isim", "DESCRIPTION": "tanım", - "CONTENT": "içerik", "STATUS": "durum", - "IS_CLOSED": "kapatıldı", - "FINISH_DATE": "bitiş tarihi", "TYPE": "tip", - "PRIORITY": "öncelik", - "SEVERITY": "önem derecesi", "ASSIGNED_TO": "atanmış", - "WATCHERS": "izleyiciler", "MILESTONE": "koşu", - "USER_STORY": "kullanıcı hikayesi", - "PROJECT": "proje", - "IS_BLOCKED": "engellendi", - "BLOCKED_NOTE": "engel notu", - "POINTS": "puanlar", - "CLIENT_REQUIREMENT": "istemci gereksinimi", - "TEAM_REQUIREMENT": "takım gereksinimi", - "IS_IOCAINE": "baldıran zehri", - "TAGS": "etiketler", - "ATTACHMENTS": "ekler", - "IS_DEPRECATED": "kaldırıldı", - "IS_NOT_DEPRECATED": "is not deprecated", - "ORDER": "sıra", - "BACKLOG_ORDER": "havuz sıralaması", - "SPRINT_ORDER": "koşu sırası", - "KANBAN_ORDER": "kanban sırası", - "TASKBOARD_ORDER": "Görev panosu sırası", - "US_ORDER": "kh sırası", "COLOR": "renk" } }, @@ -1220,8 +1204,6 @@ "CUSTOMIZE_GRAPH_TITLE": "Yönetimden puan ve koşuları ayarlayın", "MOVE_US_TO_CURRENT_SPRINT": "Şimdiki Koşuya Taşı", "MOVE_US_TO_LATEST_SPRINT": "Son koşuya taşı", - "SHOW_FILTERS": "Filtreleri göster", - "SHOW_TAGS": "Etiketleri göster", "EMPTY": "Havuz bomboş!", "CREATE_NEW_US": "Yeni bir KH oluştur", "CREATE_NEW_US_EMPTY_HELP": "Yeni bir kullanıcı hikayesi oluşturmak isteyebilirsiniz", @@ -1248,6 +1230,12 @@ "SHOW": "Etiketleri göster", "HIDE": "Etiketleri gizler" }, + "FORECASTING": { + "TITLE": "Velocity forecasting", + "BACKLOG": "Display backlog", + "NEW_SPRINT": "Candidate User Stories for your next sprint based on your velocity. Click to create a new sprint.", + "CURRENT_SPRINT": "Candidate User Stories for your sprint based on your velocity. Click to add to current sprint." + }, "TABLE": { "COLUMN_US": "Kullanıcı Hikayeleri ", "TITLE_COLUMN_POINTS": "Her rol için görünüm seç" @@ -1270,8 +1258,6 @@ }, "FILTERS": { "TOGGLE": "Filtrelerin görünürlüğünü değiştir", - "TITLE": "Filtreler", - "REMOVE": "Filtreleri Sil", "HIDE": "Filtreleri Gizle", "SHOW": "Filtreleri Göster" }, @@ -1280,7 +1266,6 @@ "DATE": "DD MM YYYY", "LINK_TASKBOARD": "Koşu İş Panosu", "TITLE_LINK_TASKBOARD": "\"{{name}}\" görev panosuna git", - "NUMBER_SPRINTS": "
koşular", "EMPTY": "Henüz hiç koşu yok", "WARNING_EMPTY_SPRINT_ANONYMOUS": "Bu koşuda hiç kullanıcı hikayesi yok.", "WARNING_EMPTY_SPRINT": "Yeni bir koşu başlatmak icin havuzdan buraya hikaye taşıyın", @@ -1305,7 +1290,6 @@ "TITLE_ACTION_ADD": "Yeni bir Görev ekle", "TITLE_ACTION_ADD_BULK": "Toplu halde yeni bir kaç görev ekle", "TITLE_ACTION_ASSIGN": "Görev ata", - "TITLE_ACTION_EDIT": "Görevi düzenle", "PLACEHOLDER_CARD_TITLE": "Bu bir görev olabilir", "PLACEHOLDER_CARD_TEXT": "Hikayeleri ve görevleri birbirinden ayırın ve öyle izleyin", "TABLE": { @@ -1335,17 +1319,11 @@ "TITLE_SELECT_STATUS": "Durum Adı", "OWNER_US": "Bu görevin ait olduğu", "TITLE_LINK_GO_OWNER": "Kullanıcı hikayesine git", - "ORIGIN_US": "Bu görevin oluşturulduğu", - "TITLE_LINK_GO_ORIGIN": "Kullanıcı hikayesine git", - "BLOCKED": "Bu iş engelli", "TITLE_DELETE_ACTION": "Görev Sil", "LIGHTBOX_TITLE_BLOKING_TASK": "Engelleyen iş", "FIELDS": { - "MILESTONE": "Koşu", - "USER_STORY": "Kullanıcı hikayesi", "IS_IOCAINE": "baldıran zehri" }, - "ACTION_IOCAINE": "baldıran zehri", "TITLE_ACTION_IOCAINE": "Bir görev size ağır geldi ve bunaldınız mı? Diğerlerinin bu durumdan haberi olması için bir görevi düzenlerken baldıran zehrinin(temsili) üzerine tıklayın. Nasıl ki zaman zaman ekstra meydan okumalarla bir işte gittikçe iyi olmanız mümkünse, zaman içerisinde küçük dozlar alarak bu ölümcül zehre de bağışıklık kazanabilmek mümkün!" }, "NOTIFICATION": { @@ -1374,14 +1352,12 @@ "ISSUES": { "PAGE_TITLE": "Sorunlar - {{projectName}}", "PAGE_DESCRIPTION": "{{projectName}} projesinin sorun listesi paneli: {{projectDescription}}", - "LIST_SECTION_NAME": "Sorunlar", "SECTION_NAME": "Sorun", "ACTION_NEW_ISSUE": "+ YENİ SORUN", "ACTION_PROMOTE_TO_US": "Kullanıcı Hikayesine Terfi Ettir", "PROMOTED": "Bu sorun, kullanıcı hikayesine yükseltildi:", "EXTERNAL_REFERENCE": "Bu talebin oluşturulduğu ", "GO_TO_EXTERNAL_REFERENCE": "Kökenine git", - "BLOCKED": "Bu sorun engelli", "ACTION_DELETE": "Sorun sil", "LIGHTBOX_TITLE_BLOKING_ISSUE": "Engelleyen sorun", "FIELDS": { @@ -1423,15 +1399,11 @@ "SECTION_NAME": "Kanban", "TITLE_ACTION_FOLD": "Sütun Katla", "TITLE_ACTION_UNFOLD": "Sütun katını aç", - "TITLE_ACTION_FOLD_CARDS": "Kartları katla", - "TITLE_ACTION_UNFOLD_CARDS": "Kartların katlarını aç", "TITLE_ACTION_ADD_US": "Yeni Kullanıcı Hikayesi Ekle", "TITLE_ACTION_ADD_BULK": "Yeni toplu ekle", "ACTION_SHOW_ARCHIVED": "Arşivlenmişleri Göster", "ACTION_HIDE_ARCHIVED": "Arşivlenmişleri gizle", "HIDDEN_USER_STORIES": "Bu durumdaki kullanıcı hikayeleri otomatik olarak gizlenir", - "ARCHIVED": "Arşivlendiniz", - "UNDO_ARCHIVED": "Geri almak için tutun ve sürükleyin", "PLACEHOLDER_CARD_TITLE": "Bunlar Kullanıcı Hikayeleriniz", "PLACEHOLDER_CARD_TEXT": "Gereksinimleri ayrıştırmak için hikayeler alt görevlere sahip olabilirler" }, @@ -1452,7 +1424,6 @@ "PAGE_TITLE": "Takım - {{projectName}}", "PAGE_DESCRIPTION": "Projedeki üyelerin tümünü göstermek için takım paneli {{projectName}}: {{projectDescription}}", "SECTION_NAME": "Takım", - "APP_TITLE": "TAKIM - {{projectName}}", "PLACEHOLDER_INPUT_SEARCH": "Tam ad ile ara", "COLUMN_MR_WOLF": "Reyiz", "EXPLANATION_COLUMN_MR_WOLF": "Kapatılmış sorunlar", @@ -1488,18 +1459,9 @@ "OPTION_ALL": "Hepsi", "OPTION_INVOLVED": "İlgili", "OPTION_NONE": "Hiçbiri" - }, - "POPOVER": { - "USER_PROFILE": "Kullanıcı Profili", - "CHANGE_PASSWORD": "Parolayı Değiştir", - "NOTIFICATIONS": "Bildirimler", - "FEEDBACK": "Geribildirim", - "TITLE_AVATAR": "Kullanıcı tercihleri" } }, "USER_PROFILE": { - "IMAGE_HELP": "Resim 80×80 piksel boyutuna ölçeklenecek.", - "ACTION_CHANGE_IMAGE": "Değiştir", "ACTION_USE_GRAVATAR": "Varsayılan resmi kullan", "ACTION_DELETE_ACCOUNT": "Taiga hesabını sil", "CHANGE_EMAIL_SUCCESS": "Gelen kutunuzu kontrol edin!
Yeni adresinizi belirlemek için gerekli
yönergeleri içeren postayı gönderdik", @@ -1517,25 +1479,10 @@ "THEME_DEFAULT": "-- varsayılan temayı kullan --" } }, - "WIZARD": { - "SECTION_TITLE_CREATE_PROJECT": "Proje Oluştur", - "CREATE_PROJECT_TEXT": "Taze ve temiz. Heycan verici!", - "CHOOSE_TEMPLATE": "Which template fits your project best?", - "CHOOSE_TEMPLATE_TITLE": "More info about project templates", - "CHOOSE_TEMPLATE_INFO": "More info", - "PROJECT_DETAILS": "Project Details", - "PUBLIC_PROJECT": "Public Project", - "PRIVATE_PROJECT": "Private Project", - "CREATE_PROJECT": "Proje oluştur", - "MAX_PRIVATE_PROJECTS": "You've reached the maximum number of private projects", - "MAX_PUBLIC_PROJECTS": "Unfortunately, you've reached the maximum number of public projects", - "CHANGE_PLANS": "change plans" - }, "WIKI": { "PAGE_TITLE": "{{wikiPageName}} - Wiki - {{projectName}}", "PAGE_DESCRIPTION": "Son sürüm {{lastModifiedDate}} ({{totalEditions}} toplamda sürüm sayısı) İçerik: {{ wikiPageContent }}", "DATETIME": "DD MMM YYYY HH:mm", - "PLACEHOLDER_PAGE": "Wiki sayfanı yaz ", "REMOVE": "Bu wiki sayfasını sil", "DELETE_LIGHTBOX_TITLE": "Wiki Sayfası Sil", "DELETE_LINK_TITLE": "Delete Wiki link", @@ -1693,7 +1640,6 @@ "MOST_LIKED": "En beğenilen", "MOST_LIKED_EMPTY": "Henüz BEĞENİLEN proje yok", "VIEW_MORE": "Daha fazlası", - "RECRUITING": "Bu proje ahalisini arıyor", "FEATURED": "Önemli projeler", "EMPTY": "Bu arama ölçütlerine göre gösterilebilecek bir proje çıkmadı.
Tekrar deneyin!", "FILTERS": { diff --git a/app/locales/taiga/locale-zh-hans.json b/app/locales/taiga/locale-zh-hans.json new file mode 100644 index 00000000..b62f18d2 --- /dev/null +++ b/app/locales/taiga/locale-zh-hans.json @@ -0,0 +1,1664 @@ +{ + "COMMON": { + "YES": "是", + "NO": "否", + "OR": "或", + "LOADING": "载入中...", + "DATE": "YYYY MMM DD", + "DATETIME": "YYYY MMM DD HH:mm", + "SAVE": "保存", + "CANCEL": "取消", + "ACCEPT": "接受", + "DELETE": "删除", + "UNLINK": "断开链接", + "CREATE": "创建", + "ADD": "新增", + "COPY_TO_CLIPBOARD": "复制到剪贴板:Ctrl+C", + "EDIT": "编辑", + "DRAG": "拖拽", + "TAG_LINE": "你的敏捷、免费和开源的项目管理工具", + "TAG_LINE_2": "你喜欢的项目", + "BLOCK": "锁定", + "BLOCK_TITLE": "冻结:例如它有一个依赖不能满足,那么请冻结此项", + "BLOCKED": "已冻结", + "UNBLOCK": "解除冻结", + "UNBLOCK_TITLE": "关闭此项", + "BLOCKED_NOTE": "为什么它被关闭了呢?", + "BLOCKED_REASON": "请解释此原因", + "CREATED_BY": "由 {{fullDisplayName}} 创建", + "CLOSE": "关闭", + "GO_HOME": "返回首页", + "PLUGINS": "插件", + "ONE_ITEM_LINE": "一行一项", + "NEW_BULK": "批量插入", + "RELATED_TASKS": "相关任务", + "PREVIOUS": "前一个", + "NEXT": "下一个", + "LOGOUT": "退出", + "EXTERNAL_USER": "外部用户", + "GENERIC_ERROR": "系统错误:{{error}}。", + "IOCAINE_TEXT": "This member is feeling a bit overwhelmed by this task. Will become immune to the iocaine poison over time with your help. For now, may need a hug.", + "CLIENT_REQUIREMENT": "终端需求:是一个之前不存在的新的需求,并且该需求被要求成为项目的一部分", + "TEAM_REQUIREMENT": "团队需求:必须是项目中已经存在的需求,并且该需求不会对终端造成任何额外成本", + "OWNER": "项目所有者", + "CAPSLOCK_WARNING": "注意!你正在输入大写字母,该输入区域是区分大小写的。", + "CONFIRM_CLOSE_EDIT_MODE_TITLE": "你确定关闭编辑模式吗?", + "CONFIRM_CLOSE_EDIT_MODE_MESSAGE": "请记住,如果你在保存之前关闭了编辑模式,所有的更改都会丢失", + "RELATED_USERSTORIES": "相关用户故事", + "CARD": { + "ASSIGN_TO": "指派给", + "EDIT": "编辑卡片" + }, + "FORM_ERRORS": { + "DEFAULT_MESSAGE": "该数值似乎为无效", + "TYPE_EMAIL": "该电子邮件应为有效地址", + "TYPE_URL": "该网址应为有效链接", + "TYPE_URLSTRICT": "该网址应为有效链接", + "TYPE_NUMBER": "该数值应为有效号码", + "TYPE_DIGITS": "该数值应为有效数字", + "TYPE_DATEISO": "该数值应为有效日期 (YYYY-MM-DD)", + "TYPE_ALPHANUM": "该数值应为字母", + "TYPE_PHONE": "该数值应为有效的电话号码", + "NOTNULL": "该数值不应为零", + "NOT_BLANK": "该数值不应为空白", + "REQUIRED": "该数值为必须", + "REGEXP": "该数值似乎无效", + "MIN": "该数值应大于或等于 %s", + "MAX": "该数值应小于或等于 %s", + "RANGE": "该数值应介于 %s 与 %s之间", + "MIN_LENGTH": "该数值过短,它至少要有 %s 个字符", + "MAX_LENGTH": "该数值过长,它不可多于 %s 个字符。", + "RANGE_LENGTH": "该数值长度为无效,它应介于 %s 与 %s 字符之间", + "MIN_CHECK": "你必须至少选择 %s 选项", + "MAX_CHECK": "你必须至多选出 %s 选项", + "RANGE_CHECK": "你必须在 %s 与 %s 之间作出选择", + "EQUAL_TO": "该数值应为一致", + "LINEWIDTH": "一行或者多行可能太长了。尝试保持在 %s 字节以内", + "PIKADAY": "无效的日期格式,请使用DD MMM YYYY (如 23 Mar 1984)" + }, + "PICKERDATE": { + "FORMAT": "DD MMM YYYY", + "IS_RTL": "错误", + "FIRST_DAY_OF_WEEK": "1", + "PREV_MONTH": "上个月", + "NEXT_MONTH": "下个月", + "MONTHS": { + "JAN": "一月", + "FEB": "二月", + "MAR": "三月", + "APR": "四月", + "MAY": "五月", + "JUN": "六月", + "JUL": "七月", + "AUG": "八月", + "SEP": "九月", + "OCT": "十月", + "NOV": "十一月", + "DEC": "十二月" + }, + "WEEK_DAYS": { + "SUN": "周日", + "MON": "周一", + "TUE": "周二", + "WED": "周三", + "THU": "周四", + "FRI": "周五", + "SAT": "周六" + }, + "WEEK_DAYS_SHORT": { + "SUN": "周日", + "MON": "周一", + "TUE": "周二", + "WED": "周三", + "THU": "周四", + "FRI": "周五", + "SAT": "周六" + } + }, + "SEE_USER_PROFILE": "查看 {{username }} 个人信息", + "USER_STORY": "用户故事", + "TASK": "任务", + "ISSUE": "问题", + "EPIC": "史诗", + "TAGS": { + "PLACEHOLDER": "输入标签", + "DELETE": "删除标签", + "ADD": "新增标签" + }, + "DESCRIPTION": { + "EMPTY": "留下空白显得很无趣,写下点描述吧", + "NO_DESCRIPTION": "未有任何描述" + }, + "FIELDS": { + "SUBJECT": "主题", + "NAME": "名称", + "URL": "网址", + "DESCRIPTION": "描述", + "VALUE": "值", + "SLUG": "代称", + "COLOR": "颜色", + "IS_CLOSED": "关闭中?", + "STATUS": "状态", + "TYPE": "类型", + "SEVERITY": "严重程度", + "PRIORITY": "优先级", + "ASSIGNED_TO": "指派给", + "POINTS": "点数", + "IS_BLOCKED": "冻结", + "REF": "Ref", + "VOTES": "投票数", + "SPRINT": "冲刺任务" + }, + "ROLES": { + "ALL": "所有" + }, + "ASSIGNED_TO": { + "NOT_ASSIGNED": "未指派", + "ASSIGN": "指派", + "DELETE_ASSIGNMENT": "删除指派", + "REMOVE_ASSIGNED": "移除指派", + "TOO_MANY": "...太多用户,继续过滤中", + "CONFIRM_UNASSIGNED": "你确定要让它无任何指派吗?", + "TITLE_ACTION_EDIT_ASSIGNMENT": "编辑指派", + "SELF": "指派给我" + }, + "STATUS": { + "CLOSED": "关闭", + "OPEN": "开启" + }, + "WATCHERS": { + "WATCHERS": "关注者列表", + "ADD": "添加关注者", + "TITLE_ADD": "添加项目成员到关注者列表", + "DELETE": "已删除关注者", + "TITLE_LIGHTBOX_DELETE_WARTCHER": "删除关注者" + }, + "WATCH_BUTTON": { + "WATCH": "关注", + "WATCHING": "关注中", + "UNWATCH": "撤销关注", + "WATCHERS": "关注者列表", + "BUTTON_TITLE": "关注/撤销关注该项", + "COUNTER_TITLE": "{total, plural, one{一个关注者} other{# 个关注者}}" + }, + "VOTE_BUTTON": { + "BUTTON_TITLE": "赞/踩该项", + "COUNTER_TITLE": "{total, plural, one{一票} other{# 票}}" + }, + "CUSTOM_ATTRIBUTES": { + "CUSTOM_FIELDS": "自定义字段", + "SAVE": "保存自定义字段", + "EDIT": "编辑自定义字段", + "DELETE": "删除自定义字段", + "CONFIRM_DELETE": "请记住,在这个自定义字段中的所有值都会被删除。你确定继续吗?" + }, + "FILTERS": { + "INPUT_PLACEHOLDER": "标题或参考", + "TITLE_ACTION_FILTER_BUTTON": "搜索", + "TITLE": "过滤器", + "TITLE_ACTION_SEARCH": "搜索", + "ACTION_SAVE_CUSTOM_FILTER": "储存为定制过滤器", + "PLACEHOLDER_FILTER_NAME": "写入过滤器名称后按下enter", + "APPLIED_FILTERS_NUM": "已用过滤器", + "CATEGORIES": { + "TYPE": "类型", + "STATUS": "状态", + "SEVERITY": "严重程度", + "PRIORITIES": "优先级", + "TAGS": "标签", + "ASSIGNED_TO": "指派给", + "CREATED_BY": "由创建", + "CUSTOM_FILTERS": "定制过滤器", + "EPIC": "史诗" + } + }, + "WYSIWYG": { + "OUTDATED": "在你编辑期间其他人做过变更,保存前请先检查新版本", + "MARKDOWN_HELP": "Markdown 语法帮助" + }, + "PERMISIONS_CATEGORIES": { + "EPICS": { + "NAME": "史诗", + "VIEW_EPICS": "查看史诗", + "ADD_EPICS": "添加史诗", + "MODIFY_EPICS": "修改史诗", + "COMMENT_EPICS": "评论史诗", + "DELETE_EPICS": "删除史诗" + }, + "SPRINTS": { + "NAME": "冲刺任务", + "VIEW_SPRINTS": "查看冲刺任务", + "ADD_SPRINTS": "增加冲刺任务", + "MODIFY_SPRINTS": "修改冲刺任务", + "DELETE_SPRINTS": "删除冲刺任务" + }, + "USER_STORIES": { + "NAME": "用户故事", + "VIEW_USER_STORIES": "查看用户故事", + "ADD_USER_STORIES": "新增用户故事", + "MODIFY_USER_STORIES": "修改用户故事", + "COMMENT_USER_STORIES": "评论用户故事", + "DELETE_USER_STORIES": "删除用户故事" + }, + "TASKS": { + "NAME": "任务", + "VIEW_TASKS": "查看任务", + "ADD_TASKS": "新增任务", + "MODIFY_TASKS": "修改任务", + "COMMENT_TASKS": "评论任务", + "DELETE_TASKS": "删除任务" + }, + "ISSUES": { + "NAME": "问题", + "VIEW_ISSUES": "查看问题", + "ADD_ISSUES": "新增问题", + "MODIFY_ISSUES": "修改议题", + "COMMENT_ISSUES": "评论问题", + "DELETE_ISSUES": "删除问题" + }, + "WIKI": { + "NAME": "维基", + "VIEW_WIKI_PAGES": "查看维基页", + "ADD_WIKI_PAGES": "新增维基页", + "MODIFY_WIKI_PAGES": "修改维基页", + "DELETE_WIKI_PAGES": "删除维基页", + "VIEW_WIKI_LINKS": "查看维基链接", + "ADD_WIKI_LINKS": "新增维基链接", + "DELETE_WIKI_LINKS": "删除维基链接" + } + } + }, + "LOGIN": { + "PAGE_TITLE": "登入 - Taiga", + "PAGE_DESCRIPTION": "登录Taig,它是一个给新创团队与敏捷开发者设计师使用的项目管理平台。Taiga是一个简易轻松美观的工具,让工作变成乐趣。" + }, + "AUTH": { + "INVITED_YOU": "已邀请您加入此项目", + "NOT_REGISTERED_YET": "还没注册吗?", + "REGISTER": "注册", + "CREATE_ACCOUNT": "在此建立您的免费账户" + }, + "LOGIN_COMMON": { + "HEADER": "我已登录Taiga", + "PLACEHOLDER_AUTH_NAME": "用户名称或电子邮件(注意大小写)", + "LINK_FORGOT_PASSWORD": "忘记密码?", + "TITLE_LINK_FORGOT_PASSWORD": "您忘记密码了吗", + "ACTION_ENTER": "回车", + "ACTION_SIGN_IN": "登录", + "PLACEHOLDER_AUTH_PASSWORD": "密码(大小写敏感)" + }, + "LOGIN_FORM": { + "ERROR_AUTH_INCORRECT": "根据我们的系统记录,你的账户名称/电子邮件或密码并不正确", + "SUCCESS": "欢迎你登录Taiga" + }, + "REGISTER": { + "PAGE_TITLE": "注册 - Taiga", + "PAGE_DESCRIPTION": "在Taiga创建一个账户,它是一个给新创团队与敏捷开发者设计师使用的项目管理平台。Taiga是一个简易轻松美观的工具,让工作变成乐趣。" + }, + "REGISTER_FORM": { + "TITLE": "注册一个新的Taiga账户(免费 )", + "PLACEHOLDER_NAME": "填写一个用户账号(注意大小写)", + "PLACEHOLDER_FULL_NAME": "填写你的全名", + "PLACEHOLDER_EMAIL": "填写你的电子邮件", + "PLACEHOLDER_PASSWORD": "设置密码(大小写敏感)", + "ACTION_SIGN_UP": "注册", + "TITLE_LINK_LOGIN": "登录", + "LINK_LOGIN": "你是否已注册? 登录" + }, + "FORGOT_PASSWORD": { + "PAGE_TITLE": "忘记密码 - Taiga", + "PAGE_DESCRIPTION": "请输入你的用户名或电子邮件地址获取新密码重新登录Taiga" + }, + "FORGOT_PASSWORD_FORM": { + "TITLE": "你是否忘了密码?", + "SUBTITLE": "输入你的用户名称或电子邮件进行注册", + "PLACEHOLDER_FIELD": "用户名称或电子邮件", + "ACTION_RESET_PASSWORD": "重设密码", + "LINK_CANCEL": "不,请带我回去,我记起来了", + "SUCCESS_TITLE": "检查你的收件箱!", + "SUCCESS_TEXT": "我们向你的邮箱发送了一封带有重置密码指令的邮件", + "ERROR": "根据我们的系统记录,你尚未注册" + }, + "CHANGE_PASSWORD": { + "PAGE_TITLE": "修改密码 - Taiga", + "SECTION_NAME": "更新密码", + "FIELD_CURRENT_PASSWORD": "当前密码", + "PLACEHOLDER_CURRENT_PASSWORD": "你当前的密码(如果你未有密码,此处请空白)", + "FIELD_NEW_PASSWORD": "新密码", + "PLACEHOLDER_NEW_PASSWORD": "输入新密码", + "FIELD_RETYPE_PASSWORD": "重新输入新密码", + "PLACEHOLDER_RETYPE_PASSWORD": "重新输入新密码", + "ERROR_PASSWORD_MATCH": "密码不匹配" + }, + "CHANGE_PASSWORD_RECOVERY_FORM": { + "TITLE": "创建新Taiga通过", + "SUBTITLE": "你也许该吃点含铁丰富的食物,它对你的大脑有益处:p", + "PLACEHOLDER_NEW_PASSWORD": "新密码", + "PLACEHOLDER_RE_TYPE_NEW_PASSWORD": "重新输入新密码", + "ACTION_RESET_PASSWORD": "重设密码", + "ERROR": "我们的系统无法响应恢复密码的请求。请再尝试一次。", + "SUCCESS": "系统已储存你的新密码
试试 用它登录" + }, + "INVITATION": { + "PAGE_TITLE": "接受邀请 - Taiga", + "PAGE_DESCRIPTION": "接受邀请加入Taiga上的项目,它是一个给新创团队与敏捷开发者设计师使用的项目管理平台。Taiga是一个简易轻松美观的工具,让工作变成乐趣。" + }, + "INVITATION_LOGIN_FORM": { + "NOT_FOUND": "我们的Oompa Loompas无法找到你邀请", + "SUCCESS": "你成功地加入此项目,欢迎来到 {{project_name}}" + }, + "HOME": { + "PAGE_TITLE": "首页 - Taiga", + "PAGE_DESCRIPTION": "Taiga 首页,你的主要项目以及任命,观看用户故事,任务与问题。", + "EMPTY_WORKING_ON": "看起来空荡荡的,是不是?开始使用Taiga,你将会在这里看到你正在处理的用户故事,任务以及问题。", + "EMPTY_WATCHING": "在你的项目中追踪用户故事、任务、问题并且收到更新的通知 :)", + "EMPTY_PROJECT_LIST": "你尚无任何项目", + "WORKING_ON_SECTION": "进行中", + "WATCHING_SECTION": "关注中", + "DASHBOARD": "项目仪表盘" + }, + "EPICS": { + "TITLE": "史诗", + "SECTION_NAME": "用户故事", + "EPIC": "史诗", + "PAGE_TITLE": "史诗 - {{projectName}}", + "PAGE_DESCRIPTION": "项目的史诗列表{{projectName}}:{{projectDescription}}", + "DASHBOARD": { + "ADD": "添加史诗", + "UNASSIGNED": "未指派" + }, + "EMPTY": { + "TITLE": "您还未创建任何史诗", + "EXPLANATION": "史诗是一种包含用户故事的更上层的概念。\n史诗可用于组织用户故事并处于其层次结构的顶层。", + "HELP": "了解更多关于史诗的信息" + }, + "TABLE": { + "VOTES": "投票数", + "NAME": "名称", + "PROJECT": "项目", + "SPRINT": "冲刺任务", + "ASSIGNED_TO": "已指派", + "STATUS": "状态", + "PROGRESS": "进度", + "VIEW_OPTIONS": "浏览选项" + }, + "CREATE": { + "TITLE": "新建史诗", + "PLACEHOLDER_DESCRIPTION": "请添加一些描述文字来帮助其他人更好的了解这个史诗", + "TEAM_REQUIREMENT": "团队需求", + "CLIENT_REQUIREMENT": "客户需求", + "BLOCKED": "已锁定", + "BLOCKED_NOTE_PLACEHOLDER": "为什么这个史诗被冻结了?", + "CREATE_EPIC": "创建史诗" + } + }, + "PROJECTS": { + "PAGE_TITLE": "我的项目 - Taiga", + "PAGE_DESCRIPTION": "你的项目列表,你可以重新排序或者创建新项目。", + "MY_PROJECTS": "我的项目" + }, + "ATTACHMENT": { + "SECTION_NAME": "附件", + "TITLE": "{{ fileName }} 上传于 {{ date }}", + "LIST_VIEW_MODE": "列表视图模式", + "GALLERY_VIEW_MODE": "缩略图模式", + "DESCRIPTION": "输入一段简短描述", + "DEPRECATED": "(已废弃)", + "DEPRECATED_FILE": "废弃?", + "ADD": "加入新附件 {{maxFileSizeMsg}}", + "DROP": "将附件拖到这里来!", + "SHOW_DEPRECATED": "+ 显示废弃的附件", + "HIDE_DEPRECATED": "+ 隐藏废弃的附件", + "COUNT_DEPRECATED": "({{ counter }} 遭废弃)", + "MAX_UPLOAD_SIZE": "上传文档最大体积限制 {{maxFileSize}}", + "DATE": "DD MMM YYYY [at] hh:mm", + "ERROR_UPLOAD_ATTACHMENT": "无法成功上传 '{{fileName}}'. {{errorMessage}}", + "TITLE_LIGHTBOX_DELETE_ATTACHMENT": "删除附件....", + "MSG_LIGHTBOX_DELETE_ATTACHMENT": "附件 '{{fileName}}'", + "ERROR_DELETE_ATTACHMENT": "无法删除: {{errorMessage}}", + "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) 超过系统设置的附件体积上限, 请重传小一点的附件 ({{maxFileSize}})" + }, + "PAGINATION": { + "PREVIOUS": "上一个", + "NEXT": "下一个" + }, + "ADMIN": { + "COMMON": { + "TITLE_ACTION_EDIT_VALUE": "编辑值", + "TITLE_ACTION_DELETE_VALUE": "删除值", + "TITLE_ACTION_DELETE_TAG": "删除标签" + }, + "HELP": "需要帮助吗?看看我们的帮助页面吧!", + "PROJECT_DEFAULT_VALUES": { + "TITLE": "预设值", + "SUBTITLE": "将所有选项设为预设值" + }, + "MEMBERSHIPS": { + "TITLE": "管理成员", + "PAGE_TITLE": "成员资格 - {{projectName}}", + "ADD_BUTTON": "+ 新成员", + "ADD_BUTTON_TITLE": "增加新成员", + "LIMIT_USERS_WARNING_MESSAGE_FOR_ADMIN": "对不起,本项目已经达到它所允许的最多成员上限 ({{members}})。", + "LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "这个项目已经达到它的允许最多成员上限 ({{members}})。如果你希望增加这个上限,请联系管理员。" + }, + "PROJECT_EXPORT": { + "TITLE": "导出", + "SUBTITLE": "导出你的项目以备份,或以此为基础来创建一个新的。", + "EXPORT_BUTTON": "导出", + "EXPORT_BUTTON_TITLE": "导出你的项目", + "LOADING_TITLE": "档案正在生成中", + "DUMP_READY": "你的档案已经准备好了!", + "LOADING_MESSAGE": "请勿关闭本页", + "ASYNC_MESSAGE": "准备好后,我们会发送一封电子邮件", + "SYNC_MESSAGE": "如果未能自动下载,请点击此处.", + "ERROR": "我们的系统无法导出你的资料,请再试一次", + "ERROR_BUSY": "抱歉系统繁忙中,请稍后再试试" + }, + "MODULES": { + "TITLE": "模块", + "EPICS": "史诗", + "EPICS_DESCRIPTION": "可视化和管理你项目的最为要害的部分", + "BACKLOG": "待办事项", + "BACKLOG_DESCRIPTION": "管理你的用户故事,让接下来的及优先的工作能被有条理地查看", + "NUMBER_SPRINTS": "期待的冲刺数量", + "NUMBER_SPRINTS_HELP": "待确定的数量(0)", + "NUMBER_US_POINTS": "估计总的故事点", + "NUMBER_US_POINTS_HELP": "待确定的数量(0)", + "KANBAN": "看板", + "KANBAN_DESCRIPTION": "在此看板上组织你的项目", + "ISSUES": "问题", + "ISSUES_DESCRIPTION": "追踪错误,问题以及增强你的项目,不要错过任何事", + "WIKI": "维基文档", + "WIKI_DESCRIPTION": "新增,修正或是删除与他人合作的文档内容。这里正是项目文件记录区", + "MEETUP": "视频会议", + "MEETUP_DESCRIPTION": "选择你的视频会议系统", + "SELECT_VIDEOCONFERENCE": "选择一个视频会议系统", + "SALT_CHAT_ROOM": "为聊天室名称添加一个前缀", + "JITSI_CHAT_ROOM": "Jitsi", + "APPEARIN_CHAT_ROOM": "AppearIn", + "TALKY_CHAT_ROOM": "Talky", + "CUSTOM_CHAT_ROOM": "自定", + "URL_CHAT_ROOM": "聊天室之网址" + }, + "PROJECT_PROFILE": { + "PAGE_TITLE": "{{sectionName}} - 项目档案 - {{projectName}}", + "PROJECT_DETAILS": "项目细节", + "PROJECT_NAME": "项目名称", + "TAGS": "标签", + "DESCRIPTION": "描述", + "RECRUITING": "这个项目是否在招人?", + "RECRUITING_MESSAGE": "你在寻找什么人?", + "RECRUITING_PLACEHOLDER": "定义简介", + "FEEDBACK": "是否接收来自Taiga用户的反馈?", + "PUBLIC_PROJECT": "公开项目", + "PRIVATE_PROJECT": "私有项目", + "PRIVATE_OR_PUBLIC": "公开项目与私有项目有什么区别?", + "DELETE": "删除此项目", + "CHANGE_LOGO": "更换图标", + "ACTION_USE_DEFAULT_LOGO": "使用默认图片", + "MAX_PRIVATE_PROJECTS": "根据你当前计划,你已经达到了私有项目允许的最大成员限制", + "MAX_PRIVATE_PROJECTS_MEMBERS": "已超过私有项目的最大成员数目的限制", + "MAX_PUBLIC_PROJECTS": "对不起,根据你当前计划,你已经达到了公开项目允许的最大成员限制", + "MAX_PUBLIC_PROJECTS_MEMBERS": "作为公开项目,该项目已经超过了你的最大成员数目", + "PROJECT_OWNER": "项目所有者", + "REQUEST_OWNERSHIP": "请求项目所有权", + "REQUEST_OWNERSHIP_CONFIRMATION_TITLE": "你希望成为该项目的新所有者吗?", + "REQUEST_OWNERSHIP_DESC": "请求当前项目所有者 {{name}} 将项目所有权转给你。", + "REQUEST_OWNERSHIP_BUTTON": "要求", + "REQUEST_OWNERSHIP_SUCCESS": "我们将通知项目所有者", + "CHANGE_OWNER": "改变所有者", + "CHANGE_OWNER_SUCCESS_TITLE": "好,你的请求已经发出!", + "CHANGE_OWNER_SUCCESS_DESC": "如果项目所有者请求被接受或者被拒绝,我们将通过邮件通知你" + }, + "REPORTS": { + "TITLE": "报告", + "SUBTITLE": "以 CSV 格式导出你的项目资料,并制作你的专属报告", + "DESCRIPTION": "下载CSV档案格式是复制生成网址到常用的文字编辑软件/试算表,以保存你的项目资料报告。你可以轻易地视觉化和分析你的资料。", + "HELP": "如何使用我的表格软件?", + "REGENERATE_TITLE": "改变网址", + "REGENERATE_SUBTITLE": "你将要改变CSV资料的访问网址,之前的网址将失效。你确定要这样做吗?" + }, + "CSV": { + "SECTION_TITLE_EPIC": "史诗报告", + "SECTION_TITLE_US": "用户故事报告", + "SECTION_TITLE_TASK": "任务报告", + "SECTION_TITLE_ISSUE": "问题报告", + "DOWNLOAD": "下载CSV档案", + "URL_FIELD_PLACEHOLDER": "再次产生CSV 网址", + "TITLE_REGENERATE_URL": "再次产生CSV 网址", + "ACTION_GENERATE_URL": "产生网址", + "ACTION_REGENERATE": "再次产生" + }, + "CUSTOM_FIELDS": { + "TITLE": "自定义字段", + "SUBTITLE": "指定用户故事,任务与问题一些自定义字段", + "EPIC_DESCRIPTION": "史诗自定义字段", + "EPIC_ADD": "在史诗中加入自定义字段", + "US_DESCRIPTION": "用户自定义字段", + "US_ADD": "在用户故事中加入自定义字段", + "TASK_DESCRIPTION": "任务自定义字段", + "TASK_ADD": "在任务中加入自定义字段", + "ISSUE_DESCRIPTION": "问题自定义字段", + "ISSUE_ADD": "在问题中加入自定义字段", + "FIELD_TYPE_TEXT": "单行文字", + "FIELD_TYPE_RICHTEXT": "富文本", + "FIELD_TYPE_MULTI": "多行文字", + "FIELD_TYPE_DATE": "日期", + "FIELD_TYPE_URL": "链接" + }, + "PROJECT_VALUES": { + "PAGE_TITLE": "{{sectionName}} - 项目数值 - {{projectName}}", + "REPLACEMENT": "所有此值的项将被改成", + "ERROR_DELETE_ALL": "你不能删除所有的值" + }, + "PROJECT_VALUES_POINTS": { + "TITLE": "点数", + "SUBTITLE": "指定你的用户故事的估计点数为", + "US_TITLE": "用户故事点数", + "ACTION_ADD": "增加点数" + }, + "PROJECT_VALUES_PRIORITIES": { + "TITLE": "优先级", + "SUBTITLE": "指明你将遇到的问题优先程度", + "ISSUE_TITLE": "问题优先级", + "ACTION_ADD": "新增优先级" + }, + "PROJECT_VALUES_SEVERITIES": { + "TITLE": "严重程度", + "SUBTITLE": "指明你将遇到问题的严重程度", + "ISSUE_TITLE": "问题严重程度", + "ACTION_ADD": "新增严重程度" + }, + "PROJECT_VALUES_STATUS": { + "TITLE": "Statuses", + "SUBTITLE": "指明你的用户故事,任务以及问题经历的状态", + "EPIC_TITLE": "史诗状态", + "US_TITLE": "用户故事状态", + "TASK_TITLE": "任务状态", + "ISSUE_TITLE": "问题状态" + }, + "PROJECT_VALUES_TYPES": { + "TITLE": "类型", + "SUBTITLE": "指定你的问题类型可能是", + "ISSUE_TITLE": "问题类型", + "ACTION_ADD": "新增{{objName}}" + }, + "PROJECT_VALUES_TAGS": { + "TITLE": "标签", + "SUBTITLE": "查看并编辑你的用户故事的颜色", + "EMPTY": "当前没有标签", + "EMPTY_SEARCH": "看起来没有符合你的搜索条件的结果", + "ACTION_ADD": "新增标签", + "NEW_TAG": "新建标签", + "MIXING_HELP_TEXT": "选择你想合并的标签", + "MIXING_MERGE": "合并标签", + "SELECTED": "已选择" + }, + "ROLES": { + "PAGE_TITLE": "角色- {{projectName}}", + "WARNING_NO_ROLE": "注意,你的项目中无角色可以评估用户故事的点数", + "HELP_ROLE_ENABLED": "当启动时,被指派此角色的成员将可以评估用户故事点数", + "DISABLE_COMPUTABLE_ALERT_TITLE": "你确定要禁用这个角色评估吗?", + "DISABLE_COMPUTABLE_ALERT_SUBTITLE": "如果该角色“{{roleName}}”被禁止估算用户故事的点数,那么该角色以前做的所有评估将被删除", + "COUNT_MEMBERS": "{{ role.members_count }} 这类角色的成员", + "TITLE_DELETE_ROLE": "删除角色", + "REPLACEMENT_ROLE": "和此角色有关的用户都将被移除", + "WARNING_DELETE_ROLE": "小心!所有角色估算都将被移除", + "ERROR_DELETE_ALL": "你不能删除所有值", + "EXTERNAL_USER": "外部用户" + }, + "THIRD_PARTIES": { + "SECRET_KEY": "密钥", + "PAYLOAD_URL": "有效负荷网址", + "VALID_IPS": "有效来源IP(请用逗点分开)" + }, + "BITBUCKET": { + "SECTION_NAME": "Bitbucket", + "PAGE_TITLE": "Bitbucket - {{projectName}}", + "INFO_VERIFYING_IP": "Bitbucket要求不指派,因此最佳确认方式为IP位置来源。如果此处空白,表示IP未有效校验。" + }, + "GITLAB": { + "SECTION_NAME": "Gitlab", + "PAGE_TITLE": "Gitlab - {{projectName}}", + "INFO_VERIFYING_IP": "GitLab要求不指派因此最佳确认方式为IP位置来源。如果此处空白,表示IP未有效校验。" + }, + "GITHUB": { + "SECTION_NAME": "Github", + "PAGE_TITLE": "GitHub - {{projectName}}" + }, + "GOGS": { + "SECTION_NAME": "Gogs", + "PAGE_TITLE": "Gogs - {{projectName}}" + }, + "WEBHOOKS": { + "PAGE_TITLE": "网页钩子- {{projectName}}", + "SECTION_NAME": "网页触发", + "ADD_NEW": "新增一个网页触发", + "TYPE_NAME": "键入服务名称", + "TYPE_PAYLOAD_URL": "键入服务有效负荷网址", + "TYPE_SERVICE_SECRET": "键入服务密码钥匙", + "SAVE": "储存网页触发", + "CANCEL": "取消网页触发", + "SHOW_HISTORY": "(显示记录)", + "TEST": "测试网页触发", + "EDIT": "编辑网页触发", + "DELETE": "删除网页触发", + "REQUEST": "要求", + "RESEND_REQUEST": "重送出要求", + "HEADERS": "标头", + "PAYLOAD": "有效负荷", + "RESPONSE": "回应", + "DATE": "DD MMM YYYY [at] hh:mm", + "ACTION_HIDE_HISTORY": "(藏记录)", + "ACTION_HIDE_HISTORY_TITLE": "藏记录细节", + "ACTION_SHOW_HISTORY": "(显示记录)", + "ACTION_SHOW_HISTORY_TITLE": "显示记录细节", + "WEBHOOK_NAME": "网页触发 '{{name}}'" + }, + "CUSTOM_ATTRIBUTES": { + "PAGE_TITLE": "{{sectionName}} - 个性设置 - {{projectName}}", + "ADD": "加入自定义字段", + "EDIT": "编辑自定义字段", + "DELETE": "删除自定义字段", + "SAVE_TITLE": "储存自定义字段", + "CANCEL_TITLE": "取消创建", + "SET_FIELD_NAME": "设定你的自定义字段名称", + "SET_FIELD_DESCRIPTION": "设定你自定义字段的文字描述", + "FIELD_TYPE_DEFAULT": "-- 选择一个 --", + "ACTION_UPDATE": "更新自定义字段", + "ACTION_CANCEL_EDITION": "取消编辑" + }, + "MEMBERSHIP": { + "COLUMN_MEMBER": "成员", + "COLUMN_ADMIN": "管理者", + "COLUMN_ROLE": "角色", + "COLUMN_STATUS": "状态", + "STATUS_ACTIVE": "活跃", + "STATUS_PENDING": "待办中", + "DELETE_MEMBER": "删除成员", + "RESEND": "Resend", + "SUCCESS_SEND_INVITATION": "我们已再次发出邀请信给'{{email}}'.", + "SUCCESS_DELETE": "已删除 {{message}}.", + "ERROR_DELETE": "我们无法删除 {{message}}.", + "DEFAULT_DELETE_MESSAGE": "邀请 {{email}}" + }, + "DEFAULT_VALUES": { + "LABEL_EPIC_STATUS": "史诗状态选择器的默认值", + "LABEL_US_STATUS": "用户故事状态选择器的默认值", + "LABEL_POINTS": "点数选择器预设值", + "LABEL_TASK_STATUS": "任务状态选择器预设值", + "LABEL_ISSUE_TYPE": "问题类型选择器预设值", + "LABEL_ISSUE_STATUS": "问题状态选择器预设值", + "LABEL_PRIORITY": "优先选择器预设值", + "LABEL_SEVERITY": "严重程度选择器预设值" + }, + "STATUS": { + "PLACEHOLDER_WRITE_STATUS_NAME": "为此新状态命名" + }, + "TYPES": { + "PLACEHOLDER_WRITE_NAME": "为此新元素命名" + }, + "US_STATUS": { + "ACTION_ADD_STATUS": "增加新状态", + "IS_ARCHIVED_COLUMN": "归档", + "IS_CLOSED_COLUMN": "关闭", + "WIP_LIMIT_COLUMN": "WIP限制", + "PLACEHOLDER_WRITE_NAME": "为此新状态命名" + }, + "MENU": { + "PROJECT": "项目", + "ATTRIBUTES": "属性", + "MEMBERS": "成员", + "PERMISSIONS": "权限", + "INTEGRATIONS": "整合" + }, + "SUBMENU_PROJECT_VALUES": { + "STATUS": "状态", + "POINTS": "点数", + "PRIORITIES": "优先级", + "SEVERITIES": "严重程度", + "TYPES": "类型", + "CUSTOM_FIELDS": "自定义字段", + "TAGS": "标签" + }, + "SUBMENU_ROLES": { + "TITLE": "角色", + "ACTION_NEW_ROLE": "+ 新角色", + "TITLE_ACTION_NEW_ROLE": "新增角色" + }, + "PROJECT_TRANSFER": { + "DO_YOU_ACCEPT_PROJECT_OWNERNSHIP": "你希望成为新的项目所有者吗?", + "PRIVATE": "私有的", + "ACCEPTED_PROJECT_OWNERNSHIP": "恭喜你!你现在是项目新的所有者了。", + "REJECTED_PROJECT_OWNERNSHIP": "好的。我们将联系当前项目的所有者", + "ACCEPT": "接受", + "REJECT": "拒绝", + "PROPOSE_OWNERSHIP": "{{owner}}, 当前项目 {{project}} 的所有者要求你成为项目的新的所有者。", + "ADD_COMMENT": "你愿意为项目所有者添加一条评论吗?", + "UNLIMITED_PROJECTS": "无线的", + "OWNER_MESSAGE": { + "PRIVATE": "请记住你可以拥有最多 {{maxProjects}} 个私有项目。你当前拥有 {{currentProjects}} 个私有项目", + "PUBLIC": "请记住你最多可以拥有 {{maxProjects}} 个公开项目。你当前拥有 {{currentProjects}} 个公开项目" + }, + "CANT_BE_OWNED": "目前你不能成为这类项目的所有者。如果你希望成为这个项目的所有者,请联系管理员,请其在你的账户设置中启用项目所有权。" + } + }, + "USER": { + "PROFILE": { + "PAGE_TITLE": "{{userFullName}} (@{{userUsername}})", + "EDIT": "编辑个人资料", + "CLOSED_US": "关闭用户故事", + "PROJECTS": "项目", + "PROJECTS_EMPTY": "{{username}} 尚无项目", + "CONTACTS": "联络人", + "CONTACTS_EMPTY": "{{username}} 尚无联络人", + "CURRENT_USER_CONTACTS_EMPTY": "您尚无任何联络人", + "CURRENT_USER_CONTACTS_EMPTY_EXPLAIN": "你在Taiga一同工作的伙伴将自动成为你的联络人", + "TABS": { + "ACTIVITY_TAB": "时间表", + "ACTIVITY_TAB_TITLE": "显示该用户的所有活动", + "PROJECTS_TAB": "项目", + "PROJECTS_TAB_TITLE": "列出该用户参与的所有项目", + "LIKES_TAB": "Likes", + "LIKES_TAB_TITLE": "List all likes made by this user", + "VOTES_TAB": "投票数", + "VOTES_TAB_TITLE": "列出该用户的所有投票", + "WATCHED_TAB": "关注", + "WATCHED_TAB_TITLE": "列出该用户关注的所有事项", + "CONTACTS_TAB": "联络人", + "CONTACTS_TAB_TITLE": "列出这个用户的所有联系人" + } + }, + "PROFILE_SIDEBAR": { + "TITLE": "个人信息", + "DESCRIPTION": "其他人可以看到你做的所有事情以及正在做的事情。添加一个好的简历可以使得你的个人信息更为丰满。", + "ADD_INFO": "编辑个人简介" + }, + "PROFILE_FAVS": { + "FILTER_INPUT_PLACEHOLDER": "输入内容...", + "FILTER_TYPE_ALL": "所有", + "FILTER_TYPE_ALL_TITLE": "显示所有", + "FILTER_TYPE_PROJECTS": "项目", + "FILTER_TYPE_PROJECTS_TITLE": "只显示项目", + "FILTER_TYPE_EPICS": "史诗", + "FILTER_TYPE_EPICS_TITLE": "仅显示史诗", + "FILTER_TYPE_USER_STORIES": "故事", + "FILTER_TYPE_USER_STORIES_TITLE": "只显示用户故事", + "FILTER_TYPE_TASKS": "任务", + "FILTER_TYPE_TASKS_TITLE": "只显示任务", + "FILTER_TYPE_ISSUES": "问题", + "FILTER_TYPE_ISSUES_TITLE": "只显示问题", + "EMPTY_TITLE": "看来没有什么可以显示的." + } + }, + "PROJECT": { + "PAGE_TITLE": "{{projectName}}", + "HELP": "记录你的项目在上方常用栏位
前十个项目将会显示在上方导览处。", + "PRIVATE": "私有项目", + "LOOKING_FOR_PEOPLE": "这个项目在寻找队友", + "FANS_COUNTER_TITLE": "{total, plural, one{一个粉丝} other{# 个粉丝}}", + "WATCHERS_COUNTER_TITLE": "{total, plural, one{一个关注者} other{# 个关注者}}", + "MEMBERS_COUNTER_TITLE": "{total, plural, one{一个成员} other{# 个成员}}", + "BLOCKED_PROJECT": { + "BLOCKED": "关闭项目", + "THIS_PROJECT_IS_BLOCKED": "这个项目暂时被关闭了", + "TO_UNBLOCK_CONTACT_THE_ADMIN_STAFF": "要解冻你的项目,请联系管理员。" + }, + "SECTION": { + "SEARCH": "搜索", + "TIMELINE": "时间表", + "BACKLOG": "待办任务", + "KANBAN": "看板", + "ISSUES": "问题", + "WIKI": "维基", + "TEAM": "团队", + "MEETUP": "视频会议", + "ADMIN": "管理者" + }, + "NAVIGATION": { + "ACTION_CREATE_PROJECT": "创建项目", + "MANAGE_PROJECTS": "管理项目", + "TITLE_CREATE_PROJECT": "创建项目", + "HELP_TITLE": "Taiga支持页", + "HELP": "帮助", + "HOMEPAGE": "主页", + "FEEDBACK_TITLE": "发送反馈", + "FEEDBACK": "反馈", + "NOTIFICATIONS_TITLE": "编辑个人通知设定", + "NOTIFICATIONS": "通知", + "VIEW_PROFILE_TITLE": "查看个人资料", + "VIEW_PROFILE": "查看个人资料", + "EDIT_PROFILE_TITLE": "编辑你的个人资料", + "EDIT_PROFILE": "编辑个人资料", + "CHANGE_PASSWORD_TITLE": "更换密码", + "CHANGE_PASSWORD": "更换密码", + "DASHBOARD_TITLE": "控制台", + "DISCOVER_TITLE": "发现流行项目", + "DISCOVER": "发现" + }, + "LIKE_BUTTON": { + "LIKE": "点赞", + "LIKED": "已点赞", + "UNLIKE": "取消点赞", + "BUTTON_TITLE": "对这个项目点赞或者取消点赞", + "COUNTER_TITLE": "{total, plural, one{一个粉丝} other{# 个粉丝}}" + }, + "WATCH_BUTTON": { + "BUTTON_TITLE": "关注这个项目并设置通知规则", + "WATCH": "Watch", + "WATCHING": "关注中", + "COUNTER_TITLE": "{total, plural, one{一个关注者} other{# 个关注者}}", + "OPTIONS": { + "NOTIFY_ALL": "接收所有通知", + "NOTIFY_ALL_TITLE": "接收这个项目的所有通知", + "NOTIFY_INVOLVED": "只接收相关通知", + "NOTIFY_INVOLVED_TITLE": "只接收与你相关的通知", + "UNWATCH": "取消关注", + "UNWATCH_TITLE": "取消关注这个项目" + } + }, + "CONTACT_BUTTON": { + "CONTACT_TITLE": "联系项目组", + "CONTACT_BUTTON": "联系项目组" + }, + "CREATE": { + "TITLE": "创建项目", + "CHOOSE_TEMPLATE": "哪个模板更适合你的项目?", + "TEMPLATE_SCRUM": "冲刺", + "TEMPLATE_SCRUM_DESC": "Prioritize and solve your tasks in short time cycles.", + "TEMPLATE_SCRUM_LONGDESC": "Scrum is an iterative and incremental agile software development methodology for managing product development.\nThe product backlog is what will ultimately be delivered, ordered into the sequence in which it should be delivered. Product Backlogs are broken into manageable, executable chunks named sprints. Every certain amount of time the team initiates a new sprint and commits to deliver a certain number of user stories from the backlog, in accordance with their skills, abilities and resources. The project advances as the backlog becomes depleted.", + "TEMPLATE_KANBAN": "看板", + "TEMPLATE_KANBAN_DESC": "Keep a constant workflow on independent tasks", + "TEMPLATE_KANBAN_LONGDESC": "The Kanban methodology is used to divide project development (any sort of project) into stages.\nA kanban card is like an index card or post-it note that details every task (or user story) in a project that needs to be completed. The Kanban board is used to move each card from one state of completion to the next and in so doing, helps track progress.", + "DUPLICATE": "复制项目", + "DUPLICATE_DESC": "Start clean and keep your configuration", + "IMPORT": "导入项目", + "IMPORT_DESC": "从多平台导入你的项目到Taiga", + "INVITE": "邀请加入项目", + "SOLO_PROJECT": "你会单独加入这个项目", + "INVITE_LATER": "(你可以在之后邀请更多成员)", + "BACK": "后退", + "MAX_PRIVATE_PROJECTS": "很抱歉,你创建的私有项目数量已到达限制。如果想创建更多私有项目,请联系管理员", + "MAX_PUBLIC_PROJECTS": "Unfortunately, You've reached the maximum number of public projects.\nIf you would like to increase the current limit please contact the administrator.", + "PUBLIC_PROJECT": "公开项目", + "PRIVATE_PROJECT": "私有项目" + }, + "COMMON": { + "DETAILS": "新的项目详情", + "PROJECT_TITLE": "项目名称", + "PROJECT_DESCRIPTION": "项目描述" + }, + "DUPLICATE": { + "TITLE": "复制项目", + "DESCRIPTION": "Start clean and keep your configuration", + "SELECT_PLACEHOLDER": "选择一个已存在的项目来复制" + }, + "IMPORT": { + "TITLE": "导入项目", + "DESCRIPTION": "从多平台导入你的项目到Taiga", + "ASYNC_IN_PROGRESS_TITLE": "我们正在导入你的项目", + "ASYNC_IN_PROGRESS_MESSAGE": "这个过程要花上一点时间
当弄好时我们会发给你一封邮件", + "UPLOAD_IN_PROGRESS_MESSAGE": "已上传 {{totalSize}}中的{{uploadedSize}}", + "ERROR": "系统在滙进你倒入的资料时遇上一些问题,请再试一次", + "ERROR_TOO_MANY_REQUEST": "抱歉系统繁忙中,请稍后再试试", + "ERROR_MESSAGE": "我们的系统无法导入你的资料", + "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) 超过系统设置的附件体积上限, 请重传小一点的附件 ({{maxFileSize}})", + "SYNC_SUCCESS": "你的项目已成功导入", + "IMPORT": "导入", + "WHO_IS": "Their tasks will be assigned to ...", + "WRITE_EMAIL": "Or if you want, write the email that this user uses in Taiga", + "SEARCH_CONTACT": "Or if you want, search in your contacts", + "WRITE_EMAIL_LABEL": "Write the email that this user uses in Taiga", + "ACCEEDE": "Acceede", + "PROJECT_MEMBERS": "项目成员", + "PROCESS_DESCRIPTION": "Tell us who from Taiga you want to assign the tasks of {{platform}}", + "MATCH": "{{user_external}}{{user_internal}}是同一个人吗?", + "CHOOSE": "选择用户", + "LINKS": "Links with {{platform}}", + "LINKS_DESCRIPTION": "Do you want to keep the link of each item with the original {{platform}} card?", + "WARNING_MAIL_USER": "Note that if the user does not have a Taiga account we will not be able to assign the tasks to him.", + "ASSIGN": "指派", + "PROJECT_SELECTOR": { + "NO_RESULTS": "看起来没有符合你的搜索条件的结果", + "ACTION_SEARCH": "搜索", + "ACTION_BACK": "后退" + }, + "PROJECT_RESTRICTIONS": { + "PROJECT_MEMBERS_DESC_PRIVATE": "The project you are trying to import has {{members}} members including you, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per private project. If you would like to increase that limit please contact the administrator.", + "PROJECT_MEMBERS_DESC_PUBLIC": "The project you are trying to import has {{members}} members including you, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per public project. If you would like to increase that limit please contact the administrator.", + "ACCOUNT_ALLOW_MEMBERS": "Your account only allows {{members}} members", + "PRIVATE_PROJECTS_SPACE": { + "TITLE": "对不起,你当前的计划不允许额外的私有项目", + "DESC": "你尝试导入的项目是私有的。不幸的是,你当前的计划不允许额外的私有项目。" + }, + "PUBLIC_PROJECTS_SPACE": { + "TITLE": "对不起,你当前的计划不允许额外的公开项目", + "DESC": "你尝试导入的项目是公开的。不幸的是,你当前的计划不允许额外的公开项目。" + }, + "PRIVATE_PROJECTS_MEMBERS": { + "TITLE": "你当前的计划允许每个私有项目最多 {{max_memberships}} 位成员。" + }, + "PUBLIC_PROJECTS_MEMBERS": { + "TITLE": "你当前的计划允许每个项目最多 {{max_memberships}} 位成员。" + }, + "PRIVATE_PROJECTS_SPACE_MEMBERS": { + "TITLE": "对不起,你当前的计划不允许额外的私有项目或者每个私有项目多于 {{max_memberships}} 位成员", + "DESC": "你正在试图导入的项目是私有的并且有 {{members}} 位成员。" + }, + "PUBLIC_PROJECTS_SPACE_MEMBERS": { + "TITLE": "对不起,你当前的计划不允许额外的公开项目或者每个公开项目多于 {{max_memberships}} 位成员", + "DESC": "你正在试图导入的项目是公开的并且有多于 {{members}} 位成员。" + } + }, + "IN_PROGRESS": { + "TITLE": "导入项目中", + "DESCRIPTION": "这个过桯要花点时间,请保持视窗开启" + }, + "WARNING": { + "TITLE": "Some taks will be unassigned", + "DESCRIPTION": "There are still unidentified people. The cards assigned to these people will remain unassigned. Check all the contacts to not lose that information.", + "CHECK": "Check contacts" + }, + "TAIGA": { + "SELECTOR": "Import your Taiga project" + }, + "TRELLO": { + "SELECTOR": "Import your Trello boards into Taiga", + "CHOOSE_PROJECT": "Choose board that you want to import", + "NO_PROJECTS": "It seems you have no boards in Trello" + }, + "GITHUB": { + "SELECTOR": "Import your GitHub project issues", + "CHOOSE_PROJECT": "查找你想要导入的项目", + "NO_PROJECTS": "It seems you have no porjects in GitHub", + "HOW_DO_YOU_WANT_TO_IMPORT": "How do you want to import your issues into Taiga?", + "KANBAN_PROJECT": "As user stories in a kanban project", + "KANBAN_PROJECT_DESCRIPTION": "After that you can enable scrum with backlog.", + "SCRUM_PROJECT": "As user stories in a scrum project", + "SCRUM_PROJECT_DESCRIPTION": "After that you can enable kanban mode.", + "ISSUES_PROJECT": "As issues", + "ISSUES_PROJECT_DESCRIPTION": "You will not be able to use your issues in kanban or scrum mode. You will be able to enable kanban or scrum for new user stories" + }, + "ASANA": { + "SELECTOR": "Import your Asana project and choose how to manage it", + "CHOOSE_PROJECT": "选择你想导入的项目", + "NO_PROJECTS": "It seems you have no porjects in Asana", + "KANBAN_PROJECT": "看板", + "SCRUM_PROJECT": "冲刺", + "CREATE_AS_SCRUM_DESCRIPTION": "The tasks and sub-tasks of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_KANBAN_DESCRIPTION": "The tasks and sub-tasks of your project will be created as Taiga user stories and tasks." + }, + "JIRA": { + "SELECTOR": "Import your Jira project and choose how to manage it", + "CHOOSE_PROJECT": "Choose project or board that you want to import", + "NO_PROJECTS": "It seems you have no porjects or boards in Jira", + "URL": "Your Jira URL", + "KANBAN_PROJECT": "看板", + "SCRUM_PROJECT": "冲刺", + "ISSUES_PROJECT": "问题", + "CREATE_AS_SCRUM_DESCRIPTION": "The issues and sub-issues of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_KANBAN_DESCRIPTION": "The issues and sub-issues of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_ISSUES_DESCRIPTION": "What do you want to do with sub-issues from the Jira project? (Taiga doesn't allow sub-issues)", + "CREATE_NEW_ISSUES": "Convert sub-issues to new Taiga issues", + "NOT_CREATE_NEW_ISSUES": "Do not import sub-issues" + } + } + }, + "LIGHTBOX": { + "DELETE_ACCOUNT": { + "CONFIRM": "你确定要删除Taiga账户吗?", + "CANCEL": "返回设置", + "ACCEPT": "删除账号", + "BLOCK_PROJECT": "请注意,在你删除你的账户之后,所有属于你的项目都会被冻结。如果你确实希望一个项目被冻结,在你删除你的账户之前,请将所有权转移至该项目的其他成员名下。" + }, + "DELETE_PROJECT": { + "TITLE": "删除项目", + "QUESTION": "你确定要删除这个项目吗?", + "SUBTITLE": "所有项目资料 (用户故事/任务/问题/冲刺/维基页面) 将会丢失! :-(", + "CONFIRM": "是的,我很确定" + }, + "ASSIGNED_TO": { + "SELECT": "选择要指派给", + "SEARCH": "搜索用户" + }, + "ADD_MEMBER": { + "TITLE": "新成员", + "PLACEHOLDER": "筛选用户或者编写邮件来进行邀请", + "ADD_EMAIL": "添加收件人邮箱", + "REMOVE": "移除", + "INVITE": "邀请", + "CHOOSE_ROLE": "选择一个角色", + "PLACEHOLDER_INVITATION_TEXT": "(非必要) 加上一段私人文字在邀请信,告诉你的新成员一些好事 ;-)", + "HELP_TEXT": "如果用户已注册Taiga账户,他们会自动被加入。否则他们会收到一封加入的邀请信" + }, + "CREATE_ISSUE": { + "TITLE": "新增问题" + }, + "FEEDBACK": { + "TITLE": "告诉我们你的故事", + "COMMENT": "系统错误,有改进建议有乐趣,或者是你使用Taiga 上的恶梦?", + "ACTION_SEND": "送出反馈" + }, + "SEARCH": { + "TITLE": "搜索", + "PLACEHOLDER_SEARCH": "你在找什么?" + }, + "ADD_EDIT_SPRINT": { + "TITLE": "新冲刺任务", + "PLACEHOLDER_SPRINT_NAME": "冲刺任务名称", + "PLACEHOLDER_SPRINT_START": "预估开始", + "PLACEHOLDER_SPRINT_END": "预估结束", + "ACTION_DELETE_SPRINT": "你确定要删除这个冲刺任务吗?", + "TITLE_ACTION_DELETE_SPRINT": "删除冲刺任务", + "LAST_SPRINT_NAME": "最后冲刺任务 {{lastSprint}} ;-) " + }, + "CREATE_EDIT_TASK": { + "TITLE": "新任务", + "PLACEHOLDER_SUBJECT": "任务主旨", + "PLACEHOLDER_STATUS": "任务状态", + "OPTION_UNASSIGNED": "未指派", + "PLACEHOLDER_SHORT_DESCRIPTION": "输入一段简短描述", + "ACTION_EDIT": "编辑任务" + }, + "CREATE_EDIT_US": { + "TITLE": "新建用户故事", + "PLACEHOLDER_DESCRIPTION": "请加上一些描述文字以帮助其它人了解此用户故事", + "NEW_US": "新建用户故事", + "EDIT_US": "编辑用户故事" + }, + "DELETE_SPRINT": { + "TITLE": "删除冲刺任务" + }, + "CREATE_MEMBER": { + "PLACEHOLDER_INVITATION_TEXT": "(非必要) 加上一段私人文字在邀请信,告诉你的新成员一些好事 ;-)", + "PLACEHOLDER_TYPE_EMAIL": "输入一个电邮地址", + "LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "对不起,该项目不能超过 {{maxMembers}} 位成员。
如果你希望增加当前限制,请联系管理员。", + "LIMIT_USERS_WARNING_MESSAGE": "对不起,本项目不能有超过 {{maxMembers}} 名成员。" + }, + "LEAVE_PROJECT_WARNING": { + "TITLE": "对不起,该项目不允许在没有所有者的情况下离开", + "CURRENT_USER_OWNER": { + "DESC": "你是本项目的当前所有者。在离开之前,请将所有权转移给其他成员。", + "BUTTON": "改变项目拥有者" + }, + "OTHER_USER_OWNER": { + "DESC": "对不起,你不能删除作为当前项目所有者的成员。首先,请指派一位新的项目所有者。", + "BUTTON": "请求项目所有者改变" + } + }, + "CHANGE_OWNER": { + "TITLE": "你希望谁作为项目的新的所有者?", + "ADD_COMMENT": "评论", + "BUTTON": "要求这位项目成员作为新的项目所有者" + }, + "CONTACT_PROJECT": { + "TITLE": "发送邮件到", + "WARNING": "项目管理员会收到邮件", + "PLACEHOLDER": "输入你的消息", + "SEND": "发送" + } + }, + "EPIC": { + "PAGE_TITLE": "{{epicSubject}} - 史诗{{epicRef}} - {{projectName}}", + "PAGE_DESCRIPTION": "状态:{{epicStatus}}。描述:{{epicDescription}}", + "SECTION_NAME": "史诗", + "TITLE_LIGHTBOX_UNLINK_RELATED_USERSTORY": "断开相关用户故事链接", + "MSG_LIGHTBOX_UNLINK_RELATED_USERSTORY": "这将删除到相关用户故事的链接'{{subject}}'", + "ERROR_UNLINK_RELATED_USERSTORY": "无法断开链接:{{errorMessage}}", + "CREATE_RELATED_USERSTORIES": "创建关系", + "NEW_USERSTORY": "新建用户故事", + "EXISTING_USERSTORY": "退出用户故事", + "CHOOSE_PROJECT_FOR_CREATION": "项目是什么", + "SUBJECT": "主题", + "SUBJECT_BULK_MODE": "题目(批量插入)", + "CHOOSE_PROJECT_FROM": "项目是什么", + "CHOOSE_USERSTORY": "用户故事是什么", + "NO_USERSTORIES": "该项目无用户故事。请选择其他项目。", + "FILTER_USERSTORIES": "过滤用户故事", + "LIGHTBOX_TITLE_BLOKING_EPIC": "屏蔽史诗", + "ACTION_DELETE": "删除史诗" + }, + "US": { + "PAGE_TITLE": "{{userStorySubject}} - 用户故事 {{userStoryRef}} - {{projectName}}", + "PAGE_DESCRIPTION": "状态: {{userStoryStatus }},已完成 {{userStoryProgressPercentage}}% (任务总数 {{userStoryTotalTasks}},已关闭{{userStoryClosedTasks}}),点数: {{userStoryPoints}},描述: {{userStoryDescription}}", + "SECTION_NAME": "用户故事", + "LINK_TASKBOARD": "任务板", + "TITLE_LINK_TASKBOARD": "到任务板去", + "TOTAL_POINTS": "总点数", + "ADD": "+新增用户故事", + "ADD_BULK": "批次加入新用户故事", + "PROMOTED": "此用户故事已提升成问题:", + "TITLE_LINK_GO_TO_ISSUE": "到问题", + "TITLE_DELETE_ACTION": "删除用户故事", + "LIGHTBOX_TITLE_BLOKING_US": "封锁中的用户故事", + "NOT_ESTIMATED": "无预估", + "TRIBE": { + "PUBLISH": "以Gig的形式在Taiga Tribe中发布", + "PUBLISH_INFO": "更多信息", + "PUBLISH_TITLE": "在Taiga Tribe中查找关于发布的更多信息", + "PUBLISHED_AS_GIG": "用户故事已经以Gig的形式在Taiga Tribe中发布", + "EDIT_LINK": "编辑链接", + "CLOSE": "关闭", + "SYNCHRONIZE_LINK": "与Taiga Tribe同步", + "PUBLISH_MORE_INFO_TITLE": "你是否需要其他人来做这个任务?", + "PUBLISH_MORE_INFO_TEXT": "

If you need help with a particular piece of work you can easily create gigs on Taiga Tribe and receive help from all over the world. You will be able to control and manage the gig enjoying a great community eager to contribute.

TaigaTribe was born as a Taiga sibling. Both platforms can live separately but we believe that there is much power in using them combined so we are making sure the integration works like a charm.

" + }, + "FIELDS": { + "TEAM_REQUIREMENT": "团队要求", + "CLIENT_REQUIREMENT": "客户要求" + } + }, + "COMMENTS": { + "DELETED_INFO": "评论被用户{{user}}删除", + "COMMENTS_COUNT": "{{comments}}评论", + "OLDER_FIRST": "上次第一名", + "RECENT_FIRST": "最近第一名", + "COMMENT": "评论", + "EDITED_COMMENT": "已编辑", + "SHOW_HISTORY": "查看历史", + "TYPE_NEW_COMMENT": "在此输入一个新的评论", + "SHOW_DELETED": "显示遭删除的评论", + "HIDE_DELETED": "隐藏已删除之评论", + "DELETE": "删除评论", + "RESTORE": "恢复原评论", + "HISTORY": { + "TITLE": "动态" + } + }, + "ACTIVITY": { + "TITLE": "动态", + "ACTIVITIES_COUNT": "{{activities}} 活动", + "TAGS_ADDED": "已添加的标签", + "TAGS_REMOVED": "已移除的标签", + "US_POINTS": "{{role}} 得分", + "NEW_ATTACHMENT": "新附件", + "DELETED_ATTACHMENT": "删除附件:", + "UPDATED_ATTACHMENT": "更新附件 ({{filename}}):", + "CREATED_CUSTOM_ATTRIBUTE": "创建自定义属性", + "UPDATED_CUSTOM_ATTRIBUTE": "更新自定义属性", + "BECAME_DEPRECATED": "已置为废弃", + "BECAME_UNDEPRECATED": "已置为废弃", + "TEAM_REQUIREMENT": "团队要求", + "CLIENT_REQUIREMENT": "客户要求", + "BLOCKED": "已封锁", + "VALUES": { + "UNASSIGNED": "未指派" + }, + "FIELDS": { + "SUBJECT": "主旨", + "DESCRIPTION": "描述", + "STATUS": "状态", + "TYPE": "类型", + "ASSIGNED_TO": "指派给", + "MILESTONE": "冲刺任务", + "COLOR": "颜色" + } + }, + "BACKLOG": { + "PAGE_TITLE": "待办任务 - {{projectName}}", + "PAGE_DESCRIPTION": "待办任务面板 {{projectName}}(项目的用户故事与冲刺任务): {{projectDescription}}", + "SECTION_NAME": "待办任务", + "CUSTOMIZE_GRAPH": "自定义你的代办任务图表", + "CUSTOMIZE_GRAPH_TEXT": "一个好的图表可以帮助你更好地跟随项目进展,这就要求你设置好点数和冲刺", + "CUSTOMIZE_GRAPH_ADMIN": "管理者", + "CUSTOMIZE_GRAPH_TITLE": "通过管理员来设置点数和冲刺", + "MOVE_US_TO_CURRENT_SPRINT": "移到目前的冲刺", + "MOVE_US_TO_LATEST_SPRINT": "切换到最近的冲刺", + "EMPTY": "没有待办任务!", + "CREATE_NEW_US": "创建一个新的用户故事", + "CREATE_NEW_US_EMPTY_HELP": "你可以创建一个新用户故事", + "EXCESS_OF_POINTS": "超过的点数", + "PENDING_POINTS": "待核点数", + "CLOSED_POINTS": "关闭", + "COMPACT_SPRINT": "浓缩冲刺点数", + "GO_TO_TASKBOARD": "前往任务板 {{spring.name}}", + "EDIT_SPRINT": "编辑冲刺任务", + "TOTAL_POINTS": "全部", + "STATUS_NAME": "状态名称", + "SORTABLE_FILTER_ERROR": "当过滤器开启时,无法放入待办任务", + "DOOMLINE": "项目规模 [Doomline]", + "CHART": { + "XAXIS_LABEL": "冲刺任务", + "YAXIS_LABEL": "点数", + "OPTIMAL": "最适化的冲刺任务\"{{sprintName}}\"待定点数应为 {{value}}", + "REAL": "真实的冲刺任务\"{{sprintName}}\"待定点数为 {{value}}", + "INCREMENT_TEAM": "团队要求的冲刺任务\"{{sprintName}}\"渐增点数为 {{value}}", + "INCREMENT_CLIENT": "客户要求的冲刺任务\"{{sprintName}}\"渐增点数为 {{value}}" + }, + "TAGS": { + "TOGGLE": "切换标签可见度", + "SHOW": "显示标签", + "HIDE": "隐藏标签" + }, + "FORECASTING": { + "TITLE": "速度预测", + "BACKLOG": "显示待办任务", + "NEW_SPRINT": "根据进度确定下一个冲刺目标的候选用户故事。点击创建新的冲刺目标。", + "CURRENT_SPRINT": "根据进度确定当前冲刺目标的候选用户故事。点击创建当前的冲刺目标。" + }, + "TABLE": { + "COLUMN_US": "用户故事", + "TITLE_COLUMN_POINTS": "选择检示每个角色" + }, + "SPRINT_SUMMARY": { + "TOTAL_POINTS": "全部
点数", + "COMPLETED_POINTS": "已完成
点数", + "OPEN_TASKS": "开启
任务", + "CLOSED_TASKS": "已关闭
任务", + "IOCAINE_DOSES": "毒物(全新任务挑战)
剂量", + "SHOW_STATISTICS_TITLE": "显示统计", + "TOGGLE_BAKLOG_GRAPH": "显示/隐藏 剩余工作量图", + "POINTS_PER_ROLE": "每角色的点数" + }, + "SUMMARY": { + "PROJECT_POINTS": "项目
点数", + "DEFINED_POINTS": "已定义
点数", + "CLOSED_POINTS": "已关闭
点数", + "POINTS_PER_SPRINT": "点数 /
冲刺任务" + }, + "FILTERS": { + "TOGGLE": "切换过滤器可见度", + "HIDE": "隐藏过滤器", + "SHOW": "显示过滤器" + }, + "SPRINTS": { + "TITLE": "冲刺任务", + "DATE": "DD MMM YYYY", + "LINK_TASKBOARD": "冲刺任务板", + "TITLE_LINK_TASKBOARD": "到任务板 {{spring.name}}", + "EMPTY": "还没有冲刺", + "WARNING_EMPTY_SPRINT_ANONYMOUS": "这个冲刺没有用户故事", + "WARNING_EMPTY_SPRINT": "从你的待办事项中拖拽一个用户故事到这里来开启一个新的冲刺", + "TITLE_ACTION_NEW_SPRINT": "添加一个新的冲刺", + "TEXT_ACTION_NEW_SPRINT": "你可能希望在你的项目中创建一个新的冲刺", + "ACTION_SHOW_CLOSED_SPRINTS": "显示关闭冲刺任务", + "ACTION_HIDE_CLOSED_SPRINTS": "隐藏冲刺任务" + } + }, + "ERROR": { + "TEXT1": "系统出了一点问题,工程师正在抢修中", + "NOT_FOUND": "找不到", + "NOT_FOUND_TEXT": "Error 404,你要找的网页不存在,你可以稍后再回来Taiga首页,看看是否能再次找到要找的东西。", + "PERMISSION_DENIED": "无此权限", + "PERMISSION_DENIED_TEXT": "你无权访问这个页面", + "VERSION_ERROR": "Taiga某人之前更改了这个,而我们的工程师无法再做改变。请重新载入页面来使用你的更新(之前设定将消失)" + }, + "TASKBOARD": { + "PAGE_TITLE": "{{sprintName}} - 冲刺任务看板 - {{projectName}}", + "PAGE_DESCRIPTION": "冲刺任务 {{sprintName}} (项目 {{projectName}} 从 {{startDate}} 到 {{endDate}})。完成比例{{completedPercentage}}% (总点数 {{totalPoints}} 点,完成 {{completedPoints}} 点)。总任务数 {{totalTasks}},开启任务数 {{openTasks}}。", + "SECTION_NAME": "任务板", + "TITLE_ACTION_ADD": "增加新任务", + "TITLE_ACTION_ADD_BULK": "批次加入新任务", + "TITLE_ACTION_ASSIGN": "指派任务", + "PLACEHOLDER_CARD_TITLE": "这可能是一个任务", + "PLACEHOLDER_CARD_TEXT": "将用户故事拆分为多个任务以便单独跟踪", + "TABLE": { + "COLUMN": "用户故事", + "TITLE_ACTION_FOLD": "隐藏栏位", + "TITLE_ACTION_UNFOLD": "未隐藏栏位", + "TITLE_ACTION_FOLD_ROW": "隐藏列数", + "TITLE_ACTION_UNFOLD_ROW": "未隐藏列数", + "FIELD_POINTS": "点数", + "ROW_UNASSIGED_TASKS_TITLE": "未指派的任务" + }, + "CHARTS": { + "XAXIS_LABEL": "天数", + "YAXIS_LABEL": "点数", + "OPTIMAL": "一天最适待办点数 {formattedDate},应为 {{roundedValue}}", + "REAL": "一天真实的待办点数 {{formattedDate}},应为 {{roundedValue}}", + "DATE": "DD MMM YYYY" + } + }, + "TASK": { + "PAGE_TITLE": "{{taskSubject}} - 任务 {{taskRef}} - {{projectName}}", + "PAGE_DESCRIPTION": "状态:{{taskStatus }}。描述:{{taskDescription}}", + "SECTION_NAME": "任务", + "LINK_TASKBOARD": "任务板", + "TITLE_LINK_TASKBOARD": "到任务板去", + "PLACEHOLDER_SUBJECT": "键入新任务主旨", + "TITLE_SELECT_STATUS": "状态名称", + "OWNER_US": "这任务属于", + "TITLE_LINK_GO_OWNER": "到用户故事", + "TITLE_DELETE_ACTION": "删除任务", + "LIGHTBOX_TITLE_BLOKING_TASK": "封锁中的任务", + "FIELDS": { + "IS_IOCAINE": "负予全新任务" + }, + "TITLE_ACTION_IOCAINE": "感到任务的不勘负荷?确定其它人知道此状况在编辑任务时点选此「毒药键」。这种致命毒物如果长期吸食微量,最后可能免疫。因此你最好偶而做点出奇的挑战。" + }, + "NOTIFICATION": { + "OK": "一切顺利", + "WARNING": "哇,有状况发生", + "WARNING_TEXT": "很抱歉你的变动并未成功保存", + "SAVED": "系统已保存你所有变动", + "CLOSE": "关闭通知", + "MAIL": "通过邮件通知", + "ASK_DELETE": "你确定要删除吗?" + }, + "CANCEL_ACCOUNT": { + "TITLE": "注销您的账户", + "SUBTITLE": "很遗憾你要离开Taiga,希望你喜欢这段时光~", + "PLACEHOLDER_INPUT_TOKEN": "注销账户代码", + "ACTION_LEAVING": "是的,我要走了", + "SUCCESS": "我们系统已移除你的账户" + }, + "CHANGE_EMAIL_FORM": { + "TITLE": "变更电子邮件", + "SUBTITLE": "确认要更新你的电子邮件", + "PLACEHOLDER_INPUT_TOKEN": "变更电邮代码", + "ACTION_CHANGE_EMAIL": "变更电邮地址", + "SUCCESS": "我们系统已更新你的电子邮件地址" + }, + "ISSUES": { + "PAGE_TITLE": "问题 - {{projectName}}", + "PAGE_DESCRIPTION": "{{projectName}}的问题清单看版:{{projectDescription}}", + "SECTION_NAME": "问题", + "ACTION_NEW_ISSUE": "+ 新问题", + "ACTION_PROMOTE_TO_US": "提升到用户故事", + "PROMOTED": "此问题已提升为用户故事", + "EXTERNAL_REFERENCE": "此问题的提出者是", + "GO_TO_EXTERNAL_REFERENCE": "回到开头", + "ACTION_DELETE": "删除议题", + "LIGHTBOX_TITLE_BLOKING_ISSUE": "冻结中的问题", + "FIELDS": { + "PRIORITY": "优先级", + "SEVERITY": "严重程度", + "TYPE": "类型" + }, + "CONFIRM_PROMOTE": { + "TITLE": "将此问题提为用户故事", + "MESSAGE": "你确定要用此问题创建一个新的用户故事?" + }, + "TABLE": { + "COLUMNS": { + "TYPE": "类型", + "SEVERITY": "严重程度", + "PRIORITY": "优先级", + "SUBJECT": "主旨", + "VOTES": "投票数", + "STATUS": "状态", + "CREATED": "已创建", + "ASSIGNED_TO": "指派给" + }, + "TITLE_ACTION_CHANGE_STATUS": "改变状态", + "TITLE_ACTION_ASSIGNED_TO": "指派给", + "BLOCKED": "已冻结", + "EMPTY": { + "TITLE": "没有问题回报:-)", + "SUBTITLE": "你有发现任何问题吗?" + } + } + }, + "ISSUE": { + "PAGE_TITLE": "{{issueSubject}} - 问题 {{issueRef}} - {{projectName}}", + "PAGE_DESCRIPTION": "状态:{{issueStatus }},类型:{{issueType}},优先级:{{issuePriority}},严重程度:{{issueSeverity}},描述:{{issueDescription}}" + }, + "KANBAN": { + "PAGE_TITLE": "看板 - {{projectName}}", + "PAGE_DESCRIPTION": "看板面板上有项目的用户故事 {{projectName}}:{{projectDescription}}", + "SECTION_NAME": "看板", + "TITLE_ACTION_FOLD": "隐藏栏位", + "TITLE_ACTION_UNFOLD": "未隐藏栏位", + "TITLE_ACTION_ADD_US": "新增用户故事", + "TITLE_ACTION_ADD_BULK": "成批增加", + "ACTION_SHOW_ARCHIVED": "显示归档资料", + "ACTION_HIDE_ARCHIVED": "隐藏归档", + "HIDDEN_USER_STORIES": "此状态下的用户故事预设为隐藏", + "PLACEHOLDER_CARD_TITLE": "这是您的用户故事", + "PLACEHOLDER_CARD_TEXT": "用户故事可有子任务以便分离需求" + }, + "SEARCH": { + "PAGE_TITLE": "搜索 - {{projectName}}", + "PAGE_DESCRIPTION": "项目搜索(用户故事, 问题, 任务或维基页等信息) {{projectName}}: {{projectDescription}}", + "FILTER_EPICS": "史诗", + "FILTER_USER_STORIES": "用户故事", + "FILTER_ISSUES": "问题", + "FILTER_TASKS": "任务", + "FILTER_WIKI": "维基页", + "PLACEHOLDER_SEARCH": "搜索", + "TITLE_ACTION_SEARCH": "搜索", + "EMPTY_TITLE": "依你搜索标准并未找到任何东西", + "EMPTY_DESCRIPTION": "请试试上方某一个分页或再搜索一次" + }, + "TEAM": { + "PAGE_TITLE": "团队- {{projectName}}", + "PAGE_DESCRIPTION": "团队面版可显示项目中所有成员{{projectName}}:{{projectDescription}}", + "SECTION_NAME": "团队", + "PLACEHOLDER_INPUT_SEARCH": "以全名搜索", + "COLUMN_MR_WOLF": "问题解决高手", + "EXPLANATION_COLUMN_MR_WOLF": "已关闭议题", + "COLUMN_IOCAINE": "新任务挑战者", + "EXPLANATION_COLUMN_IOCAINE": "毒物(新任务)剂量摄取", + "COLUMN_CERVANTES": "大文豪", + "EXPLANATION_COLUMN_CERVANTES": "已编辑的维基页", + "COLUMN_BUG_HUNTER": "Bug猎手", + "EXPLANATION_COLUMN_BUG_HUNTER": "问题回报", + "COLUMN_NIGHT_SHIFT": "夜猫子", + "EXPLANATION_COLUMN_NIGHT_SHIFT": "任务关闭", + "COLUMN_TOTAL_POWER": "总战斗力", + "EXPLANATION_COLUMN_TOTAL_POWER": "所有点数", + "SECTION_TITLE_TEAM": "团队 >", + "SECTION_FILTER_ALL": "所有", + "CONFIRM_LEAVE_PROJECT": "你确定要退出这个项目吗?", + "ACTION_LEAVE_PROJECT": "退出此项目" + }, + "USER_SETTINGS": { + "AVATAR_MAX_SIZE": "[最大尺寸:{{maxFileSize}}]", + "MENU": { + "SECTION_TITLE": "用户设置", + "USER_PROFILE": "用户设置", + "CHANGE_PASSWORD": "更新密码", + "EMAIL_NOTIFICATIONS": "电子邮件通知" + }, + "NOTIFICATIONS": { + "SECTION_NAME": "电子邮件通知", + "COLUMN_PROJECT": "项目", + "COLUMN_RECEIVE_ALL": "接收所有通知", + "COLUMN_ONLY_INVOLVED": "只接收相关通知", + "COLUMN_NO_NOTIFICATIONS": "不接收通知", + "OPTION_ALL": "所有", + "OPTION_INVOLVED": "相关", + "OPTION_NONE": "无" + } + }, + "USER_PROFILE": { + "ACTION_USE_GRAVATAR": "使用默认图片", + "ACTION_DELETE_ACCOUNT": "删除Taiga账户", + "CHANGE_EMAIL_SUCCESS": "检查你的收信箱
我们送出了一封信
里面有设定你新电子邮件的相关指示", + "CHANGE_PHOTO": "变更照片", + "FIELD": { + "USERNAME": "用户名称", + "EMAIL": "电子邮件", + "FULL_NAME": "全名", + "PLACEHOLDER_FULL_NAME": "你的全名", + "BIO": "简历(最多210字)", + "PLACEHOLDER_BIO": "请自我介绍", + "LANGUAGE": "语言", + "LANGUAGE_DEFAULT": "-- 使用默认语言 --", + "THEME": "主题", + "THEME_DEFAULT": "-- 使用默认主题--" + } + }, + "WIKI": { + "PAGE_TITLE": "{{wikiPageName}} - 维基 - {{projectName}}", + "PAGE_DESCRIPTION": "最近编辑{{lastModifiedDate}} (总共编辑了{{totalEditions}}次),内容:{{ wikiPageContent }}", + "DATETIME": "DD MMM YYYY HH:mm", + "REMOVE": "移除此维基页", + "DELETE_LIGHTBOX_TITLE": "删除维基页", + "DELETE_LINK_TITLE": "删除维基链接", + "NAVIGATION": { + "HOME": "主页", + "SECTION_NAME": "连结", + "ACTION_ADD_LINK": "新增连结", + "ALL_PAGES": "所有页面" + }, + "SUMMARY": { + "TIMES_EDITED": "次数
编辑", + "LAST_EDIT": "上次
编辑", + "LAST_MODIFICATION": "上回修改" + }, + "SECTION_PAGES_LIST": "所有页面", + "PAGES_LIST_COLUMNS": { + "TITLE": "标题", + "EDITIONS": "版本", + "CREATED": "已创建", + "MODIFIED": "已修改", + "CREATOR": "创建者", + "LAST_MODIFIER": "最新修改者" + } + }, + "HINTS": { + "SECTION_NAME": "提示", + "LINK": "如果想知道如何使用,可以到我们的支援页面了解详情。", + "LINK_TITLE": "造访我们的支援页面", + "HINT1_TITLE": "你知道可以导入与滙出项目吗?", + "HINT1_TEXT": "可以从 Taiga提取所有个人资料记录,移入其它地方。", + "HINT2_TITLE": "你知道可以创建个人化栏位吗", + "HINT2_TEXT": "作为一个灵活手段,团队现在可以创建自定义字段,这意味着需要为特殊的工作流指定有用的数据。", + "HINT3_TITLE": "根据特性来重新排序与你最为相关的项目。", + "HINT3_TEXT": "在顶端的直接访问条中,列出了十个项目。", + "HINT4_TITLE": "你忘记了你正在做什么了吗?", + "HINT4_TEXT": "别担心,在控制台可以找到你的公开任务、问题以及用户故事的工作次序。" + }, + "TIMELINE": { + "UPLOAD_ATTACHMENT": "{{username}} 上传新附件 {{obj_name}}", + "US_CREATED": "{{username}} 为项目 {{project_name}} 创建新的用户故事 {{obj_name}}", + "ISSUE_CREATED": "{{username}} 为项目 {{project_name}} 创建新问题 {{obj_name}}", + "TASK_CREATED": "{{username}} 为项目 {{project_name}} 创建新任务 {{obj_name}}", + "TASK_CREATED_WITH_US": "{{username}} 为项目 {{project_name}} 创建新任务 {{obj_name}},该任务隶属于用户故事 {{us_name}}", + "WIKI_CREATED": "{{username}} 为项目 {{project_name}} 创建新维基页 {{obj_name}}", + "MILESTONE_CREATED": "{{username}} 为项目 {{project_name}} 创建新冲刺任务 {{obj_name}}", + "EPIC_CREATED": "{{username}} 已经在{{project_name}}中创建了一个新史诗{{obj_name}}", + "EPIC_RELATED_USERSTORY_CREATED": "在{{project_name}}中{{username}}已经关联到史诗{{epic_name}}的用户故事{{related_us_name}}", + "NEW_PROJECT": "{{username}} 创建项目 {{project_name}}", + "MILESTONE_UPDATED": "{{username}} 已更新冲刺任务 {{obj_name}}", + "US_UPDATED": "{{username}} 已更新用户故事 {{obj_name}} 的 \"{{field_name}}\" 属性", + "US_UPDATED_WITH_NEW_VALUE": "{{username}} 更新了用户故事 {{obj_name}} 的 \"{{field_name}}\" 属性为 {{new_value}}", + "US_UPDATED_POINTS": "{{username}} 更新了用户故事 {{obj_name}} 的 \"{{field_name}}\" 点数为 {{new_value}}", + "ISSUE_UPDATED": "{{username}} 更新了问题 {{obj_name}} 的 \"{{field_name}}\" 属性", + "ISSUE_UPDATED_WITH_NEW_VALUE": "{{username}} 更新了问题 {{obj_name}} 的 \"{{field_name}}\" 属性为 {{new_value}}", + "TASK_UPDATED": "{{username}} 更新了任务 {{obj_name}} 的 \"{{field_name}}\" 属性为 {{new_value}}", + "TASK_UPDATED_WITH_NEW_VALUE": "{{username}} 更新了任务 {{obj_name}} 的 \"{{field_name}}\" 属性为 {{new_value}}", + "TASK_UPDATED_WITH_US": "{{username}} 更新了用户故事 {{us_name}} 的任务 {{obj_name}} 的 \"{{field_name}}\" 属性", + "TASK_UPDATED_WITH_US_NEW_VALUE": "{{username}} 已更新了用户故事 {{us_name}} 的任务 {{obj_name}} 的 \"{{field_name}}\" 属性为 {{new_value}}", + "WIKI_UPDATED": "{{username}} 更新了维基页 {{obj_name}}", + "EPIC_UPDATED": "{{username}}已经更新了史诗{{obj_name}}的\"{{field_name}}\"属性", + "EPIC_UPDATED_WITH_NEW_VALUE": "{{username}}已经更新了史诗{{obj_name}}的\"{{field_name}}\"属性为{{new_value}}", + "EPIC_UPDATED_WITH_NEW_COLOR": "{{username}}已经更新了史诗{{obj_name}}的\"{{field_name}}\"属性为", + "NEW_COMMENT_US": "{{username}} 评论了用户故事 {{obj_name}}", + "NEW_COMMENT_ISSUE": "{{username}} 评论了问题 {{obj_name}}", + "NEW_COMMENT_TASK": "{{username}} 评论了任务 {{obj_name}}", + "NEW_COMMENT_EPIC": "{{username}}在史诗{{obj_name}}做了评论", + "NEW_MEMBER": "{{project_name}} 有新成员", + "US_ADDED_MILESTONE": "{{username}} 为冲刺 {{sprint_name}} 添加用户故事 {{obj_name}}", + "US_MOVED": "{{username}} 已经移动了用户故事 {{obj_name}}", + "US_REMOVED_FROM_MILESTONE": "{{username}} 新增用户故事 {{obj_name}} 到待办任务", + "BLOCKED": "{{username}} 冻结了 {{obj_name}}", + "UNBLOCKED": "{{username}} 解除对 {{obj_name}} 的冻结", + "NEW_USER": "{{username}} 已加入 Taiga" + }, + "LEGAL": { + "TERMS_OF_SERVICE_AND_PRIVACY_POLICY_AD": "当创建一个新账户时,说明你已经同意我们的
服务条款隐私策略." + }, + "EXTERNAL_APP": { + "PAGE_TITLE": "一个外部应用需要验证", + "PAGE_DESCRIPTION": "一个外部应用需要验证", + "AUTHORIZATION_REQUEST": "向你的Taiga账户验证{{application}}?", + "LOGIN_WITH_ANOTHER_USER": "以其他用户登录", + "AUTHORIZE_APP": "授权应用", + "CANCEL": "取消" + }, + "JOYRIDE": { + "NAV": { + "NEXT": "下一个", + "BACK": "后退", + "SKIP": "跳过", + "DONE": "完成" + }, + "DASHBOARD": { + "STEP1": { + "TITLE": "你的项目", + "TEXT": "欢迎!你将找到你所涉及的项目。" + }, + "STEP2": { + "TITLE": "进行中", + "TEXT": "在这里你将发现一些你正在处理的用户故事,任务,问题。" + }, + "STEP3": { + "TITLE": "观看中", + "TEXT1": "在这里你将会找到那些你希望了解的你的项目成员。", + "TEXT2": "你已经开始使用Taiga ;)" + }, + "STEP4": { + "TITLE": "现在开始!", + "TEXT1": "你可以以创建你的第一个Taiga项目开始。", + "TEXT2": "祝你好运!" + } + }, + "BACKLOG": { + "STEP1": { + "TITLE": "项目简介", + "TEXT1": "在这里你将看到你的项目状态。", + "TEXT2": "通过管理员,你可以改变项目的各种设置。" + }, + "STEP2": { + "TITLE": "产品待办事项", + "TEXT": "待办事项是产品的需求(用户故事)列表这里也就是你做冲刺计划的地方。" + }, + "STEP3": { + "TITLE": "冲刺任务", + "TEXT": "冲刺是一段时间(一般为两周),在这期间你需要完成指定工作并交付。" + }, + "STEP4": { + "TITLE": "用户故事", + "TEXT": "这些是更高层次的需求。你可以将它们添加到待办事项中,然后将其拖拽到冲刺,它们应该在冲刺中进行交付。" + } + }, + "KANBAN": { + "STEP1": { + "TITLE": "自定义你的工作流", + "TEXT": "通过管理员,根据你的需要设置这些列来映射你的工作流" + }, + "STEP2": { + "TITLE": "用户故事和任务", + "TEXT": "用户故事是更高层次的需求。你可以将其拖拽到不同列中" + }, + "STEP3": { + "TITLE": "添加你的用户故事", + "TEXT1": "你可能希望添加一个用户故事(添加用户故事图标)或者一组用户故事(批量图标)", + "TEXT2": "祝你好运!" + } + } + }, + "DISCOVER": { + "PAGE_TITLE": "探索更多项目", + "PAGE_DESCRIPTION": "Taiga中的公共项目的可搜索的目录。探索积压,时间线,问题,以及团队。检索出最喜欢的或者最活跃的项目。通过看板或者敏捷开发进行过滤。", + "DISCOVER_TITLE": "探索项目", + "DISCOVER_SUBTITLE": "{projects, plural, one{一个要发现的公开项目} other{# 个要发现的公开项目}}", + "MOST_ACTIVE": "最活跃的", + "MOST_ACTIVE_EMPTY": "还没有活动的项目", + "MOST_LIKED": "最受欢迎的", + "MOST_LIKED_EMPTY": "还没有喜欢的项目", + "VIEW_MORE": "查看更多", + "FEATURED": "特色项目", + "EMPTY": "没有满足当前搜索条件的项目。
再试一次!", + "FILTERS": { + "ALL": "所有", + "KANBAN": "看板", + "SCRUM": "冲刺", + "PEOPLE": "查找队友", + "WEEK": "上周", + "MONTH": "上月", + "YEAR": "去年", + "ALL_TIME": "长期", + "CLEAR": "清除过滤" + }, + "SEARCH": { + "PAGE_TITLE": "搜索 - 发现项目 - Taiga", + "PAGE_DESCRIPTION": "Taiga中的公共项目的可搜索的目录。探索积压,时间线,问题,以及团队。检索出最喜欢的或者最活跃的项目。通过看板或者敏捷开发进行过滤。", + "INPUT_PLACEHOLDER": "输入内容...", + "ACTION_TITLE": "搜索", + "RESULTS": "搜索结果" + } + } +} \ No newline at end of file diff --git a/app/locales/taiga/locale-zh-hant.json b/app/locales/taiga/locale-zh-hant.json index 7312dc86..d0b217af 100644 --- a/app/locales/taiga/locale-zh-hant.json +++ b/app/locales/taiga/locale-zh-hant.json @@ -4,7 +4,6 @@ "NO": "No", "OR": "or", "LOADING": "載入中...", - "LOADING_PROJECT": "載入專案中...", "DATE": "DD MMM YYYY", "DATETIME": "DD MMM YYYY HH:mm", "SAVE": "儲存", @@ -27,12 +26,9 @@ "BLOCKED_NOTE": "為何遭到封鎖?", "BLOCKED_REASON": "請解釋此原因", "CREATED_BY": "由 {{fullDisplayName}}創建", - "FROM": "from", - "TO": "to", "CLOSE": "關閉", "GO_HOME": "帶我回到首頁", "PLUGINS": "外掛", - "BETA": "我們在測試中", "ONE_ITEM_LINE": "一行一物 ", "NEW_BULK": "新批次插入", "RELATED_TASKS": "相關任務 ", @@ -41,7 +37,7 @@ "LOGOUT": "登出", "EXTERNAL_USER": "外部使用者", "GENERIC_ERROR": "我們的系統指出{{error}}.", - "IOCAINE_TEXT": "感到任務的不堪負荷?確認其它人在編輯任務時知道此狀況,可以點選Iocaine。它可能會成為免疫的致命狀況,只要長期小量消耗,但如果你只是偶而挑戰它可有助表現。", + "IOCAINE_TEXT": "This member is feeling a bit overwhelmed by this task. Will become immune to the iocaine poison over time with your help. For now, may need a hug.", "CLIENT_REQUIREMENT": "Client requirement is new requirement that was not previously expected and it is required to be part of the project", "TEAM_REQUIREMENT": "Team requirement is a requirement that must exist in the project but should have no cost for the client", "OWNER": "Project Owner", @@ -148,7 +144,6 @@ "PRIORITY": "優先性", "ASSIGNED_TO": "指派給 ", "POINTS": "點數", - "BLOCKED_NOTE": "已封鎖之筆記", "IS_BLOCKED": "封鎖", "REF": "Ref", "VOTES": "投票數", @@ -187,10 +182,6 @@ "COUNTER_TITLE": "{total, plural, one{一個觀注者} other{# 觀注者}}" }, "VOTE_BUTTON": { - "UPVOTE": "Upvote", - "UPVOTED": "Upvoted", - "DOWNVOTE": "Downvote", - "VOTERS": "投票者", "BUTTON_TITLE": "Upvote/Downvote this item", "COUNTER_TITLE": "{total, plural, one{one vote} other{# votes}}" }, @@ -202,10 +193,9 @@ "CONFIRM_DELETE": "記住在此客制欄位裏的數值資料都將遭刪除\n你確定要繼續嗎?" }, "FILTERS": { - "TITLE": "過濾器", "INPUT_PLACEHOLDER": "主旨或參考", "TITLE_ACTION_FILTER_BUTTON": "搜尋", - "INPUT_SEARCH_PLACEHOLDER": "主旨或參考", + "TITLE": "過濾器", "TITLE_ACTION_SEARCH": "搜尋", "ACTION_SAVE_CUSTOM_FILTER": "儲存為客製過濾器 ", "PLACEHOLDER_FILTER_NAME": "寫入過濾器名稱後按下enter ", @@ -220,41 +210,10 @@ "CREATED_BY": "由創建", "CUSTOM_FILTERS": "客製過濾器 ", "EPIC": "Epic" - }, - "CONFIRM_DELETE": { - "TITLE": "刪除客製過濾器 ", - "MESSAGE": "預設過濾器 '{{customFilterName}}'" } }, "WYSIWYG": { - "H1_BUTTON": "第一層標頭 ", - "H1_SAMPLE_TEXT": "你的頭銜 ", - "H2_BUTTON": "第二層標頭 ", - "H2_SAMPLE_TEXT": "你的頭銜 ", - "H3_BUTTON": "第三標頭", - "H3_SAMPLE_TEXT": "你的頭銜", - "BOLD_BUTTON": "粗體字", - "BOLD_BUTTON_SAMPLE_TEXT": "你的文字在此", - "ITALIC_BUTTON": "斜體字", - "ITALIC_SAMPLE_TEXT": "你的文字在此", - "STRIKE_BUTTON": "刪除線", - "STRIKE_SAMPLE_TEXT": "你的文字在此", - "BULLETED_LIST_BUTTON": "次序列表", - "BULLETED_LIST_SAMPLE_TEXT": "你的文字在此", - "NUMERIC_LIST_BUTTON": "列號清單", - "NUMERIC_LIST_SAMPLE_TEXT": "你的文字在此 ", - "PICTURE_BUTTON": "圖片", - "PICTURE_SAMPLE_TEXT": "對照圖片的說明文", - "LINK_BUTTON": "連結", - "LINK_SAMPLE_TEXT": "文字連結在此", - "QUOTE_BLOCK_BUTTON": "引言區塊", - "QUOTE_BLOCK_SAMPLE_TEXT": "你的文字在此", - "CODE_BLOCK_BUTTON": "原始碼區塊", - "CODE_BLOCK_SAMPLE_TEXT": "你的文字在此", - "PREVIEW_BUTTON": "預視 ", - "EDIT_BUTTON": "編輯", - "ATTACH_FILE_HELP": "Attach files by dragging & dropping on the textarea above.", - "ATTACH_FILE_HELP_SAVE_FIRST": "Save first before if you want to attach files by dragging & dropping on the textarea above.", + "OUTDATED": "Another person has made changes while you were editing. Check the new version on the activiy tab before you save your changes.", "MARKDOWN_HELP": "Markdown 語法協助" }, "PERMISIONS_CATEGORIES": { @@ -307,10 +266,6 @@ "ADD_WIKI_LINKS": "新增維基連結", "DELETE_WIKI_LINKS": "刪除維基連結" } - }, - "META": { - "PAGE_TITLE": "Taiga", - "PAGE_DESCRIPTION": "Taiga是一個給新創團隊與敏捷開發者設計師使用的專案管理平台。Taiga是一個簡易輕鬆美觀的工具,讓工作變成樂趣。" } }, "LOGIN": { @@ -366,7 +321,6 @@ }, "CHANGE_PASSWORD": { "PAGE_TITLE": "變更密碼 - Taiga", - "PAGE_DESCRIPTION": "設定Taiga 帳戶密碼! 你也許該吃點鐵質豐富的食物,它對你的大腦有益處:p", "SECTION_NAME": "改變密碼 ", "FIELD_CURRENT_PASSWORD": "現用密碼 ", "PLACEHOLDER_CURRENT_PASSWORD": "你目前的密碼(如果你未有密碼,此處請空白)", @@ -391,8 +345,7 @@ }, "INVITATION_LOGIN_FORM": { "NOT_FOUND": "我們找不到你的邀請碼", - "SUCCESS": "你成功地加入此專案,歡迎來到 {{project_name}}", - "ERROR": "按我們的記錄,你尚未註冊或是未輸入有效的密碼 " + "SUCCESS": "你成功地加入此專案,歡迎來到 {{project_name}}" }, "HOME": { "PAGE_TITLE": "首頁 - Taiga", @@ -463,10 +416,7 @@ "TITLE_LIGHTBOX_DELETE_ATTACHMENT": "刪除附件....", "MSG_LIGHTBOX_DELETE_ATTACHMENT": "附件 '{{fileName}}'", "ERROR_DELETE_ATTACHMENT": "無法刪除: {{errorMessage}}", - "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) 超過系統容量上限, 請重傳小一點的檔案 ({{maxFileSize}})", - "FIELDS": { - "IS_DEPRECATED": "被棄用" - } + "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) 超過系統容量上限, 請重傳小一點的檔案 ({{maxFileSize}})" }, "PAGINATION": { "PREVIOUS": "Prev", @@ -502,13 +452,10 @@ "ASYNC_MESSAGE": "準備好後,我們會送給 你一封電子郵件", "SYNC_MESSAGE": "如果未能自動下載,請點選此處 . ", "ERROR": "我們的系統無法製作你的滙出資料,請再試一次 ", - "ERROR_BUSY": "抱歉系統繁忙中,請稍後再試試 ", - "ERROR_MESSAGE": "我們的系統在生成你的傾倒時遇到一些問題: {{message}}" + "ERROR_BUSY": "抱歉系統繁忙中,請稍後再試試 " }, "MODULES": { "TITLE": "模組", - "ENABLE": "啟用", - "DISABLE": "停用", "EPICS": "Epics", "EPICS_DESCRIPTION": "Visualize and manage the most strategic part of your project", "BACKLOG": "待辦任務優先表", @@ -537,17 +484,16 @@ "PAGE_TITLE": "{{sectionName}} - 專案檔案 - {{projectName}}", "PROJECT_DETAILS": "專案細節", "PROJECT_NAME": "專案名稱", - "PROJECT_SLUG": "專案代稱", "TAGS": "標籤", "DESCRIPTION": "描述", "RECRUITING": "這個專案是否在徵人", "RECRUITING_MESSAGE": "你在找誰?", "RECRUITING_PLACEHOLDER": "定義你要找的資訊", + "FEEDBACK": "Receive feedback from Taiga users?", "PUBLIC_PROJECT": "公開專案", "PRIVATE_PROJECT": "不公開專案", "PRIVATE_OR_PUBLIC": "公開專案和私密專案有何差異?", "DELETE": "刪除此專案", - "LOGO_HELP": "此圖片將被裁成80x80px.
", "CHANGE_LOGO": "更改圖標", "ACTION_USE_DEFAULT_LOGO": "使用設預圖片", "MAX_PRIVATE_PROJECTS": "You've reached the maximum number of private projects allowed by your current plan", @@ -595,6 +541,7 @@ "ISSUE_DESCRIPTION": "問題客製化欄位", "ISSUE_ADD": "在問題中加入客制欄位", "FIELD_TYPE_TEXT": "單行文字", + "FIELD_TYPE_RICHTEXT": "Rich text", "FIELD_TYPE_MULTI": "多行", "FIELD_TYPE_DATE": "日期", "FIELD_TYPE_URL": "Url" @@ -623,7 +570,7 @@ "ACTION_ADD": "新增急迫性" }, "PROJECT_VALUES_STATUS": { - "TITLE": "狀態", + "TITLE": "Statuses", "SUBTITLE": "指明你的使用者故事狀態,任務以及經歷問題 ", "EPIC_TITLE": "Epic Statuses", "US_TITLE": "User Story Statuses", @@ -676,8 +623,8 @@ "INFO_VERIFYING_IP": "GitHub要求不指派因此最佳確認方式為IP位置來源。如果此處空白,表示IP未有效確核。" }, "GITHUB": { - "SECTION_NAME": "Githun", - "PAGE_TITLE": "Gitlab - {{projectName}}" + "SECTION_NAME": "GitHub", + "PAGE_TITLE": "GitHub - {{projectName}}" }, "GOGS": { "SECTION_NAME": "Gogs", @@ -686,7 +633,6 @@ "WEBHOOKS": { "PAGE_TITLE": "Webhooks- {{projectName}}", "SECTION_NAME": "網頁觸發 ", - "SUBTITLE": "網頁觸發通知關於Taiga事件的外部服務,例如評論,使用者故事等。 ", "ADD_NEW": "新增一個網頁觸發 ", "TYPE_NAME": "鍵入服務名稱 ", "TYPE_PAYLOAD_URL": "鍵入服務有效載荷網址", @@ -732,7 +678,6 @@ "DELETE_MEMBER": "刪除成員", "RESEND": "重新送出", "SUCCESS_SEND_INVITATION": "我們已再次發出邀請信給'{{email}}'. ", - "ERROR_SEND_INVITATION": "我們未送出邀請 ", "SUCCESS_DELETE": "已刪除 {{message}}.", "ERROR_DELETE": "我們無法刪除 {{message}}.", "DEFAULT_DELETE_MESSAGE": "邀請 {{email}}" @@ -761,16 +706,11 @@ "PLACEHOLDER_WRITE_NAME": "為此新狀態命名" }, "MENU": { - "TITLE": "管理者", "PROJECT": "專案", "ATTRIBUTES": "屬性", "MEMBERS": "成員", "PERMISSIONS": "權限", - "INTEGRATIONS": "整合", - "PLUGINS": "外掛" - }, - "SUBMENU_PROJECT_ATTRIBUTES": { - "TITLE": "屬性" + "INTEGRATIONS": "整合" }, "SUBMENU_PROJECT_VALUES": { "STATUS": "狀態", @@ -781,17 +721,11 @@ "CUSTOM_FIELDS": "客製化欄位", "TAGS": "標籤" }, - "SUBMENU_PROJECT_PROFILE": { - "TITLE": "專案檔案" - }, "SUBMENU_ROLES": { "TITLE": "角色", "ACTION_NEW_ROLE": "+ 新角色", "TITLE_ACTION_NEW_ROLE": "新增角色" }, - "SUBMENU_THIDPARTIES": { - "TITLE": "服務 " - }, "PROJECT_TRANSFER": { "DO_YOU_ACCEPT_PROJECT_OWNERNSHIP": "Would you like to become the new project owner?", "PRIVATE": "Private", @@ -806,15 +740,13 @@ "PRIVATE": "Please remember that you can own up to {{maxProjects}} private projects. You currently own {{currentProjects}} private projects", "PUBLIC": "Please remember that you can own up to {{maxProjects}} public projects. You currently own {{currentProjects}} public projects" }, - "CANT_BE_OWNED": "At the moment you cannot become an owner of a project of this type. If you would like to become the owner of this project, please contact the administrator so they change your account settings to enable project ownership.", - "CHANGE_MY_PLAN": "Change my plan" + "CANT_BE_OWNED": "At the moment you cannot become an owner of a project of this type. If you would like to become the owner of this project, please contact the administrator so they change your account settings to enable project ownership." } }, "USER": { "PROFILE": { "PAGE_TITLE": "{{userFullName}} (@{{userUsername}})", "EDIT": "編輯個人資料", - "FOLLOW": "追踪", "CLOSED_US": "閞閉使用者故事", "PROJECTS": "專案", "PROJECTS_EMPTY": "{{username}} 尚無專案", @@ -822,7 +754,6 @@ "CONTACTS_EMPTY": "{{username}} 尚無聯絡人", "CURRENT_USER_CONTACTS_EMPTY": "您尚無任何聯絡人", "CURRENT_USER_CONTACTS_EMPTY_EXPLAIN": "你在Taiga一同工作的伙伴將自動成為你的聯絡人", - "REPORT": "回報濫用", "TABS": { "ACTIVITY_TAB": "時間表", "ACTIVITY_TAB_TITLE": "顯示該用戶的所有活動", @@ -848,13 +779,13 @@ "FILTER_TYPE_ALL": "所有", "FILTER_TYPE_ALL_TITLE": "顯示全部", "FILTER_TYPE_PROJECTS": "專案", - "FILTER_TYPE_PROJECT_TITLES": "只顯示專案", + "FILTER_TYPE_PROJECTS_TITLE": "只顯示專案", "FILTER_TYPE_EPICS": "Epics", - "FILTER_TYPE_EPIC_TITLES": "Show only epics", + "FILTER_TYPE_EPICS_TITLE": "Show only epics", "FILTER_TYPE_USER_STORIES": "故事", - "FILTER_TYPE_USER_STORIES_TITLES": "只顯視使用者故事", + "FILTER_TYPE_USER_STORIES_TITLE": "只顯視使用者故事", "FILTER_TYPE_TASKS": "任務 ", - "FILTER_TYPE_TASK_TITLES": "只顯示任務 ", + "FILTER_TYPE_TASKS_TITLE": "只顯示任務 ", "FILTER_TYPE_ISSUES": "問題 ", "FILTER_TYPE_ISSUES_TITLE": "只顯示問題 ", "EMPTY_TITLE": "似乎沒有東西可顯示" @@ -862,8 +793,6 @@ }, "PROJECT": { "PAGE_TITLE": "{{projectName}}", - "WELCOME": "歡迎", - "SECTION_PROJECTS": "專案", "HELP": "記錄你的專案在上方常用欄位
前十個專案將會顯示在上方導覽處。", "PRIVATE": "不公開專案", "LOOKING_FOR_PEOPLE": "這個專案正在徵人", @@ -875,12 +804,6 @@ "THIS_PROJECT_IS_BLOCKED": "This project is temporarily blocked", "TO_UNBLOCK_CONTACT_THE_ADMIN_STAFF": "In order to unblock your projects, contact the administrator." }, - "STATS": { - "PROJECT": "專案
點數", - "DEFINED": "已定義
點數", - "ASSIGNED": "已指派
點數", - "CLOSED": "已關閉
點數" - }, "SECTION": { "SEARCH": "搜尋", "TIMELINE": "時間表", @@ -893,15 +816,9 @@ "ADMIN": "管理者" }, "NAVIGATION": { - "SECTION_TITLE": "你的專案", - "PLACEHOLDER_SEARCH": "搜尋", "ACTION_CREATE_PROJECT": "創建專案", - "ACTION_IMPORT_PROJECT": "滙入專案", "MANAGE_PROJECTS": "管理專案", "TITLE_CREATE_PROJECT": "創建專案", - "TITLE_IMPORT_PROJECT": "滙入專案", - "TITLE_PRVIOUS_PROJECT": "顯示過去專案", - "TITLE_NEXT_PROJECT": "顯示下一個任務", "HELP_TITLE": "Taiga支援頁", "HELP": "幫助", "HOMEPAGE": "首頁", @@ -909,10 +826,6 @@ "FEEDBACK": "回饋 ", "NOTIFICATIONS_TITLE": "編輯個人通知設定", "NOTIFICATIONS": "通知", - "ORGANIZATIONS_TITLE": "編輯您的組織資料", - "ORGANIZATIONS": "編輯組織資料", - "SETTINGS_TITLE": "編輯個人設定", - "SETTINGS": "設定", "VIEW_PROFILE_TITLE": "檢視個人資料", "VIEW_PROFILE": "檢視個人資料", "EDIT_PROFILE_TITLE": "編輯你的個人資料", @@ -921,14 +834,68 @@ "CHANGE_PASSWORD": "更換密碼 ", "DASHBOARD_TITLE": "控制台", "DISCOVER_TITLE": "發現流行專案", - "NEW_ITEM": "新 ", - "DISCOVER": "發現", - "ACTION_REORDER": "拖移 & 丟到來記錄" + "DISCOVER": "發現" + }, + "LIKE_BUTTON": { + "LIKE": "喜歡", + "LIKED": "喜歡", + "UNLIKE": "不喜歡", + "BUTTON_TITLE": "是否喜歡該專案", + "COUNTER_TITLE": "{total, plural, one{一個粉絲} other{# 粉絲}}" + }, + "WATCH_BUTTON": { + "BUTTON_TITLE": "觀注本專案並設置通知選項", + "WATCH": "觀注", + "WATCHING": "觀看中", + "COUNTER_TITLE": "{total, plural, one{一個觀注者} other{# 觀注者}}", + "OPTIONS": { + "NOTIFY_ALL": "接收所有通知", + "NOTIFY_ALL_TITLE": "接到該專案的所有通知", + "NOTIFY_INVOLVED": "只有相關", + "NOTIFY_INVOLVED_TITLE": "只接收與你相關的通知訊息", + "UNWATCH": "不觀注", + "UNWATCH_TITLE": "不再觀注此專案" + } + }, + "CONTACT_BUTTON": { + "CONTACT_TITLE": "Contact the project team", + "CONTACT_BUTTON": "Contact the project" + }, + "CREATE": { + "TITLE": "創建專案", + "CHOOSE_TEMPLATE": "Which template fits your project better?", + "TEMPLATE_SCRUM": "Scrum", + "TEMPLATE_SCRUM_DESC": "Prioritize and solve your tasks in short time cycles.", + "TEMPLATE_SCRUM_LONGDESC": "Scrum is an iterative and incremental agile software development methodology for managing product development.\nThe product backlog is what will ultimately be delivered, ordered into the sequence in which it should be delivered. Product Backlogs are broken into manageable, executable chunks named sprints. Every certain amount of time the team initiates a new sprint and commits to deliver a certain number of user stories from the backlog, in accordance with their skills, abilities and resources. The project advances as the backlog becomes depleted.", + "TEMPLATE_KANBAN": "Kanban(看板)", + "TEMPLATE_KANBAN_DESC": "Keep a constant workflow on independent tasks", + "TEMPLATE_KANBAN_LONGDESC": "The Kanban methodology is used to divide project development (any sort of project) into stages.\nA kanban card is like an index card or post-it note that details every task (or user story) in a project that needs to be completed. The Kanban board is used to move each card from one state of completion to the next and in so doing, helps track progress.", + "DUPLICATE": "Duplicate project", + "DUPLICATE_DESC": "Start clean and keep your configuration", + "IMPORT": "滙入專案", + "IMPORT_DESC": "Import your project from multiple platforms into Taiga", + "INVITE": "Invite to the project", + "SOLO_PROJECT": "You'll be alone in this project", + "INVITE_LATER": "(You'll be able to invite more members later)", + "BACK": "後台", + "MAX_PRIVATE_PROJECTS": "Unfortunately, You've reached the maximum number of private projects.\nIf you would like to increase the current limit please contact the administrator.", + "MAX_PUBLIC_PROJECTS": "Unfortunately, You've reached the maximum number of public projects.\nIf you would like to increase the current limit please contact the administrator.", + "PUBLIC_PROJECT": "Public Project", + "PRIVATE_PROJECT": "Private Project" + }, + "COMMON": { + "DETAILS": "New project details", + "PROJECT_TITLE": "Project Name", + "PROJECT_DESCRIPTION": "Project Description" + }, + "DUPLICATE": { + "TITLE": "Duplicate Project", + "DESCRIPTION": "Start clean and keep your configuration", + "SELECT_PLACEHOLDER": "Choose an existing project to duplicate" }, "IMPORT": { - "TITLE": "滙入專案中", - "UPLOADING_FILE": "上傳傾倒檔案", - "DESCRIPTION": "這個過桯要花點時間,請保持视窗開啟", + "TITLE": "Import Project", + "DESCRIPTION": "Import your project from multiple platforms into Taiga", "ASYNC_IN_PROGRESS_TITLE": "我們的工程師對你的專案很重要哦", "ASYNC_IN_PROGRESS_MESSAGE": "這個過程要花上一點時間
當弄好時我們會發給你一封郵件", "UPLOAD_IN_PROGRESS_MESSAGE": "已上傳 {{totalSize}}中的{{uploadedSize}} ", @@ -937,8 +904,29 @@ "ERROR_MESSAGE": "我們的系統無法滙入你的資料", "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) 超過系統容量上限, 請重傳小一點的檔案 ({{maxFileSize}})", "SYNC_SUCCESS": "你的專案已成功滙入", + "IMPORT": "Import", + "WHO_IS": "Their tasks will be assigned to ...", + "WRITE_EMAIL": "Or if you want, write the email that this user uses in Taiga", + "SEARCH_CONTACT": "Or if you want, search in your contacts", + "WRITE_EMAIL_LABEL": "Write the email that this user uses in Taiga", + "ACCEEDE": "Acceede", + "PROJECT_MEMBERS": "Project Members", + "PROCESS_DESCRIPTION": "Tell us who from Taiga you want to assign the tasks of {{platform}}", + "MATCH": "Is {{user_external}} the same person as {{user_internal}}?", + "CHOOSE": "Select user", + "LINKS": "Links with {{platform}}", + "LINKS_DESCRIPTION": "Do you want to keep the link of each item with the original {{platform}} card?", + "WARNING_MAIL_USER": "Note that if the user does not have a Taiga account we will not be able to assign the tasks to him.", + "ASSIGN": "指派", + "PROJECT_SELECTOR": { + "NO_RESULTS": "It looks like nothing was found with your search criteria", + "ACTION_SEARCH": "搜尋", + "ACTION_BACK": "後台" + }, "PROJECT_RESTRICTIONS": { - "PROJECT_MEMBERS_DESC": "The project you are trying to import has {{members}} members, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per project. If you would like to increase that limit please contact the administrator.", + "PROJECT_MEMBERS_DESC_PRIVATE": "The project you are trying to import has {{members}} members including you, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per private project. If you would like to increase that limit please contact the administrator.", + "PROJECT_MEMBERS_DESC_PUBLIC": "The project you are trying to import has {{members}} members including you, unfortunately, your current plan allows for a maximum of {{max_memberships}} members per public project. If you would like to increase that limit please contact the administrator.", + "ACCOUNT_ALLOW_MEMBERS": "Your account only allows {{members}} members", "PRIVATE_PROJECTS_SPACE": { "TITLE": "Unfortunately, your current plan does not allow for additional private projects", "DESC": "The project you are trying to import is private. Unfortunately, your current plan does not allow for additional private projects." @@ -961,39 +949,67 @@ "TITLE": "Unfortunately your current plan doesn't allow additional public projects or an increase of more than {{max_memberships}} members per public project", "DESC": "The project that you are trying to import is public and has more than {{members}} members." } - } - }, - "LIKE_BUTTON": { - "LIKE": "喜歡", - "LIKED": "喜歡", - "UNLIKE": "不喜歡", - "BUTTON_TITLE": "是否喜歡該專案", - "COUNTER_TITLE": "{total, plural, one{一個粉絲} other{# 粉絲}}" - }, - "WATCH_BUTTON": { - "BUTTON_TITLE": "觀注本專案並設置通知選項", - "WATCH": "觀注", - "WATCHING": "觀看中", - "COUNTER_TITLE": "{total, plural, one{一個觀注者} other{# 觀注者}}", - "OPTIONS": { - "NOTIFY_ALL": "接收所有通知", - "NOTIFY_ALL_TITLE": "接到該專案的所有通知", - "NOTIFY_INVOLVED": "只有相關", - "NOTIFY_INVOLVED_TITLE": "只接收與你相關的通知訊息", - "UNWATCH": "不觀注", - "UNWATCH_TITLE": "不再觀注此專案" + }, + "IN_PROGRESS": { + "TITLE": "滙入專案中", + "DESCRIPTION": "這個過桯要花點時間,請保持视窗開啟" + }, + "WARNING": { + "TITLE": "Some taks will be unassigned", + "DESCRIPTION": "There are still unidentified people. The cards assigned to these people will remain unassigned. Check all the contacts to not lose that information.", + "CHECK": "Check contacts" + }, + "TAIGA": { + "SELECTOR": "Import your Taiga project" + }, + "TRELLO": { + "SELECTOR": "Import your Trello boards into Taiga", + "CHOOSE_PROJECT": "Choose board that you want to import", + "NO_PROJECTS": "It seems you have no boards in Trello" + }, + "GITHUB": { + "SELECTOR": "Import your GitHub project issues", + "CHOOSE_PROJECT": "Find the project you want to import", + "NO_PROJECTS": "It seems you have no porjects in GitHub", + "HOW_DO_YOU_WANT_TO_IMPORT": "How do you want to import your issues into Taiga?", + "KANBAN_PROJECT": "As user stories in a kanban project", + "KANBAN_PROJECT_DESCRIPTION": "After that you can enable scrum with backlog.", + "SCRUM_PROJECT": "As user stories in a scrum project", + "SCRUM_PROJECT_DESCRIPTION": "After that you can enable kanban mode.", + "ISSUES_PROJECT": "As issues", + "ISSUES_PROJECT_DESCRIPTION": "You will not be able to use your issues in kanban or scrum mode. You will be able to enable kanban or scrum for new user stories" + }, + "ASANA": { + "SELECTOR": "Import your Asana project and choose how to manage it", + "CHOOSE_PROJECT": "Choose project that you want to import", + "NO_PROJECTS": "It seems you have no porjects in Asana", + "KANBAN_PROJECT": "Kanban(看板)", + "SCRUM_PROJECT": "Scrum", + "CREATE_AS_SCRUM_DESCRIPTION": "The tasks and sub-tasks of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_KANBAN_DESCRIPTION": "The tasks and sub-tasks of your project will be created as Taiga user stories and tasks." + }, + "JIRA": { + "SELECTOR": "Import your Jira project and choose how to manage it", + "CHOOSE_PROJECT": "Choose project or board that you want to import", + "NO_PROJECTS": "It seems you have no porjects or boards in Jira", + "URL": "Your Jira URL", + "KANBAN_PROJECT": "Kanban(看板)", + "SCRUM_PROJECT": "Scrum", + "ISSUES_PROJECT": "問題 ", + "CREATE_AS_SCRUM_DESCRIPTION": "The issues and sub-issues of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_KANBAN_DESCRIPTION": "The issues and sub-issues of your project will be created as Taiga user stories and tasks.", + "CREATE_AS_ISSUES_DESCRIPTION": "What do you want to do with sub-issues from the Jira project? (Taiga doesn't allow sub-issues)", + "CREATE_NEW_ISSUES": "Convert sub-issues to new Taiga issues", + "NOT_CREATE_NEW_ISSUES": "Do not import sub-issues" } } }, "LIGHTBOX": { "DELETE_ACCOUNT": { - "SECTION_NAME": "刪除Taiga帳戶", "CONFIRM": "你確定要刪除Taiga帳戶嗎?", - "NEWSLETTER_LABEL_TEXT": "不願再收到電子月報", "CANCEL": "Back to settings", "ACCEPT": "Delete account", - "BLOCK_PROJECT": "Note that all the projects you own projects will be blocked after you delete your account. If you do want a project blocked, transfer ownership to another member of each project prior to deleting your account.", - "SUBTITLE": "Sorry to see you go. We'll be here if you should ever consider us again! :(" + "BLOCK_PROJECT": "Note that all the projects you own projects will be blocked after you delete your account. If you do want a project blocked, transfer ownership to another member of each project prior to deleting your account." }, "DELETE_PROJECT": { "TITLE": "刪除專案", @@ -1007,6 +1023,12 @@ }, "ADD_MEMBER": { "TITLE": "新成員", + "PLACEHOLDER": "Filter users or write an email to invite", + "ADD_EMAIL": "Add email", + "REMOVE": "Remove", + "INVITE": "Invite", + "CHOOSE_ROLE": "Choose a role", + "PLACEHOLDER_INVITATION_TEXT": "(非必要) 加上一段私人文字在邀請信,告訴你的新成員一些好事 ;-)", "HELP_TEXT": "如果用戶已註冊Taiga帳戶,他們會自動被加入。否則他們會收到一封加入的邀請信" }, "CREATE_ISSUE": { @@ -1068,6 +1090,12 @@ "TITLE": "Who do you want to be the new project owner?", "ADD_COMMENT": "Add comment", "BUTTON": "Ask this project member to become the new project owner" + }, + "CONTACT_PROJECT": { + "TITLE": "Send an email to", + "WARNING": "The email will be received by the project admins", + "PLACEHOLDER": "Write your message", + "SEND": "Send" } }, "EPIC": { @@ -1101,15 +1129,9 @@ "ADD_BULK": "批次加入新使用者故事", "PROMOTED": "此使用者故事已提昇成問題:", "TITLE_LINK_GO_TO_ISSUE": "到問題 ", - "EXTERNAL_REFERENCE": "此使用者故事創造者是", - "GO_TO_EXTERNAL_REFERENCE": "回到一開始", - "BLOCKED": "這個使用者故事已被封鎖", "TITLE_DELETE_ACTION": "刪除使用者故事", "LIGHTBOX_TITLE_BLOKING_US": "封鎖中的使用者故事", - "TASK_COMPLETED": "{{totalClosedTasks}}/{{totalTasks}} 任務完成", - "ASSIGN": "指派使用者故事", "NOT_ESTIMATED": "無預估", - "TOTAL_US_POINTS": "全部使用者故事點數", "TRIBE": { "PUBLISH": "Publish as Gig in Taiga Tribe", "PUBLISH_INFO": "More info", @@ -1119,23 +1141,19 @@ "CLOSE": "Close", "SYNCHRONIZE_LINK": "synchronize with Taiga Tribe", "PUBLISH_MORE_INFO_TITLE": "Do you need somebody for this task?", - "PUBLISH_MORE_INFO_TEXT": "

If you need help with a particular piece of work you can easily create gigs on Taiga Tribe and receive help from all over the world. You will be able to control and manage the gig enjoying a great community eager to contribute.

TaigaTribe was born as a Taiga sibling. Both platforms can live separately but we believe that there is much power in using them combined so we are making sure the integration works like a charm.

" + "PUBLISH_MORE_INFO_TEXT": "

If you need help with a particular piece of work you can easily create gigs on Taiga Tribe and receive help from all over the world. You will be able to control and manage the gig enjoying a great community eager to contribute.

TaigaTribe was born as a Taiga sibling. Both platforms can live separately but we believe that there is much power in using them combined so we are making sure the integration works like a charm.

" }, "FIELDS": { "TEAM_REQUIREMENT": "團隊要求", - "CLIENT_REQUIREMENT": "客戶要求", - "FINISH_DATE": "完成日期" + "CLIENT_REQUIREMENT": "客戶要求" } }, "COMMENTS": { "DELETED_INFO": "Comment deleted by {{user}}", - "TITLE": "評論", "COMMENTS_COUNT": "{{comments}} Comments", - "ORDER": "Order", "OLDER_FIRST": "Older first", "RECENT_FIRST": "Recent first", "COMMENT": "評論", - "EDIT_COMMENT": "Edit comment", "EDITED_COMMENT": "Edited:", "SHOW_HISTORY": "View historic", "TYPE_NEW_COMMENT": "在此輸入一個新的評論", @@ -1148,13 +1166,8 @@ } }, "ACTIVITY": { - "SHOW_ACTIVITY": "顯示動態", - "DATETIME": "DD MMM YYYY HH:mm", - "SHOW_MORE": "+ 顯示過去條目 ({{showMore}} more)", "TITLE": "動態", "ACTIVITIES_COUNT": "{{activities}} Activities", - "REMOVED": "已移除", - "ADDED": "已加入", "TAGS_ADDED": "tags added:", "TAGS_REMOVED": "tags removed:", "US_POINTS": "{{role}} points", @@ -1163,50 +1176,21 @@ "UPDATED_ATTACHMENT": "updated attachment ({{filename}}):", "CREATED_CUSTOM_ATTRIBUTE": "created custom attribute", "UPDATED_CUSTOM_ATTRIBUTE": "updated custom attribute", - "SIZE_CHANGE": "使 {size, plural, one{更改} other{變化}}", "BECAME_DEPRECATED": "became deprecated", "BECAME_UNDEPRECATED": "became undeprecated", "TEAM_REQUIREMENT": "團隊要求", "CLIENT_REQUIREMENT": "客戶要求", "BLOCKED": "已封鎖", "VALUES": { - "YES": "yes", - "NO": "no", - "EMPTY": "空白", "UNASSIGNED": "未指派" }, "FIELDS": { "SUBJECT": "主旨", - "NAME": "名稱 ", "DESCRIPTION": "描述", - "CONTENT": "內容", "STATUS": "狀態", - "IS_CLOSED": "關閉中", - "FINISH_DATE": "完成日期", "TYPE": "類型", - "PRIORITY": "優先性", - "SEVERITY": "急迫性", "ASSIGNED_TO": "指派給 ", - "WATCHERS": "監督者", "MILESTONE": "衝刺任務", - "USER_STORY": "使用者故事", - "PROJECT": "專案", - "IS_BLOCKED": "封鎖", - "BLOCKED_NOTE": "已封鎖之筆記", - "POINTS": "點數", - "CLIENT_REQUIREMENT": "客戶要求", - "TEAM_REQUIREMENT": "團隊要求", - "IS_IOCAINE": "負予全新任務", - "TAGS": "標籤", - "ATTACHMENTS": "附件", - "IS_DEPRECATED": "被棄用", - "IS_NOT_DEPRECATED": "is not deprecated", - "ORDER": "次序", - "BACKLOG_ORDER": "待辦任務先後次序", - "SPRINT_ORDER": "衝刺任務次序", - "KANBAN_ORDER": "kanban看板次序", - "TASKBOARD_ORDER": "任務板次序", - "US_ORDER": "使用者故事次序", "COLOR": "顏色" } }, @@ -1220,8 +1204,6 @@ "CUSTOMIZE_GRAPH_TITLE": "透由管理頁面設置點數與衝刺任務 \n ", "MOVE_US_TO_CURRENT_SPRINT": "移到目前的 Sprint", "MOVE_US_TO_LATEST_SPRINT": "移到最近的一個衝刺任務 ", - "SHOW_FILTERS": "顯示過濾器", - "SHOW_TAGS": "顯示標籤 (Tag)", "EMPTY": "The backlog is empty!", "CREATE_NEW_US": "創建一個新的使用者故事", "CREATE_NEW_US_EMPTY_HELP": "你可以創建一個新使用者故事", @@ -1248,6 +1230,12 @@ "SHOW": "顯示標籤", "HIDE": "隱藏標籤" }, + "FORECASTING": { + "TITLE": "Velocity forecasting", + "BACKLOG": "Display backlog", + "NEW_SPRINT": "Candidate User Stories for your next sprint based on your velocity. Click to create a new sprint.", + "CURRENT_SPRINT": "Candidate User Stories for your sprint based on your velocity. Click to add to current sprint." + }, "TABLE": { "COLUMN_US": "使用者故事", "TITLE_COLUMN_POINTS": "選擇檢示每個角色" @@ -1270,8 +1258,6 @@ }, "FILTERS": { "TOGGLE": "切換過濾器可見度", - "TITLE": "過濾器", - "REMOVE": "移除過濾器", "HIDE": "隱藏過濾器", "SHOW": "顯示過濾器" }, @@ -1280,7 +1266,6 @@ "DATE": "DD MMM YYYY", "LINK_TASKBOARD": "衝刺任務板", "TITLE_LINK_TASKBOARD": "到任務板 {{spring.name}}", - "NUMBER_SPRINTS": "
衝刺任務 ", "EMPTY": "尚無衝刺任務", "WARNING_EMPTY_SPRINT_ANONYMOUS": "此衝刺任務無使用者故事", "WARNING_EMPTY_SPRINT": "Drop here Stories from your backlog to start a new sprint", @@ -1305,7 +1290,6 @@ "TITLE_ACTION_ADD": "增加新任務 ", "TITLE_ACTION_ADD_BULK": "批次加入新任務 ", "TITLE_ACTION_ASSIGN": "指派任務 ", - "TITLE_ACTION_EDIT": "結束任務 ", "PLACEHOLDER_CARD_TITLE": "這可能是一項任務", "PLACEHOLDER_CARD_TEXT": "Split Stories into tasks to track them separately", "TABLE": { @@ -1335,17 +1319,11 @@ "TITLE_SELECT_STATUS": "狀態名稱 ", "OWNER_US": "這任務屬於", "TITLE_LINK_GO_OWNER": "到使用者故事", - "ORIGIN_US": "此任務創造者是", - "TITLE_LINK_GO_ORIGIN": "到使用者故事", - "BLOCKED": "這任務已被封鎖", "TITLE_DELETE_ACTION": "刪除任務", "LIGHTBOX_TITLE_BLOKING_TASK": "封鎖中的任務 ", "FIELDS": { - "MILESTONE": "衝刺任務", - "USER_STORY": "使用者故事", "IS_IOCAINE": "負予全新任務" }, - "ACTION_IOCAINE": "挑戰全新任務", "TITLE_ACTION_IOCAINE": "感到任務的不勘負荷?確定其它人知道此狀況在編輯任務時點選此「毒藥鍵」。這種致命毒物如果長期吸食微量,最後可能免疫。因此你最好偶而做點出奇的挑戰。" }, "NOTIFICATION": { @@ -1374,14 +1352,12 @@ "ISSUES": { "PAGE_TITLE": "問題 - {{projectName}}", "PAGE_DESCRIPTION": " {{projectName}}的問題清單看版: {{projectDescription}}", - "LIST_SECTION_NAME": "問題 ", "SECTION_NAME": "問題", "ACTION_NEW_ISSUE": "+ 新問題 ", "ACTION_PROMOTE_TO_US": "提昇到使用者故事", "PROMOTED": "此問題已提昇成使用者故事 ", "EXTERNAL_REFERENCE": "此問題的提供者是", "GO_TO_EXTERNAL_REFERENCE": "回到一開始", - "BLOCKED": "這個議題已被封鎖", "ACTION_DELETE": "删除議題 ", "LIGHTBOX_TITLE_BLOKING_ISSUE": "封鎖中的問題", "FIELDS": { @@ -1423,15 +1399,11 @@ "SECTION_NAME": "Kanban(看板)", "TITLE_ACTION_FOLD": "隱藏欄位", "TITLE_ACTION_UNFOLD": "未隱藏欄位", - "TITLE_ACTION_FOLD_CARDS": "隱藏卡片", - "TITLE_ACTION_UNFOLD_CARDS": "未隱藏卡片", "TITLE_ACTION_ADD_US": "新增使用者故事", "TITLE_ACTION_ADD_BULK": "增加新批次", "ACTION_SHOW_ARCHIVED": "顯示歸檔資料", "ACTION_HIDE_ARCHIVED": "隱藏歸檔", "HIDDEN_USER_STORIES": "此狀態下的使用者故事預設為隱藏", - "ARCHIVED": "你已歸檔", - "UNDO_ARCHIVED": "拖移 & 丟到未做", "PLACEHOLDER_CARD_TITLE": "這裏是你的使用者故事", "PLACEHOLDER_CARD_TEXT": "在此可以找到你想了解的專案" }, @@ -1452,7 +1424,6 @@ "PAGE_TITLE": "團隊- {{projectName}}", "PAGE_DESCRIPTION": "團隊面版可顯示專案中所有成員{{projectName}}: {{projectDescription}}", "SECTION_NAME": "團隊", - "APP_TITLE": "團隊- {{projectName}}", "PLACEHOLDER_INPUT_SEARCH": "以全名搜尋", "COLUMN_MR_WOLF": "問題解決高手", "EXPLANATION_COLUMN_MR_WOLF": "已關閉議題 ", @@ -1488,18 +1459,9 @@ "OPTION_ALL": "所有", "OPTION_INVOLVED": "涉入", "OPTION_NONE": "無" - }, - "POPOVER": { - "USER_PROFILE": "使用者設定檔案", - "CHANGE_PASSWORD": "更換密碼 ", - "NOTIFICATIONS": "通知", - "FEEDBACK": "回饋 ", - "TITLE_AVATAR": "使用者偏好" } }, "USER_PROFILE": { - "IMAGE_HELP": "此圖片將被裁成80x80px.
", - "ACTION_CHANGE_IMAGE": "變更", "ACTION_USE_GRAVATAR": "使用預設圖像", "ACTION_DELETE_ACCOUNT": "刪除Taiga帳戶", "CHANGE_EMAIL_SUCCESS": "檢查你的收信箱
我們送出了一封信
裏面有設定你新電子郵件的相關指示", @@ -1517,25 +1479,10 @@ "THEME_DEFAULT": "-- 使用預設主題--" } }, - "WIZARD": { - "SECTION_TITLE_CREATE_PROJECT": "創建專案", - "CREATE_PROJECT_TEXT": "新鮮與乾淨,太好了", - "CHOOSE_TEMPLATE": "Which template fits your project best?", - "CHOOSE_TEMPLATE_TITLE": "More info about project templates", - "CHOOSE_TEMPLATE_INFO": "More info", - "PROJECT_DETAILS": "Project Details", - "PUBLIC_PROJECT": "Public Project", - "PRIVATE_PROJECT": "Private Project", - "CREATE_PROJECT": "創建專案", - "MAX_PRIVATE_PROJECTS": "You've reached the maximum number of private projects", - "MAX_PUBLIC_PROJECTS": "Unfortunately, you've reached the maximum number of public projects", - "CHANGE_PLANS": "change plans" - }, "WIKI": { "PAGE_TITLE": "{{wikiPageName}} - 維基 - {{projectName}}", "PAGE_DESCRIPTION": "上回編輯{{lastModifiedDate}} ({{totalEditions}} editions in total) 內容: {{ wikiPageContent }}", "DATETIME": "DD MMM YYYY HH:mm", - "PLACEHOLDER_PAGE": "編寫你的維基頁", "REMOVE": "移除此維基頁 ", "DELETE_LIGHTBOX_TITLE": "刪除維基頁", "DELETE_LINK_TITLE": "Delete Wiki link", @@ -1693,7 +1640,6 @@ "MOST_LIKED": "最受喜愛的", "MOST_LIKED_EMPTY": "尚未有喜愛的專案", "VIEW_MORE": "顯示更多", - "RECRUITING": "這個專案正在徵人", "FEATURED": "受矚目專案", "EMPTY": "沒有專案符合你尋找的條件.
再試一次", "FILTERS": { diff --git a/app/modules/components/assigned-to/assigned-item/assigned-item.directive.coffee b/app/modules/components/assigned-to/assigned-item/assigned-item.directive.coffee index 709ba6cc..03eb261f 100644 --- a/app/modules/components/assigned-to/assigned-item/assigned-item.directive.coffee +++ b/app/modules/components/assigned-to/assigned-item/assigned-item.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/assigned-to/assigned-to-selector/assigned-to-selector.directive.coffee b/app/modules/components/assigned-to/assigned-to-selector/assigned-to-selector.directive.coffee index b840e856..27c36326 100644 --- a/app/modules/components/assigned-to/assigned-to-selector/assigned-to-selector.directive.coffee +++ b/app/modules/components/assigned-to/assigned-to-selector/assigned-to-selector.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/assigned-to/assigned-to.directive.coffee b/app/modules/components/assigned-to/assigned-to.directive.coffee index a6ec47aa..06677d6f 100644 --- a/app/modules/components/assigned-to/assigned-to.directive.coffee +++ b/app/modules/components/assigned-to/assigned-to.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/attachment-link/attachment-link.directive.coffee b/app/modules/components/attachment-link/attachment-link.directive.coffee index d1a5d299..603d90ce 100644 --- a/app/modules/components/attachment-link/attachment-link.directive.coffee +++ b/app/modules/components/attachment-link/attachment-link.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/attachment/attachment-gallery.directive.coffee b/app/modules/components/attachment/attachment-gallery.directive.coffee index 2214a893..a2e33bf6 100644 --- a/app/modules/components/attachment/attachment-gallery.directive.coffee +++ b/app/modules/components/attachment/attachment-gallery.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/attachment/attachment-gallery.jade b/app/modules/components/attachment/attachment-gallery.jade index 4a131ef2..5a4a9074 100644 --- a/app/modules/components/attachment/attachment-gallery.jade +++ b/app/modules/components/attachment/attachment-gallery.jade @@ -32,6 +32,8 @@ a.icon-delete( href="" title="{{'COMMON.DELETE' | translate}}" + ng-if="!vm.attachment.get('editable')" + tg-check-permission="modify_{{vm.type}}" ng-click="vm.delete()" ) tg-svg(svg-icon="icon-trash") diff --git a/app/modules/components/attachment/attachment.directive.coffee b/app/modules/components/attachment/attachment.directive.coffee index 94202b8a..c84ad680 100644 --- a/app/modules/components/attachment/attachment.directive.coffee +++ b/app/modules/components/attachment/attachment.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/attachments-full/attachments-full.service.coffee b/app/modules/components/attachments-full/attachments-full.service.coffee index 2635f7c4..759a5e8a 100644 --- a/app/modules/components/attachments-full/attachments-full.service.coffee +++ b/app/modules/components/attachments-full/attachments-full.service.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -47,12 +47,12 @@ class AttachmentsFullService extends taiga.Service else @._attachmentsVisible = @._attachments.filter (it) -> !it.getIn(['file', 'is_deprecated']) - addAttachment: (projectId, objId, type, file, editable = true) -> + addAttachment: (projectId, objId, type, file, editable = true, comment = false) -> return new Promise (resolve, reject) => if @attachmentsService.validate(file) @.uploadingAttachments.push(file) - promise = @attachmentsService.upload(file, objId, projectId, type) + promise = @attachmentsService.upload(file, objId, projectId, type, comment) promise.then (file) => @.uploadingAttachments = @.uploadingAttachments.filter (uploading) -> return uploading.name != file.get('name') @@ -62,7 +62,8 @@ class AttachmentsFullService extends taiga.Service attachment = attachment.merge({ file: file, editable: editable, - loading: false + loading: false, + from_comment: comment }) @._attachments = @._attachments.push(attachment) diff --git a/app/modules/components/attachments-preview/attachments-preview.directive.coffee b/app/modules/components/attachments-preview/attachments-preview.directive.coffee index 4e6b48cf..dacb39aa 100644 --- a/app/modules/components/attachments-preview/attachments-preview.directive.coffee +++ b/app/modules/components/attachments-preview/attachments-preview.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/attachments-preview/attachments-preview.jade b/app/modules/components/attachments-preview/attachments-preview.jade index 0be41189..b2966ab7 100644 --- a/app/modules/components/attachments-preview/attachments-preview.jade +++ b/app/modules/components/attachments-preview/attachments-preview.jade @@ -10,8 +10,8 @@ tg-svg(svg-icon="icon-arrow-left") a(href="{{vm.current.get('url')}}", title="{{vm.current.get('description')}}", target="_blank", download="{{vm.current.get('name')}}") - tg-preload-image(preload-src="{{vm.getCurrent().get('url')}}") - img(ng-src="{{vm.getCurrent().get('url')}}") + tg-preload-image(preload-src="{{vm.current.get('preview_url') || vm.getCurrent().get('url')}}") + img(ng-src="{{vm.current.get('preview_url') || vm.getCurrent().get('url')}}") a.next( href="#", diff --git a/app/modules/components/attachments-preview/attachments-preview.service.coffee b/app/modules/components/attachments-preview/attachments-preview.service.coffee index 5739e8a0..b282f9b3 100644 --- a/app/modules/components/attachments-preview/attachments-preview.service.coffee +++ b/app/modules/components/attachments-preview/attachments-preview.service.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/attachments-sortable/attachments-sortable.directive.coffee b/app/modules/components/attachments-sortable/attachments-sortable.directive.coffee index f1e91147..ef1694cf 100644 --- a/app/modules/components/attachments-sortable/attachments-sortable.directive.coffee +++ b/app/modules/components/attachments-sortable/attachments-sortable.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/auto-select/auto-select.directive.coffee b/app/modules/components/auto-select/auto-select.directive.coffee index 5ac889cc..c03a1fd6 100644 --- a/app/modules/components/auto-select/auto-select.directive.coffee +++ b/app/modules/components/auto-select/auto-select.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/avatar/avatar.directive.coffee b/app/modules/components/avatar/avatar.directive.coffee index 96ea925e..5656a8d4 100644 --- a/app/modules/components/avatar/avatar.directive.coffee +++ b/app/modules/components/avatar/avatar.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/belong-to-epics/belong-to-epics.directive.coffee b/app/modules/components/belong-to-epics/belong-to-epics.directive.coffee index 91ffe19e..15032040 100644 --- a/app/modules/components/belong-to-epics/belong-to-epics.directive.coffee +++ b/app/modules/components/belong-to-epics/belong-to-epics.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/bind-code.directive.coffee b/app/modules/components/bind-code.directive.coffee new file mode 100644 index 00000000..e333036a --- /dev/null +++ b/app/modules/components/bind-code.directive.coffee @@ -0,0 +1,54 @@ +### +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: modules/components/bind-code.directive.coffee +### + +BindCode = ($sce, $parse, $compile, wysiwygService, wysiwygCodeHightlighterService) -> + return { + restrict: 'A', + compile: (tElement, tAttrs) -> + tgBindCodeGetter = $parse(tAttrs.tgBindCode) + tgBindCodeWatch = $parse tAttrs.tgBindCode, (value) -> + return (value || '').toString() + + $compile.$$addBindingClass(tElement) + + return (scope, element, attr) -> + $compile.$$addBindingInfo(element, attr.tgBindCode); + + scope.$watch tgBindCodeWatch, () -> + html = wysiwygService.getHTML(tgBindCodeGetter(scope)) + + element.html($sce.getTrustedHtml(html) || '') + + wysiwygCodeHightlighterService.addHightlighter(element) + + } + +angular.module("taigaComponents") + .directive("tgBindCode", [ + "$sce", + "$parse", + "$compile", + "tgWysiwygService", + "tgWysiwygCodeHightlighterService", + BindCode]) diff --git a/app/modules/components/board-zoom/board-zoom.directive.coffee b/app/modules/components/board-zoom/board-zoom.directive.coffee index cba9fdcf..51789f40 100644 --- a/app/modules/components/board-zoom/board-zoom.directive.coffee +++ b/app/modules/components/board-zoom/board-zoom.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/board-zoom/board-zoom.scss b/app/modules/components/board-zoom/board-zoom.scss index 5e5d7eb2..d04f643c 100644 --- a/app/modules/components/board-zoom/board-zoom.scss +++ b/app/modules/components/board-zoom/board-zoom.scss @@ -36,12 +36,15 @@ $contrast: 2; .range-slider { -webkit-appearance: none; + display: block; margin: $thumb-height / 2 0; width: $track-width; &:focus { + outline: 0; + &::-webkit-slider-runnable-track { - background: lighten($track-color, $contrast); + background: lighten($primary-dark, $contrast); } &::-webkit-slider-thumb { box-shadow: 0 0 0 4px $thumb-shadow; diff --git a/app/modules/components/card/card-templates/card-data.jade b/app/modules/components/card/card-templates/card-data.jade index e5fb512a..73f941c2 100644 --- a/app/modules/components/card/card-templates/card-data.jade +++ b/app/modules/components/card/card-templates/card-data.jade @@ -3,7 +3,7 @@ ng-class="{'empty-tasks': !vm.item.getIn(['model', 'tasks']).size}" ) span.card-estimation( - ng-if="vm.item.getIn(['model', 'total_points']) === null", + ng-if="vm.item.getIn(['model', 'total_points']) === null && vm.visible('empty_extra_info')", translate="US.NOT_ESTIMATED" ) span.card-estimation( @@ -17,12 +17,18 @@ tg-svg( svg-icon="icon-iocaine" ) - .statistic.card-votes(ng-class="{'active': vm.item.getIn(['model', 'is_voter'])}") + .statistic.card-votes( + ng-class="{'active': vm.item.getIn(['model', 'is_voter'])}" + ng-if="vm.item.getIn(['model', 'total_voters']) || vm.visible('empty_extra_info')" + ) tg-svg(svg-icon="icon-upvote") span {{vm.item.getIn(['model', 'total_voters'])}} - .statistic.card-watchers + .statistic.card-watchers(ng-if="vm.item.getIn(['model', 'watchers']).size || vm.visible('empty_extra_info')") tg-svg(svg-icon="icon-watch") span {{vm.item.getIn(['model', 'watchers']).size}} - .statistic.card-attachments(ng-if="vm.item.getIn(['model', 'attachments']).size") + .statistic.card-comments(ng-if="vm.item.getIn(['model', 'total_comments']) || vm.visible('empty_extra_info')") + tg-svg(svg-icon="icon-bubble-empty") + span {{vm.item.getIn(['model', 'total_comments'])}} + .statistic.card-attachments(ng-if="vm.item.getIn(['model', 'attachments']).size || vm.visible('empty_extra_info')") tg-svg(svg-icon="icon-attachment") span {{vm.item.getIn(['model', 'attachments']).size}} diff --git a/app/modules/components/card/card-templates/card-unfold.jade b/app/modules/components/card/card-templates/card-unfold.jade index 5b734660..cefcfc47 100644 --- a/app/modules/components/card/card-templates/card-unfold.jade +++ b/app/modules/components/card/card-templates/card-unfold.jade @@ -1,6 +1,11 @@ .card-unfold.ng-animate-disabled( ng-click="vm.toggleFold()" - ng-if="vm.visible('unfold') && (vm.item.getIn(['model', 'tasks']).size || vm.item.get('images').size)" + ng-if="vm.visible('unfold')" role="button" ) tg-svg(svg-icon="icon-view-more") + +.loading-extra( + tg-loading="vm.item.get('loading-extra')" + + ) diff --git a/app/modules/components/card/card.controller.spec.coffee b/app/modules/components/card/card.controller.spec.coffee index 3e2ed30c..b24360b9 100644 --- a/app/modules/components/card/card.controller.spec.coffee +++ b/app/modules/components/card/card.controller.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/card/card.scss b/app/modules/components/card/card.scss index 47d3c57d..5dfbbe5b 100644 --- a/app/modules/components/card/card.scss +++ b/app/modules/components/card/card.scss @@ -5,6 +5,10 @@ margin: 0 .6rem .6rem; overflow: hidden; transition: box-shadow .2s ease-in; + .loading-extra.loading { + padding: .2rem; + text-align: center; + } &:hover { box-shadow: 3px 3px 6px darken($whitish, 10%); } diff --git a/app/modules/components/click-input-file.directive.coffee b/app/modules/components/click-input-file.directive.coffee new file mode 100644 index 00000000..49d83375 --- /dev/null +++ b/app/modules/components/click-input-file.directive.coffee @@ -0,0 +1,39 @@ +### +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: modules/components/click-input-file.directive.coffee +### + +ClickInputFile = () -> + return { + link: (scope, el) -> + el.on 'click', (e) -> + if !$(e.target).is('input') + e.preventDefault() + inputFile = el.find('input[type="file"]') + inputFile.val('') + inputFile.trigger('click') + + scope.$on "$destroy", -> el.off() + } + +angular.module("taigaComponents") + .directive("tgClickInputFile", [ClickInputFile]) diff --git a/app/modules/components/color-selector/color-selector.controller.coffee b/app/modules/components/color-selector/color-selector.controller.coffee index 47838f23..25bd621e 100644 --- a/app/modules/components/color-selector/color-selector.controller.coffee +++ b/app/modules/components/color-selector/color-selector.controller.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/color-selector/color-selector.directive.coffee b/app/modules/components/color-selector/color-selector.directive.coffee index f020e408..6778666a 100644 --- a/app/modules/components/color-selector/color-selector.directive.coffee +++ b/app/modules/components/color-selector/color-selector.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/components.module.coffee b/app/modules/components/components.module.coffee index 468886b6..d1c526b4 100644 --- a/app/modules/components/components.module.coffee +++ b/app/modules/components/components.module.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/detail/header/detail-header.directive.coffee b/app/modules/components/detail/header/detail-header.directive.coffee index 10267d0f..3f120659 100644 --- a/app/modules/components/detail/header/detail-header.directive.coffee +++ b/app/modules/components/detail/header/detail-header.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/detail/header/detail-header.jade b/app/modules/components/detail/header/detail-header.jade index 842a09d7..a678babd 100644 --- a/app/modules/components/detail/header/detail-header.jade +++ b/app/modules/components/detail/header/detail-header.jade @@ -11,11 +11,12 @@ span.detail-subject.e2e-title-subject( ng-if="!vm.permissions.canEdit" ) {{vm.item.subject}} - tg-svg.detail-edit.e2e-detail-edit( + a( + href="" ng-if="vm.permissions.canEdit" - svg-icon="icon-edit" ng-click="vm.editSubject(true)" ) + tg-svg.detail-edit.e2e-detail-edit(svg-icon="icon-edit") .edit-title-wrapper(ng-if="vm.editMode") input.edit-title-input.e2e-title-input( diff --git a/app/modules/components/file-change/file-change.directive.coffee b/app/modules/components/file-change/file-change.directive.coffee index 3c94f94a..aedef73b 100644 --- a/app/modules/components/file-change/file-change.directive.coffee +++ b/app/modules/components/file-change/file-change.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -27,7 +27,6 @@ FileChangeDirective = ($parse) -> scope.$on "$destroy", -> el.off() return { - require: "ngModel", restrict: "A", link: link } diff --git a/app/modules/components/filter/filter-remote.service.coffee b/app/modules/components/filter/filter-remote.service.coffee index 95435432..a7e66542 100644 --- a/app/modules/components/filter/filter-remote.service.coffee +++ b/app/modules/components/filter/filter-remote.service.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/filter/filter.controller.spec.coffee b/app/modules/components/filter/filter.controller.spec.coffee index bb9a9140..e273bfbf 100644 --- a/app/modules/components/filter/filter.controller.spec.coffee +++ b/app/modules/components/filter/filter.controller.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/filter/filter.directive.coffee b/app/modules/components/filter/filter.directive.coffee index c15eb137..1ddc01af 100644 --- a/app/modules/components/filter/filter.directive.coffee +++ b/app/modules/components/filter/filter.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -26,6 +26,14 @@ FilterDirective = () -> else if scope.vm.filtersForm.$dirty unwatch() + attrs.$observe "open", (open) -> + open = scope.$eval(open) + + if open + el.addClass('open') + else + el.removeClass('open') + return { scope: { onChangeQ: "&", diff --git a/app/modules/components/filter/filter.scss b/app/modules/components/filter/filter.scss index 3782d855..109b78cf 100644 --- a/app/modules/components/filter/filter.scss +++ b/app/modules/components/filter/filter.scss @@ -1,16 +1,26 @@ tg-filter { background-color: $mass-white; - box-shadow: 1px 1px 5px rgbag($primary, .2); + box-shadow: 1px 1px 5px rgba($primary, .2); display: block; left: 0; min-height: 100%; padding: 1rem 0; position: absolute; top: 0; + transform: translateX(-260px); + transition-duration: .5s; width: 260px; z-index: 1; .filters-applied { padding: 0 1rem 1rem; + .single-filter { + &:hover { + color: currentColor; + cursor: default; + opacity: .5; + transition: none; + } + } } h1, form { @@ -28,18 +38,7 @@ tg-filter { right: .7rem; top: .7rem; } - &.ng-hide-add { - transform: translateX(0); - transition-duration: .5s; - } - &.ng-hide-add-active { - transform: translateX(-260px); - } - &.ng-hide-remove { - transform: translateX(-260px); - transition-duration: .5s; - } - &.ng-hide-remove-active { + &.open { transform: translateX(0); } } @@ -78,7 +77,7 @@ tg-filter { transition: color .2s ease-in; &:hover, &.selected { - background-color: rgba(darken($whitish, 20%), 1); + background-color: rgba(darken($whitish, 10%), 1); color: $grayer; transition: background-color .2s ease-in; .icon { @@ -101,7 +100,7 @@ tg-filter { @include font-type(text); @include clearfix; align-items: center; - background: darken($whitish, 10%); // Fallback + background: darken($whitish, 5%); cursor: pointer; display: flex; justify-content: space-between; @@ -110,7 +109,7 @@ tg-filter { padding-right: .5rem; position: relative; &:hover { - color: $grayer; + background: darken($whitish, 8%); opacity: 1; transition: opacity .2s linear; } @@ -136,6 +135,7 @@ tg-filter { top: 0; } .remove-filter { + cursor: pointer; display: block; svg { fill: $gray; diff --git a/app/modules/components/joy-ride/joy-ride.directive.coffee b/app/modules/components/joy-ride/joy-ride.directive.coffee index 1f2a79a8..b667aed9 100644 --- a/app/modules/components/joy-ride/joy-ride.directive.coffee +++ b/app/modules/components/joy-ride/joy-ride.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/joy-ride/joy-ride.service.coffee b/app/modules/components/joy-ride/joy-ride.service.coffee index bf22b54b..12c533c3 100644 --- a/app/modules/components/joy-ride/joy-ride.service.coffee +++ b/app/modules/components/joy-ride/joy-ride.service.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/joy-ride/joy-ride.service.spec.coffee b/app/modules/components/joy-ride/joy-ride.service.spec.coffee index 06e944de..4876b830 100644 --- a/app/modules/components/joy-ride/joy-ride.service.spec.coffee +++ b/app/modules/components/joy-ride/joy-ride.service.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/kanban-board-zoom/kanban-board-zoom.directive.coffee b/app/modules/components/kanban-board-zoom/kanban-board-zoom.directive.coffee index 26e60a0f..cf613dd0 100644 --- a/app/modules/components/kanban-board-zoom/kanban-board-zoom.directive.coffee +++ b/app/modules/components/kanban-board-zoom/kanban-board-zoom.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -27,7 +27,7 @@ KanbanBoardZoomDirective = (storage, projectService) -> ["subject"], ["owner", "tags", "extra_info", "unfold"], ["attachments"], - ["related_tasks"] + ["related_tasks", "empty_extra_info"] ] getZoomView = (zoomIndex = 0) -> diff --git a/app/modules/components/live-announcement/live-announcement.directive.coffee b/app/modules/components/live-announcement/live-announcement.directive.coffee index b175ebf3..0c61e4ad 100644 --- a/app/modules/components/live-announcement/live-announcement.directive.coffee +++ b/app/modules/components/live-announcement/live-announcement.directive.coffee @@ -2,9 +2,9 @@ # Copyright (C) 2014-2015 Andrey Antukh # Copyright (C) 2014-2015 Jesús Espino Garcia # Copyright (C) 2014-2015 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/project-logo-big-src/project-logo-big-src.directive.coffee b/app/modules/components/project-logo-big-src/project-logo-big-src.directive.coffee index 2c271629..85e90f1f 100644 --- a/app/modules/components/project-logo-big-src/project-logo-big-src.directive.coffee +++ b/app/modules/components/project-logo-big-src/project-logo-big-src.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/project-logo-small-src/project-logo-small-src.directive.coffee b/app/modules/components/project-logo-small-src/project-logo-small-src.directive.coffee index 51900e2e..9e4edfb9 100644 --- a/app/modules/components/project-logo-small-src/project-logo-small-src.directive.coffee +++ b/app/modules/components/project-logo-small-src/project-logo-small-src.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/project-menu/project-menu.controller.coffee b/app/modules/components/project-menu/project-menu.controller.coffee index 9ef67946..b7a0b866 100644 --- a/app/modules/components/project-menu/project-menu.controller.coffee +++ b/app/modules/components/project-menu/project-menu.controller.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/project-menu/project-menu.controller.spec.coffee b/app/modules/components/project-menu/project-menu.controller.spec.coffee index 65601c88..9771a85e 100644 --- a/app/modules/components/project-menu/project-menu.controller.spec.coffee +++ b/app/modules/components/project-menu/project-menu.controller.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/project-menu/project-menu.directive.coffee b/app/modules/components/project-menu/project-menu.directive.coffee index ee3da69b..6b39ff7d 100644 --- a/app/modules/components/project-menu/project-menu.directive.coffee +++ b/app/modules/components/project-menu/project-menu.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/tags/tag-dropdown/tag-dropdown.directive.coffee b/app/modules/components/tags/tag-dropdown/tag-dropdown.directive.coffee index c1386e2f..723945ef 100644 --- a/app/modules/components/tags/tag-dropdown/tag-dropdown.directive.coffee +++ b/app/modules/components/tags/tag-dropdown/tag-dropdown.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -61,7 +61,7 @@ TagOptionDirective = () -> link = (scope, el) -> stop() - $(document).on "keydown.tags-keyboard-navigation", (event) => + $(el).parent().on "keydown.tags-keyboard-navigation", (event) => code = if event.keyCode then event.keyCode else event.which if code == 40 || code == 38 diff --git a/app/modules/components/tags/tag-line-common/tag-line-common.controller.coffee b/app/modules/components/tags/tag-line-common/tag-line-common.controller.coffee index dde598ea..33b069ce 100644 --- a/app/modules/components/tags/tag-line-common/tag-line-common.controller.coffee +++ b/app/modules/components/tags/tag-line-common/tag-line-common.controller.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/tags/tag-line-common/tag-line-common.directive.coffee b/app/modules/components/tags/tag-line-common/tag-line-common.directive.coffee index 1fd9e8f6..f20f210c 100644 --- a/app/modules/components/tags/tag-line-common/tag-line-common.directive.coffee +++ b/app/modules/components/tags/tag-line-common/tag-line-common.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/tags/tag-line-detail/tag-line-detail.controller.coffee b/app/modules/components/tags/tag-line-detail/tag-line-detail.controller.coffee index 5130cac6..349b22e4 100644 --- a/app/modules/components/tags/tag-line-detail/tag-line-detail.controller.coffee +++ b/app/modules/components/tags/tag-line-detail/tag-line-detail.controller.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/tags/tag-line-detail/tag-line-detail.directive.coffee b/app/modules/components/tags/tag-line-detail/tag-line-detail.directive.coffee index 50976ab6..4cb58ab7 100644 --- a/app/modules/components/tags/tag-line-detail/tag-line-detail.directive.coffee +++ b/app/modules/components/tags/tag-line-detail/tag-line-detail.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/tags/tag-line.service.coffee b/app/modules/components/tags/tag-line.service.coffee index f8257b8a..46760652 100644 --- a/app/modules/components/tags/tag-line.service.coffee +++ b/app/modules/components/tags/tag-line.service.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/tags/tag/tag.directive.coffee b/app/modules/components/tags/tag/tag.directive.coffee index ccd366f1..8fbe1da0 100644 --- a/app/modules/components/tags/tag/tag.directive.coffee +++ b/app/modules/components/tags/tag/tag.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/taskboard-zoom/taskboard-zoom.directive.coffee b/app/modules/components/taskboard-zoom/taskboard-zoom.directive.coffee index 7db01d43..16e06b07 100644 --- a/app/modules/components/taskboard-zoom/taskboard-zoom.directive.coffee +++ b/app/modules/components/taskboard-zoom/taskboard-zoom.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -27,7 +27,7 @@ TaskboardZoomDirective = (storage) -> ["ref"], ["subject"], ["owner", "tags", "extra_info", "unfold"], - ["attachments"], + ["attachments", "empty_extra_info"], ["related_tasks"] ] diff --git a/app/modules/components/terms-of-service-and-privacy-policy-notice/terms-of-service-and-privacy-policy-notice.directive.coffee b/app/modules/components/terms-of-service-and-privacy-policy-notice/terms-of-service-and-privacy-policy-notice.directive.coffee index ae8b4b56..f7236786 100644 --- a/app/modules/components/terms-of-service-and-privacy-policy-notice/terms-of-service-and-privacy-policy-notice.directive.coffee +++ b/app/modules/components/terms-of-service-and-privacy-policy-notice/terms-of-service-and-privacy-policy-notice.directive.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/tribe-button/tribe-linked.jade b/app/modules/components/tribe-button/tribe-linked.jade index 965e8997..51450b29 100644 --- a/app/modules/components/tribe-button/tribe-linked.jade +++ b/app/modules/components/tribe-button/tribe-linked.jade @@ -22,7 +22,7 @@ ) {{gigTitle}} a.delete-link( - href="{{::vm.tribeHost}}/gigs/{{gigId}}/link-with-taiga?from=taiga" + href="{{::vm.tribeHost}}/gigs/{{gigId}}/link-with-task-manager?from=taiga" title="{{ 'US.TRIBE.EDIT_LINK' | translate }}" ) {{ 'US.TRIBE.EDIT_LINK' | translate }} diff --git a/app/modules/components/vote-button/vote-button.controller.coffee b/app/modules/components/vote-button/vote-button.controller.coffee index 64c4de24..e9cdb8e1 100644 --- a/app/modules/components/vote-button/vote-button.controller.coffee +++ b/app/modules/components/vote-button/vote-button.controller.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/vote-button/vote-button.controller.spec.coffee b/app/modules/components/vote-button/vote-button.controller.spec.coffee index a0201853..ac2cc030 100644 --- a/app/modules/components/vote-button/vote-button.controller.spec.coffee +++ b/app/modules/components/vote-button/vote-button.controller.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/vote-button/vote-button.directive.coffee b/app/modules/components/vote-button/vote-button.directive.coffee index 970661c2..f6d95825 100644 --- a/app/modules/components/vote-button/vote-button.directive.coffee +++ b/app/modules/components/vote-button/vote-button.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/watch-button/watch-button.controller.coffee b/app/modules/components/watch-button/watch-button.controller.coffee index e7cbae9c..7176ebe4 100644 --- a/app/modules/components/watch-button/watch-button.controller.coffee +++ b/app/modules/components/watch-button/watch-button.controller.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/watch-button/watch-button.controller.spec.coffee b/app/modules/components/watch-button/watch-button.controller.spec.coffee index 77247468..67e3c4ef 100644 --- a/app/modules/components/watch-button/watch-button.controller.spec.coffee +++ b/app/modules/components/watch-button/watch-button.controller.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/watch-button/watch-button.directive.coffee b/app/modules/components/watch-button/watch-button.directive.coffee index a5797950..aecef621 100644 --- a/app/modules/components/watch-button/watch-button.directive.coffee +++ b/app/modules/components/watch-button/watch-button.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/components/wysiwyg/comment-edit-wysiwyg.directive.coffee b/app/modules/components/wysiwyg/comment-edit-wysiwyg.directive.coffee new file mode 100644 index 00000000..8c7e7aac --- /dev/null +++ b/app/modules/components/wysiwyg/comment-edit-wysiwyg.directive.coffee @@ -0,0 +1,60 @@ +### +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: modules/components/wysiwyg/comment-edit-wysiwyg.directive.coffee +### + +CommentEditWysiwyg = (attachmentsFullService) -> + link = ($scope, $el, $attrs) -> + types = { + epics: "epic", + userstories: "us", + issues: "issue", + tasks: "task" + } + + uploadFile = (file, cb) -> + return attachmentsFullService.addAttachment($scope.vm.projectId, $scope.vm.comment.comment.id, types[$scope.vm.comment.comment._name], file, true, true).then (result) -> + cb(result.getIn(['file', 'name']), result.getIn(['file', 'url'])) + + $scope.uploadFiles = (files, cb) -> + for file in files + uploadFile(file, cb) + + return { + scope: true, + link: link, + template: """ +
+ + +
+ """ + } + +angular.module("taigaComponents") + .directive("tgCommentEditWysiwyg", ["tgAttachmentsFullService", CommentEditWysiwyg]) diff --git a/app/modules/components/wysiwyg/comment-wysiwyg.directive.coffee b/app/modules/components/wysiwyg/comment-wysiwyg.directive.coffee new file mode 100644 index 00000000..73d4421b --- /dev/null +++ b/app/modules/components/wysiwyg/comment-wysiwyg.directive.coffee @@ -0,0 +1,78 @@ +### +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: modules/components/wysiwyg/comment-wysiwyg.directive.coffee +### + +CommentWysiwyg = (attachmentsFullService) -> + link = ($scope, $el, $attrs) -> + $scope.editableDescription = false + + $scope.saveComment = (description, cb) -> + $scope.content = '' + $scope.vm.type.comment = description + $scope.vm.onAddComment({callback: cb}) + + types = { + epics: "epic", + userstories: "us", + issues: "issue", + tasks: "task" + } + + uploadFile = (file, cb) -> + return attachmentsFullService.addAttachment($scope.vm.projectId, $scope.vm.type.id, types[$scope.vm.type._name], file, true, true).then (result) -> + cb(result.getIn(['file', 'name']), result.getIn(['file', 'url'])) + + $scope.onChange = (markdown) -> + $scope.vm.type.comment = markdown + + $scope.uploadFiles = (files, cb) -> + for file in files + uploadFile(file, cb) + + $scope.content = '' + + $scope.$watch "vm.type", (value) -> + return if not value + + $scope.storageKey = "comment-" + value.project + "-" + value.id + "-" + value._name + + return { + scope: true, + link: link, + template: """ +
+ + +
+ """ + } + +angular.module("taigaComponents") + .directive("tgCommentWysiwyg", ["tgAttachmentsFullService", CommentWysiwyg]) diff --git a/app/modules/components/wysiwyg/custom-field-edit-wysiwyg.directive.coffee b/app/modules/components/wysiwyg/custom-field-edit-wysiwyg.directive.coffee new file mode 100644 index 00000000..384cbc00 --- /dev/null +++ b/app/modules/components/wysiwyg/custom-field-edit-wysiwyg.directive.coffee @@ -0,0 +1,58 @@ +### +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: modules/components/wysiwyg/comment-edit-wysiwyg.directive.coffee +### + +CustomFieldEditWysiwyg = (attachmentsFullService) -> + link = ($scope, $el, $attrs) -> + types = { + userstories: "us", + issues: "issue", + tasks: "task" + } + + uploadFile = (file, cb) -> + return attachmentsFullService.addAttachment($scope.vm.projectId, $scope.vm.comment.comment.id, types[$scope.vm.comment.comment._name], file).then (result) -> + cb(result.getIn(['file', 'name']), result.getIn(['file', 'url'])) + + $scope.uploadFiles = (files, cb) -> + for file in files + uploadFile(file, cb) + + return { + scope: true, + link: link, + template: """ +
+ + +
+ """ + } + +angular.module("taigaComponents") + .directive("tgCustomFieldEditWysiwyg", ["tgAttachmentsFullService", CustomFieldEditWysiwyg]) diff --git a/app/modules/components/wysiwyg/item-wysiwyg.directive.coffee b/app/modules/components/wysiwyg/item-wysiwyg.directive.coffee new file mode 100644 index 00000000..b64ccf0d --- /dev/null +++ b/app/modules/components/wysiwyg/item-wysiwyg.directive.coffee @@ -0,0 +1,100 @@ +### +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: modules/components/wysiwyg/item-wysiwyg.directive.coffee +### + +# Used in details descriptions +ItemWysiwyg = ($modelTransform, $rootscope, $confirm, attachmentsFullService, $translate) -> + link = ($scope, $el, $attrs) -> + $scope.editableDescription = false + + $scope.saveDescription = (description, cb) -> + transform = $modelTransform.save (item) -> + item.description = description + + return item + + transform.then -> + $confirm.notify("success") + $rootscope.$broadcast("object:updated") + + transform.then null, -> + $confirm.notify("error") + + transform.finally(cb) + + uploadFile = (file, cb) -> + return attachmentsFullService.addAttachment($scope.project.id, $scope.item.id, $attrs.type, file).then (result) -> + cb(result.getIn(['file', 'name']), result.getIn(['file', 'url'])) + + $scope.uploadFiles = (files, cb) -> + for file in files + uploadFile(file, cb) + + $scope.$watch $attrs.model, (value) -> + return if not value + $scope.item = value + $scope.version = value.version + $scope.storageKey = $scope.project.id + "-" + value.id + "-" + $attrs.type + + $scope.$watch 'project', (project) -> + return if !project + + $scope.editableDescription = project.my_permissions.indexOf($attrs.requiredPerm) != -1 + + return { + scope: true, + link: link, + template: """ +
+ + + +
+ +
+ {{'COMMON.DESCRIPTION.NO_DESCRIPTION' | translate}} +
+
+ """ + } + +angular.module("taigaComponents") + .directive("tgItemWysiwyg", [ + "$tgQueueModelTransformation", + "$rootScope", + "$tgConfirm", + "tgAttachmentsFullService", + "$translate", + ItemWysiwyg]) diff --git a/app/modules/components/wysiwyg/wysiwyg-code-hightlighter.service.coffee b/app/modules/components/wysiwyg/wysiwyg-code-hightlighter.service.coffee new file mode 100644 index 00000000..7a07e17f --- /dev/null +++ b/app/modules/components/wysiwyg/wysiwyg-code-hightlighter.service.coffee @@ -0,0 +1,74 @@ +### +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: modules/components/wysiwyg/wysiwyg-code-hightlighter.service.coffee +### + +class WysiwygCodeHightlighterService + getLanguages: () -> + return new Promise (resolve, reject) => + if @.languages + resolve(@.languages) + else if @.loadPromise + @.loadPromise.then () => resolve(@.languages) + else + @.loadPromise = $.getJSON("/#{window._version}/prism/prism-languages.json").then (_languages_) => + @.loadPromise = null + @.languages = _.map _languages_, (it) -> + it.url = "/#{window._version}/prism/" + it.file + + return it + + resolve(@.languages) + + getLanguageInClassList: (classes) -> + lan = _.find @.languages, (it) -> + return !!_.find classes, (className) -> + return 'language-' + it.name == className + + return if lan then lan.name else null + + loadLanguage: (lan) -> + return new Promise (resolve) -> + if !Prism.languages[lan] + ljs.load("/#{window._version}/prism/prism-#{lan}.min.js", resolve) + else + resolve() + + # firefox adds br instead of new lines inside + replaceCodeBrToNl: (code) -> + $(code).find('br').replaceWith('\n') + + hightlightCode: (code) -> + @.replaceCodeBrToNl(code) + + lan = @.getLanguageInClassList(code.classList) + + if lan + @.loadLanguage(lan).then () -> Prism.highlightElement(code) + + addHightlighter: (element) -> + codes = $(element).find('code') + + codes.each (index, code) => @.hightlightCode(code) + +angular.module("taigaComponents") + .service("tgWysiwygCodeHightlighterService", WysiwygCodeHightlighterService) diff --git a/app/modules/components/wysiwyg/wysiwyg-code-lightbox/wysiwyg-code-lightbox.directive.coffee b/app/modules/components/wysiwyg/wysiwyg-code-lightbox/wysiwyg-code-lightbox.directive.coffee new file mode 100644 index 00000000..60ab593b --- /dev/null +++ b/app/modules/components/wysiwyg/wysiwyg-code-lightbox/wysiwyg-code-lightbox.directive.coffee @@ -0,0 +1,55 @@ +### +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: modules/components/wysiwyg/wysiwyg-code-lightbox/wysiwyg-code-lightbox.directive.coffee +### + +WysiwygCodeLightbox = (lightboxService) -> + link = (scope, el, attrs, ctrl) -> + scope.$watch 'visible', (visible) -> + if visible && !el.hasClass('open') + scope.open = true + lightboxService.open(el, null, scope.onClose) + + scope.$applyAsync () -> + textarea = el[0].querySelector('textarea') + if textarea + textarea.select() + + else if !visible && el.hasClass('open') + scope.open = false + lightboxService.close(el) + + return { + scope: { + languages: '<', + codeLanguage: '<', + code: '<', + visible: '<', + onClose: '&', + onSave: '&' + }, + link: link, + templateUrl: "components/wysiwyg/wysiwyg-code-lightbox/wysiwyg-code-lightbox.html" + } + +angular.module("taigaComponents") + .directive("tgWysiwygCodeLightbox", ["lightboxService", WysiwygCodeLightbox]) diff --git a/app/modules/components/wysiwyg/wysiwyg-code-lightbox/wysiwyg-code-lightbox.jade b/app/modules/components/wysiwyg/wysiwyg-code-lightbox/wysiwyg-code-lightbox.jade new file mode 100644 index 00000000..7126b3bb --- /dev/null +++ b/app/modules/components/wysiwyg/wysiwyg-code-lightbox/wysiwyg-code-lightbox.jade @@ -0,0 +1,25 @@ +tg-lightbox-close(on-close="onClose()") + +form( + ng-if="open" + ng-submit="onSave({lan: codeLanguage, code: code})" +) + h2.title(translate="COMMON.WYSIWYG.CODE_SNIPPET") + + fieldset + select(ng-model="codeLanguage") + option(value="") {{'COMMON.WYSIWYG.SELECT_LANGUAGE_PLACEHOLDER' | translate}} + option(value="remove-formating") {{'COMMON.WYSIWYG.SELECT_LANGUAGE_REMOVE_FORMATING' | translate}} + option( + ng-repeat="option in languages" + ng-value="option.name" + ) {{option.name}} + + fieldset + textarea(ng-model="code") + + fieldset + button.button-green.submit-button( + type="submit" + translate="COMMON.SAVE" + ) diff --git a/app/modules/components/wysiwyg/wysiwyg-code-lightbox/wysiwyg-code-lightbox.scss b/app/modules/components/wysiwyg/wysiwyg-code-lightbox/wysiwyg-code-lightbox.scss new file mode 100644 index 00000000..5ff6ea2f --- /dev/null +++ b/app/modules/components/wysiwyg/wysiwyg-code-lightbox/wysiwyg-code-lightbox.scss @@ -0,0 +1,3 @@ +tg-wysiwyg-code-lightbox textarea { + height: 350px; +} diff --git a/app/modules/components/wysiwyg/wysiwyg-mention.service.coffee b/app/modules/components/wysiwyg/wysiwyg-mention.service.coffee new file mode 100644 index 00000000..d450d095 --- /dev/null +++ b/app/modules/components/wysiwyg/wysiwyg-mention.service.coffee @@ -0,0 +1,119 @@ +### +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: modules/components/wysiwyg/wysiwyg-mention.service.coffee +### + +class WysiwygMentionService + @.$inject = [ + "tgProjectService", + "tgWysiwygService", + "$tgNavUrls", + "$tgResources" + ] + + constructor: (@projectService, @wysiwygService, @navurls, @rs) -> + @.cancelablePromise = null + + searchEmoji: (name, cb) -> + filteredEmojis = @wysiwygService.searchEmojiByName(name) + filteredEmojis = filteredEmojis.slice(0, 10) + + cb(filteredEmojis) + + searchUser: (term, cb) -> + searchProps = ['username', 'full_name', 'full_name_display'] + + users = @projectService.project.toJS().members.filter (user) => + for prop in searchProps + if taiga.slugify(user[prop]).indexOf(term) >= 0 + return true + return false + + users = users.slice(0, 10).map (it) => + it.url = @navurls.resolve('user-profile', { + project: @projectService.project.get('slug'), + username: it.username + }) + + return it + + cb(users) + + searchItem: (term) -> + return new Promise (resolve, reject) => + term = taiga.slugify(term) + + searchTypes = ['issues', 'tasks', 'userstories'] + + urls = { + issues: "project-issues-detail", + tasks: "project-tasks-detail", + userstories: "project-userstories-detail" + } + + searchProps = ['ref', 'subject'] + + filter = (item) => + for prop in searchProps + if taiga.slugify(item[prop]).indexOf(term) >= 0 + return true + return false + + @.cancelablePromise.abort() if @.cancelablePromise + + @.cancelablePromise = @rs.search.do(@projectService.project.get('id'), term) + + @.cancelablePromise.then (res) => + # ignore wikipages if they're the only results. can't exclude them in search + if res.count < 1 or res.count == res.wikipages.length + resolve([]) + else + result = [] + for type in searchTypes + if res[type] and res[type].length > 0 + items = res[type].filter(filter) + items = items.map (it) => + it.url = @navurls.resolve(urls[type], { + project: @projectService.project.get('slug'), + ref: it.ref + }) + + return it + + result = result.concat(items) + + result = _.sortBy result, ["ref"] + + resolve(result.slice(0, 10)) + + + search: (mention) -> + return new Promise (resolve) => + if '#'.indexOf(mention[0]) != -1 + @.searchItem(mention.replace('#', '')).then(resolve) + else if '@'.indexOf(mention[0]) != -1 + @.searchUser(mention.replace('@', ''), resolve) + else if ':'.indexOf(mention[0]) != -1 + @.searchEmoji(mention.replace(':', ''), resolve) + + +angular.module("taigaComponents").service("tgWysiwygMentionService", WysiwygMentionService) diff --git a/app/modules/components/wysiwyg/wysiwyg.directive.coffee b/app/modules/components/wysiwyg/wysiwyg.directive.coffee new file mode 100644 index 00000000..ad7f4ddb --- /dev/null +++ b/app/modules/components/wysiwyg/wysiwyg.directive.coffee @@ -0,0 +1,585 @@ +### +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: modules/components/wysiwyg/wysiwyg.directive.coffee +### + +taiga = @.taiga +bindOnce = @.taiga.bindOnce + +Medium = ($translate, $confirm, $storage, wysiwygService, animationFrame, tgLoader, wysiwygCodeHightlighterService, wysiwygMentionService, analytics) -> + removeSelections = () -> + if window.getSelection + if window.getSelection().empty + window.getSelection().empty(); + else if window.getSelection().removeAllRanges + window.getSelection().removeAllRanges() + + else if document.selection + document.selection.empty() + + getRangeCodeBlock = (range) -> + return $(range.endContainer).parentsUntil('.editor', 'code') + + isCodeBlockSelected = (range) -> + return !!getRangeCodeBlock(range).length + + removeCodeBlockAndHightlight = (selection, mediumInstance) -> + if $(selection).is('code') + code = selection + else + code = $(selection).closest('code')[0] + + pre = code.parentNode + + p = document.createElement('p') + p.innerText = code.innerText + + pre.parentNode.replaceChild(p, pre) + mediumInstance.checkContentChanged(mediumInstance.elements[0]) + + addCodeBlockAndHightlight = (range, elm) -> + pre = document.createElement('pre') + code = document.createElement('code') + + console.log range.startContainer.parentNode.nextSibling + + if !range.startContainer.parentNode.nextSibling + $('
').insertAfter(range.startContainer.parentNode) + + start = range.startContainer.parentNode.nextSibling + + code.appendChild(range.extractContents()) + + pre.appendChild(code) + + start.parentNode.insertBefore(pre, start) + + refreshCodeBlocks(elm) + + refreshCodeBlocks = (mediumInstance) -> + # clean empty

content editable adds it when range.extractContents has been execute it + for mainChildren in mediumInstance.elements[0].children + if mainChildren && mainChildren.tagName.toLowerCase() == 'p' && !mainChildren.innerText.length + mainChildren.parentNode.removeChild(mainChildren) + + preList = mediumInstance.elements[0].querySelectorAll('pre') + + for pre in preList + # prevent edit a pre + pre.setAttribute('contenteditable', false) + + pre.setAttribute('title', $translate.instant("COMMON.WYSIWYG.DB_CLICK")) + + # prevent text selection in firefox + pre.addEventListener 'mousedown', (e) -> e.preventDefault() + + if pre.nextElementSibling && pre.nextElementSibling.nodeName.toLowerCase() == 'p' && !pre.nextElementSibling.children.length + pre.nextElementSibling.appendChild(document.createElement('br')) + + # add p after every pre + else if !pre.nextElementSibling || pre.nextElementSibling.nodeName.toLowerCase() != 'p' + p = document.createElement('p') + p.appendChild(document.createElement('br')) + + pre.parentNode.insertBefore(p, pre.nextSibling) + + mediumInstance.checkContentChanged(mediumInstance.elements[0]) + + AlignRightButton = MediumEditor.extensions.button.extend({ + name: 'rtl', + init: () -> + option = _.find this.base.options.toolbar.buttons, (it) -> + it.name == 'rtl' + + this.button = this.document.createElement('button') + this.button.classList.add('medium-editor-action') + this.button.innerHTML = option.contentDefault || 'RTL' + this.button.title = 'RTL' + this.on(this.button, 'click', this.handleClick.bind(this)) + + getButton: () -> + return this.button + handleClick: (event) -> + range = MediumEditor.selection.getSelectionRange(document) + if range.commonAncestorContainer.parentNode.style.textAlign == 'right' + document.execCommand('justifyLeft', false) + else + document.execCommand('justifyRight', false) + + }) + + getIcon = (icon) -> + return """ + + """ + + # MediumEditor extension to add + CodeButton = MediumEditor.extensions.button.extend({ + name: 'code', + init: () -> + option = _.find this.base.options.toolbar.buttons, (it) -> + it.name == 'code' + + this.button = this.document.createElement('button') + this.button.classList.add('medium-editor-action') + this.button.innerHTML = option.contentDefault || 'Code' + this.button.title = 'Code' + this.on(this.button, 'click', this.handleClick.bind(this)) + + getButton: () -> + return this.button + + tagNames: ['code'] + + handleClick: (event) -> + range = MediumEditor.selection.getSelectionRange(self.document) + + if isCodeBlockSelected(range, this.base) + removeCodeBlockAndHightlight(range.endContainer, this.base) + else + addCodeBlockAndHightlight(range, this.base) + removeSelections() + + toolbar = this.base.getExtensionByName('toolbar') + + if toolbar + toolbar.hideToolbar() + + }) + + CustomPasteHandler = MediumEditor.extensions.paste.extend({ + doPaste: (pastedHTML, pastedPlain, editable) -> + html = MediumEditor.util.htmlEntities(pastedPlain); + + MediumEditor.util.insertHTMLCommand(this.document, html); + }) + + # bug + #

the enter key press doesn't work + oldIsBlockContainer = MediumEditor.util.isBlockContainer + + MediumEditor.util.isBlockContainer = (element) -> + if !element + return oldIsBlockContainer(element) + + if element.tagName + tagName = element.tagName + else + tagName = element.parentNode.tagName + + if tagName.toLowerCase() == 'code' + return true + + return oldIsBlockContainer(element) + + link = ($scope, $el, $attrs) -> + mediumInstance = null + editorMedium = $el.find('.medium') + editorMarkdown = $el.find('.markdown') + codeBlockSelected = null + + isEditOnly = !!$attrs.$attr.editonly + notPersist = !!$attrs.$attr.notPersist + + $scope.required = !!$attrs.$attr.required + $scope.editMode = isEditOnly || false + $scope.mode = $storage.get('editor-mode', 'html') + $scope.markdown = '' + $scope.codeEditorVisible = false + $scope.codeLans = [] + + wysiwygService.loadEmojis() + + wysiwygCodeHightlighterService.getLanguages().then (codeLans) -> + $scope.codeLans = codeLans + + setEditMode = (editMode) -> + $scope.editMode = editMode + + setHtmlMedium = (markdown) -> + html = wysiwygService.getHTML(markdown) + editorMedium.html(html) + wysiwygCodeHightlighterService.addHightlighter(mediumInstance.elements[0]) + refreshCodeBlocks(mediumInstance) + + $scope.saveSnippet = (lan, code) -> + $scope.codeEditorVisible = false + codeBlockSelected.innerText = code + codePre = codeBlockSelected.parentNode + + if lan == 'remove-formating' + codeBlockSelected.className = '' + codePre.className = '' + + removeCodeBlockAndHightlight(codeBlockSelected, mediumInstance) + else if _.trim(code).length + if lan + codeBlockSelected.className = 'language-' + lan + codePre.className = 'language-' + lan + else + codeBlockSelected.className = '' + codePre.className = '' + + wysiwygCodeHightlighterService.hightlightCode(codeBlockSelected) + mediumInstance.checkContentChanged(mediumInstance.elements[0]) + else + codeBlockSelected.parentNode.parentNode.removeChild(codeBlockSelected.parentNode) + mediumInstance.checkContentChanged(mediumInstance.elements[0]) + + throttleChange() + + return null + + $scope.setMode = (mode) -> + $storage.set('editor-mode', mode) + + if mode == 'markdown' + updateMarkdownWithCurrentHtml() + else + setHtmlMedium($scope.markdown) + + $scope.mode = mode + mediumInstance.trigger('editableBlur', {}, editorMedium[0]) + + $scope.save = (e) -> + e.preventDefault() if e + + if $scope.mode == 'html' + updateMarkdownWithCurrentHtml() + + return if $scope.required && !$scope.markdown.length + + $scope.saving = true + $scope.outdated = false + + $scope.onSave({text: $scope.markdown, cb: saveEnd}) + + return + + $scope.cancel = (e) -> + e.preventDefault() if e + + if !isEditOnly + setEditMode(false) + + if notPersist + clean() + else if $scope.mode == 'html' + setHtmlMedium($scope.content || null) + + $scope.markdown = $scope.content + + discardLocalStorage() + mediumInstance.trigger('blur', {}, editorMedium[0]) + $scope.outdated = false + + $scope.onCancel() + + return + + clean = () -> + $scope.markdown = '' + editorMedium.html('') + + saveEnd = () -> + $scope.saving = false + + if !isEditOnly + setEditMode(false) + + if notPersist + clean() + + discardLocalStorage() + mediumInstance.trigger('blur', {}, editorMedium[0]) + + analytics.trackEvent('develop', 'save wysiwyg', $scope.mode, 1) + + uploadEnd = (name, url) -> + if taiga.isImage(name) + mediumInstance.pasteHTML("
") + else + name = $('
').text(name).html() + mediumInstance.pasteHTML("" + name + "
") + + isOutdated = () -> + store = $storage.get($scope.storageKey) + + if store && store.version && store.version != $scope.version + return true + + return false + + isDraft = () -> + store = $storage.get($scope.storageKey) + + if store + return true + + return false + + getCurrentContent = () -> + store = $storage.get($scope.storageKey) + + if store + return store.text + + return $scope.content + + discardLocalStorage = () -> + $storage.remove($scope.storageKey) + + cancelWithConfirmation = () -> + if $scope.content == $scope.markdown + $scope.cancel() + + document.activeElement.blur() + document.body.click() + + return null + + title = $translate.instant("COMMON.CONFIRM_CLOSE_EDIT_MODE_TITLE") + message = $translate.instant("COMMON.CONFIRM_CLOSE_EDIT_MODE_MESSAGE") + + $confirm.ask(title, null, message).then (askResponse) -> + $scope.cancel() + askResponse.finish() + + # firefox adds br instead of new lines inside , taiga must replace the br by \n before sending to the server + replaceCodeBrToNl = () -> + html = $('
').html(editorMedium.html()) + html.find('code br').replaceWith('\n') + + return html.html() + + updateMarkdownWithCurrentHtml = () -> + html = replaceCodeBrToNl() + $scope.markdown = wysiwygService.getMarkdown(html) + + localSave = (markdown) -> + if $scope.storageKey + store = {} + store.version = $scope.version || 0 + store.text = markdown + $storage.set($scope.storageKey, store) + + change = () -> + if $scope.mode == 'html' + updateMarkdownWithCurrentHtml() + + localSave($scope.markdown) + + $scope.onChange({markdown: $scope.markdown}) + + throttleChange = _.throttle(change, 200) + + create = (text, editMode=false) -> + if text.length + html = wysiwygService.getHTML(text) + editorMedium.html(html) + + mediumInstance = new MediumEditor(editorMedium[0], { + targetBlank: true, + imageDragging: false, + placeholder: { + text: $scope.placeholder + }, + toolbar: { + buttons: [ + { + name: 'bold', + contentDefault: getIcon('editor-bold') + }, + { + name: 'italic', + contentDefault: getIcon('editor-italic') + }, + { + name: 'strikethrough', + contentDefault: getIcon('editor-cross-out') + }, + { + name: 'anchor', + contentDefault: getIcon('editor-link') + }, + { + name: 'image', + contentDefault: getIcon('editor-image') + }, + { + name: 'orderedlist', + contentDefault: getIcon('editor-list-n') + }, + { + name: 'unorderedlist', + contentDefault: getIcon('editor-list-o') + }, + { + name: 'h1', + contentDefault: getIcon('editor-h1') + }, + { + name: 'h2', + contentDefault: getIcon('editor-h2') + }, + { + name: 'h3', + contentDefault: getIcon('editor-h3') + }, + { + name: 'quote', + contentDefault: getIcon('editor-quote') + }, + { + name: 'removeFormat', + contentDefault: getIcon('editor-no-format') + }, + { + name: 'rtl', + contentDefault: getIcon('editor-rtl') + }, + { + name: 'code', + contentDefault: getIcon('editor-code') + } + ] + }, + extensions: { + paste: new CustomPasteHandler(), + code: new CodeButton(), + autolist: new AutoList(), + alignright: new AlignRightButton(), + mediumMention: new MentionExtension({ + getItems: (mention, mentionCb) -> + wysiwygMentionService.search(mention).then(mentionCb) + }) + } + }) + + $scope.changeMarkdown = throttleChange + + mediumInstance.subscribe 'editableInput', (e) -> + $scope.$applyAsync(throttleChange) + + mediumInstance.subscribe "editableClick", (e) -> + e.stopPropagation() + + if e.target.href + window.open(e.target.href) + + mediumInstance.subscribe 'focus', (event) -> + $scope.$applyAsync () -> + if !$scope.editMode + setEditMode(true) + + mediumInstance.subscribe 'editableDrop', (event) -> + $scope.onUploadFile({files: event.dataTransfer.files, cb: uploadEnd}) + + mediumInstance.subscribe 'editableKeydown', (e) -> + code = if e.keyCode then e.keyCode else e.which + + mention = $('.medium-mention') + + if (code == 40 || code == 38) && mention.length + e.stopPropagation() + e.preventDefault() + + return + + if $scope.editMode && code == 27 + e.stopPropagation() + $scope.$applyAsync(cancelWithConfirmation) + else if code == 27 + editorMedium.blur() + + setEditMode(editMode) + + $scope.$applyAsync () -> + wysiwygCodeHightlighterService.addHightlighter(mediumInstance.elements[0]) + refreshCodeBlocks(mediumInstance) + + $(editorMedium[0]).on 'dblclick', 'pre', (e) -> + $scope.$applyAsync () -> + $scope.codeEditorVisible = true + + codeBlockSelected = e.currentTarget.querySelector('code') + + $scope.currentCodeLanguage = wysiwygCodeHightlighterService.getLanguageInClassList(codeBlockSelected.classList) + $scope.code = codeBlockSelected.innerText + + unwatch = $scope.$watch 'content', (content) -> + if !_.isUndefined(content) + $scope.outdated = isOutdated() + + if !mediumInstance && isDraft() + setEditMode(true) + + if ($scope.markdown.length || content.length) && $scope.markdown == content + return + + content = getCurrentContent() + + $scope.markdown = content + + if mediumInstance + mediumInstance.destroy() + + if tgLoader.open() + unwatchLoader = tgLoader.onEnd () -> + create(content, $scope.editMode) + unwatchLoader() + else + create(content, $scope.editMode) + + unwatch() + + $scope.$on "$destroy", () -> + if mediumInstance + mediumInstance.destroy() + + return { + templateUrl: "common/components/wysiwyg-toolbar.html", + scope: { + placeholder: '@', + version: '<', + storageKey: '<', + content: '<', + onCancel: '&', + onSave: '&', + onUploadFile: '&', + onChange: '&' + }, + link: link + } + +angular.module("taigaComponents").directive("tgWysiwyg", [ + "$translate", + "$tgConfirm", + "$tgStorage", + "tgWysiwygService", + "animationFrame", + "tgLoader", + "tgWysiwygCodeHightlighterService", + "tgWysiwygMentionService", + "$tgAnalytics", + Medium +]) diff --git a/app/styles/components/wysiwyg.scss b/app/modules/components/wysiwyg/wysiwyg.scss similarity index 50% rename from app/styles/components/wysiwyg.scss rename to app/modules/components/wysiwyg/wysiwyg.scss index dbf1220d..ef9d90ea 100644 --- a/app/styles/components/wysiwyg.scss +++ b/app/modules/components/wysiwyg/wysiwyg.scss @@ -1,6 +1,5 @@ .wysiwyg { line-height: 1.4rem; - margin-bottom: 2rem; overflow: auto; padding: 1rem; h1 { @@ -37,7 +36,7 @@ ol { line-height: 1.5; list-style-position: outside; - margin-bottom: 0; + margin-bottom: 1rem; margin-top: 0; padding-left: 2em; ul, @@ -48,6 +47,15 @@ ul { list-style-type: disc; } + .list-stye-none { + list-style: none; + } + b { + font-weight: bold; + } + i { + font-style: italic; + } dl { dt { font-size: 1em; @@ -63,6 +71,7 @@ } a { color: $primary; + cursor: pointer; &:hover { color: $primary-light; } @@ -79,22 +88,18 @@ margin: 0; } } - pre, - code { + pre:not([class*="language-"]) { @include font-size(small); - background: lighten($grayer, 10%); + background: $code-bg; color: $whitish; direction: ltr; font-family: 'courier new', 'monospace'; - margin-bottom: 1rem; + line-height: 1.4rem; + margin-bottom: .5rem; overflow: auto; + padding: 1rem; unicode-bidi: embed; white-space: pre-wrap; - - } - pre { - line-height: 1.4rem; - padding: 1rem; } table { border: $gray-light 1px solid; @@ -134,3 +139,128 @@ border: 1px solid $whitish; } } + +.medium-editor-mention-panel { + background-color: $white; + border: 1px solid $gray-light; + position: absolute; + ul { + margin-bottom: 0; + } + li { + border-top: 1px solid $gray-light; + cursor: pointer; + padding: 2px 5px; + &:first-child { + border-top: 0; + } + &:hover, + &.active { + background-color: $primary-dark; + color: $white; + } + } +} + +tg-wysiwyg { + display: flex; + margin-bottom: 2rem; + div[contenteditable="true"] *:last-child { + margin-bottom: 0; + } + pre { + cursor: pointer; + } + .outdated { + color: $red; + } + .tools { + padding-left: 1rem; + a { + display: block; + margin-bottom: .5rem; + } + svg { + fill: $gray-light; + } + } + .editor { + width: 100%; + } + .mode-editor { + span { + color: $gray-light; + cursor: pointer; + margin-right: .5rem; + } + } + .medium-editor-placeholder, + .markdown-editor-placeholder { + color: $gray-light; + overflow: visible; + padding-left: 1rem; + &::after { // overwrite medium css + color: $gray-light; + font-style: normal; + } + } + .markdown:not(.empty) { + p { + margin-bottom: 0; + white-space: pre-wrap; + } + } + .read-mode { + cursor: pointer; + } + .edit-mode { + .markdown, + .medium { + border: 1px solid $gray-light; + } + .medium-editor-element { + min-height: 10rem; + } + } + .mention { + font-weight: bold; + } +} + +.code-language-selector { + @include font-size(xsmall); + background-color: $white; + border: 1px solid $gray-light; + cursor: pointer; + padding: .2rem .5rem 0; + position: absolute; +} + +.code-language-search { + @include font-size(xsmall); + background-color: $white; + border: 1px solid $gray-light; + position: absolute; + ul { + cursor: pointer; + margin-bottom: 0; + max-height: 20vh; + overflow-y: scroll; + } + li { + padding: .2rem .5rem; + } +} + +// Override medium styles +.medium-editor-toolbar { + li .medium-editor-button-active { + color: $primary-light; + } + svg { + fill: $white; + } + button:hover svg { + fill: $primary-light; + } +} diff --git a/app/modules/components/wysiwyg/wysiwyg.service.coffee b/app/modules/components/wysiwyg/wysiwyg.service.coffee new file mode 100644 index 00000000..67236ffa --- /dev/null +++ b/app/modules/components/wysiwyg/wysiwyg.service.coffee @@ -0,0 +1,121 @@ +### +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: modules/components/wysiwyg/wysiwyg.service.coffee +### + +class WysiwygService + constructor: (@wysiwygCodeHightlighterService) -> + + searchEmojiByName: (name) -> + return _.filter @.emojis, (it) -> it.name.indexOf(name) != -1 + + setEmojiImagePath: (emojis) -> + @.emojis = _.map emojis, (it) -> + it.image = "/#{window._version}/emojis/" + it.image + + return it + + loadEmojis: () -> + $.getJSON("/#{window._version}/emojis/emojis-data.json").then(@.setEmojiImagePath.bind(this)) + + getEmojiById: (id) -> + return _.find @.emojis, (it) -> it.id == id + + getEmojiByName: (name) -> + return _.find @.emojis, (it) -> it.name == name + + replaceImgsByEmojiName: (html) -> + emojiIds = taiga.getMatches(html, /emojis\/([^"]+).png"/gi) + + for emojiId in emojiIds + regexImgs = new RegExp(']+\>', 'g') + emoji = @.getEmojiById(emojiId) + html = html.replace(regexImgs, ':' + emoji.name + ':') + + return html + + replaceEmojiNameByImgs: (text) -> + emojiIds = taiga.getMatches(text, /:([\w ]*):/g) + + for emojiId in emojiIds + regexImgs = new RegExp(':' + emojiId + ':', 'g') + emoji = @.getEmojiByName(emojiId) + + if emoji + text = text.replace(regexImgs, '![alt](' + emoji.image + ')') + + return text + + removeTrailingListBr: (text) -> + return text.replace(/
  • (.*?)
    <\/li>/g, '
  • $1
  • ') + + getMarkdown: (html) -> + # https://github.com/yabwe/medium-editor/issues/543 + cleanIssueConverter = { + filter: ['html', 'body', 'span', 'div'], + replacement: (innerHTML) -> + return innerHTML + } + + codeLanguageConverter = { + filter: (node) => + return node.nodeName == 'PRE' && + node.firstChild && + node.firstChild.nodeName == 'CODE' + replacement: (content, node) => + lan = @wysiwygCodeHightlighterService.getLanguageInClassList(node.firstChild.classList) + lan = '' if !lan + + return '\n\n```' + lan + '\n' + _.trim(node.firstChild.textContent) + '\n```\n\n' + } + + html = html.replace(/ (<\/.*>)/g, "$1") + html = @.replaceImgsByEmojiName(html) + html = @.removeTrailingListBr(html) + + markdown = toMarkdown(html, { + gfm: true, + converters: [cleanIssueConverter, codeLanguageConverter] + }) + + + return markdown + + getHTML: (text) -> + return "" if !text || !text.length + + options = { + breaks: true + } + + text = @.replaceEmojiNameByImgs(text) + + md = window.markdownit({ + breaks: true + }) + + result = md.render(text) + + return result + +angular.module("taigaComponents") + .service("tgWysiwygService", ["tgWysiwygCodeHightlighterService", WysiwygService]) diff --git a/app/modules/discover/components/highlighted/highlighted.scss b/app/modules/discover/components/highlighted/highlighted.scss index 0c9b0a0e..ff18ab43 100644 --- a/app/modules/discover/components/highlighted/highlighted.scss +++ b/app/modules/discover/components/highlighted/highlighted.scss @@ -76,6 +76,7 @@ } .empty-highlighted-project { border: 2px dashed $whitish; + flex: 1; padding: 2rem; text-align: center; svg { diff --git a/app/modules/discover/discover-search/discover-search.directive.coffee b/app/modules/discover/discover-search/discover-search.directive.coffee index 5f66cbea..c8615731 100644 --- a/app/modules/discover/discover-search/discover-search.directive.coffee +++ b/app/modules/discover/discover-search/discover-search.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/epics/create-epic/create-epic.directive.coffee b/app/modules/epics/create-epic/create-epic.directive.coffee index fda1525d..fccbf221 100644 --- a/app/modules/epics/create-epic/create-epic.directive.coffee +++ b/app/modules/epics/create-epic/create-epic.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/epics/dashboard/epic-row/epic-row.directive.coffee b/app/modules/epics/dashboard/epic-row/epic-row.directive.coffee index cf85a32b..ce59c339 100644 --- a/app/modules/epics/dashboard/epic-row/epic-row.directive.coffee +++ b/app/modules/epics/dashboard/epic-row/epic-row.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/epics/dashboard/epics-sortable/epics-sortable.directive.coffee b/app/modules/epics/dashboard/epics-sortable/epics-sortable.directive.coffee index 53063281..cfa85644 100644 --- a/app/modules/epics/dashboard/epics-sortable/epics-sortable.directive.coffee +++ b/app/modules/epics/dashboard/epics-sortable/epics-sortable.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/epics/dashboard/epics-table/epics-table.controller.coffee b/app/modules/epics/dashboard/epics-table/epics-table.controller.coffee index ea993e71..e2cd5cec 100644 --- a/app/modules/epics/dashboard/epics-table/epics-table.controller.coffee +++ b/app/modules/epics/dashboard/epics-table/epics-table.controller.coffee @@ -51,6 +51,9 @@ class EpicsTableController @.displayOptions = !@.displayOptions reorderEpic: (epic, newIndex) -> + if epic.get('epics_order') == newIndex + return null + @epicsService.reorderEpic(epic, newIndex) .then null, () => # on error @confirm.notify("error") diff --git a/app/modules/epics/dashboard/epics-table/epics-table.directive.coffee b/app/modules/epics/dashboard/epics-table/epics-table.directive.coffee index f072a3e4..65fb8b36 100644 --- a/app/modules/epics/dashboard/epics-table/epics-table.directive.coffee +++ b/app/modules/epics/dashboard/epics-table/epics-table.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/epics/dashboard/story-row/story-row.directive.coffee b/app/modules/epics/dashboard/story-row/story-row.directive.coffee index 13195c0a..32ca8908 100644 --- a/app/modules/epics/dashboard/story-row/story-row.directive.coffee +++ b/app/modules/epics/dashboard/story-row/story-row.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/epics/epics.service.coffee b/app/modules/epics/epics.service.coffee index cb611601..6c8c521c 100644 --- a/app/modules/epics/epics.service.coffee +++ b/app/modules/epics/epics.service.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -75,24 +75,42 @@ class EpicsService Promise.all(promises).then(@.fetchEpics.bind(this, true)) reorderEpic: (epic, newIndex) -> + orderList = {} + @._epics.forEach (it) -> + orderList[it.get('id')] = it.get('epics_order') + withoutMoved = @.epics.filter (it) => it.get('id') != epic.get('id') beforeDestination = withoutMoved.slice(0, newIndex) + afterDestination = withoutMoved.slice(newIndex) previous = beforeDestination.last() newOrder = if !previous then 0 else previous.get('epics_order') + 1 + orderList[epic.get('id')] = newOrder + previousWithTheSameOrder = beforeDestination.filter (it) => it.get('epics_order') == previous.get('epics_order') + setOrders = _.fromPairs previousWithTheSameOrder.map((it) => [it.get('id'), it.get('epics_order')] ).toJS() + afterDestination.forEach (it) -> orderList[it.get('id')] = it.get('epics_order') + 1 + + @._epics = @._epics.map (it) -> it.set('epics_order', orderList[it.get('id')]) + @._epics = @._epics.sortBy (it) -> it.get('epics_order') + data = { epics_order: newOrder, version: epic.get('version') } - return @resources.epics.reorder(epic.get('id'), data, setOrders) + return @resources.epics.reorder(epic.get('id'), data, setOrders).then (newEpic) => + @._epics = @._epics.map (it) -> + if it.get('id') == newEpic.get('id') + return newEpic + + return it reorderRelatedUserstory: (epic, epicUserstories, userstory, newIndex) -> withoutMoved = epicUserstories.filter (it) => it.get('id') != userstory.get('id') @@ -120,7 +138,7 @@ class EpicsService @._epics = @._epics.map (it) -> if it.get('id') == epic.get('id') return epic - + return it updateEpicStatus: (epic, statusId) -> diff --git a/app/modules/epics/epics.service.spec.coffee b/app/modules/epics/epics.service.spec.coffee index a173ca10..0046aab8 100644 --- a/app/modules/epics/epics.service.spec.coffee +++ b/app/modules/epics/epics.service.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -251,7 +251,11 @@ describe "tgEpicsService", -> mocks.tgResources.epics.reorder .withArgs(3, {epics_order: 2, version: 1}, {1: 1}) .promise() - .resolve() + .resolve(Immutable.fromJS({ + id: 3 + epics_order: 3 + version: 2 + })) epicsService.reorderEpic(epicsService._epics.get(2), 1) diff --git a/app/modules/epics/related-userstories/related-userstories-create/related-userstories-create.directive.coffee b/app/modules/epics/related-userstories/related-userstories-create/related-userstories-create.directive.coffee index 9ecd4a03..5cd7156d 100644 --- a/app/modules/epics/related-userstories/related-userstories-create/related-userstories-create.directive.coffee +++ b/app/modules/epics/related-userstories/related-userstories-create/related-userstories-create.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/epics/related-userstories/related-userstories-sortable/related-userstories-sortable.directive.coffee b/app/modules/epics/related-userstories/related-userstories-sortable/related-userstories-sortable.directive.coffee index 1989e7d5..9dc4118e 100644 --- a/app/modules/epics/related-userstories/related-userstories-sortable/related-userstories-sortable.directive.coffee +++ b/app/modules/epics/related-userstories/related-userstories-sortable/related-userstories-sortable.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/epics/related-userstories/related-userstories.directive.coffee b/app/modules/epics/related-userstories/related-userstories.directive.coffee index e3db9be8..fdcf1fe4 100644 --- a/app/modules/epics/related-userstories/related-userstories.directive.coffee +++ b/app/modules/epics/related-userstories/related-userstories.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/epics/related-userstories/related-userstory-row/related-userstory-row.directive.coffee b/app/modules/epics/related-userstories/related-userstory-row/related-userstory-row.directive.coffee index 02ea4ebd..505cc4b3 100644 --- a/app/modules/epics/related-userstories/related-userstory-row/related-userstory-row.directive.coffee +++ b/app/modules/epics/related-userstories/related-userstory-row/related-userstory-row.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/external-apps/external-app.controller.coffee b/app/modules/external-apps/external-app.controller.coffee index 0e726a87..1f1135c5 100644 --- a/app/modules/external-apps/external-app.controller.coffee +++ b/app/modules/external-apps/external-app.controller.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/external-apps/external-app.controller.spec.coffee b/app/modules/external-apps/external-app.controller.spec.coffee index e19c5b89..c698de7b 100644 --- a/app/modules/external-apps/external-app.controller.spec.coffee +++ b/app/modules/external-apps/external-app.controller.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/external-apps/external-app.service.coffee b/app/modules/external-apps/external-app.service.coffee index 679ddc75..9476df64 100644 --- a/app/modules/external-apps/external-app.service.coffee +++ b/app/modules/external-apps/external-app.service.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/external-apps/external-app.service.spec.coffee b/app/modules/external-apps/external-app.service.spec.coffee index 0adf305e..7bdc32ff 100644 --- a/app/modules/external-apps/external-app.service.spec.coffee +++ b/app/modules/external-apps/external-app.service.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/external-apps/external-apps.module.coffee b/app/modules/external-apps/external-apps.module.coffee index a24bf0ce..c89a0050 100644 --- a/app/modules/external-apps/external-apps.module.coffee +++ b/app/modules/external-apps/external-apps.module.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/feedback/feedback.service.coffee b/app/modules/feedback/feedback.service.coffee index b32a2a0e..f52ebb3a 100644 --- a/app/modules/feedback/feedback.service.coffee +++ b/app/modules/feedback/feedback.service.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/feedback/feedback.service.spec.coffee b/app/modules/feedback/feedback.service.spec.coffee index 488bdf7b..eca892a0 100644 --- a/app/modules/feedback/feedback.service.spec.coffee +++ b/app/modules/feedback/feedback.service.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/history/comments/comment.controller.coffee b/app/modules/history/comments/comment.controller.coffee index 531480ef..468b700a 100644 --- a/app/modules/history/comments/comment.controller.coffee +++ b/app/modules/history/comments/comment.controller.coffee @@ -28,7 +28,6 @@ class CommentController constructor: (@currentUserService, @permissionService, @lightboxFactory) -> @.hiddenDeletedComment = true - @.commentContent = angular.copy(@.comment) showDeletedComment: () -> @.hiddenDeletedComment = false @@ -45,6 +44,9 @@ class CommentController @.user = @currentUserService.getUser() return @.user.get('id') == @.comment.user.pk || @permissionService.check('modify_project') + saveComment: (text, cb) -> + @.onEditComment({commentId: @.comment.id, commentData: text, callback: cb}) + displayCommentHistory: () -> @lightboxFactory.create('tg-lb-display-historic', { "class": "lightbox lightbox-display-historic" diff --git a/app/modules/history/comments/comment.directive.coffee b/app/modules/history/comments/comment.directive.coffee index 0d001c7d..073cbe58 100644 --- a/app/modules/history/comments/comment.directive.coffee +++ b/app/modules/history/comments/comment.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/history/comments/comment.jade b/app/modules/history/comments/comment.jade index 447b8bfd..a73549d5 100644 --- a/app/modules/history/comments/comment.jade +++ b/app/modules/history/comments/comment.jade @@ -1,5 +1,3 @@ -include ../../../partials/common/components/wysiwyg.jade - .comment-wrapper(ng-if="!vm.comment.delete_comment_date") img.comment-avatar( tg-avatar="vm.comment.user" @@ -23,38 +21,21 @@ include ../../../partials/common/components/wysiwyg.jade .comment-container .comment-text.wysiwyg( ng-if="!vm.editMode" - ng-bind-html="vm.comment.comment_html" + tg-bind-code="vm.comment.comment" ) .comment-editor( ng-if="vm.editMode" ng-keyup="vm.checkCancelComment($event)" ) - .edit-comment(ng-model="vm.type") - textarea( - ng-model="vm.commentContent.comment" - ) - .save-comment-wrapper - button.button-green.save-comment( - type="button" - title="{{'COMMENTS.EDIT_COMMENT' | translate}}" - translate="COMMENTS.EDIT_COMMENT" - ng-disabled="!vm.commentContent.comment.length || vm.editing == vm.comment.id" - ng-click="vm.onEditComment({commentId: vm.comment.id, commentData: vm.commentContent.comment})" - tg-loading="vm.editing == vm.comment.id" - ) - .comment-options(ng-if="::vm.canEditDeleteComment()") + tg-comment-edit-wysiwyg.edit-comment + + .comment-options(ng-if="vm.canEditDeleteComment() && !vm.editMode") tg-svg.comment-option( svg-icon="icon-edit" svg-title-translate="COMMON.EDIT" ng-click="vm.onEditMode({commentId: vm.comment.id})" ng-if="!vm.editMode" ) - tg-svg.comment-option( - svg-icon="icon-close" - svg-title-translate="COMMON.CANCEL" - ng-click="vm.onEditMode({commentId: vm.comment.id})" - ng-if="vm.editMode" - ) tg-svg.comment-option( svg-icon="icon-trash" svg-title-translate="COMMON.DELETE" @@ -107,5 +88,5 @@ include ../../../partials/common/components/wysiwyg.jade span(translate="COMMENTS.RESTORE") p.deleted-comment-comment( ng-if="!vm.hiddenDeletedComment" - ng-bind-html="vm.comment.comment_html" + tg-bind-code="vm.comment.comment" ) diff --git a/app/modules/history/comments/comment.scss b/app/modules/history/comments/comment.scss index 5aef9e53..d3186c2f 100644 --- a/app/modules/history/comments/comment.scss +++ b/app/modules/history/comments/comment.scss @@ -1,5 +1,16 @@ .comments { clear: both; + tg-wysiwyg { + margin-top: 1.5rem; + } + .read-mode { + border: 1px solid $gray-light; + height: 55px; + .medium-editor-placeholder, + .markdown-editor-placeholder { + height: 55px; + } + } .add-comment { margin-top: 1rem; textarea { @@ -20,7 +31,6 @@ margin-top: 1rem; padding: .5rem 4rem; } - } .comment { display: block; @@ -143,15 +153,10 @@ .deleted-comment-comment { margin-top: 1rem; } - .comment-editor { - textarea { - height: 5rem; - min-height: 5rem; - } - } } .comment-text { + max-width: 80rem; &.wysiwyg { margin-bottom: 0; padding: 0; diff --git a/app/modules/history/comments/comments.directive.coffee b/app/modules/history/comments/comments.directive.coffee index 67d04bd2..68dd40ca 100644 --- a/app/modules/history/comments/comments.directive.coffee +++ b/app/modules/history/comments/comments.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/history/comments/comments.jade b/app/modules/history/comments/comments.jade index 249863eb..09a27fcd 100644 --- a/app/modules/history/comments/comments.jade +++ b/app/modules/history/comments/comments.jade @@ -1,5 +1,3 @@ -include ../../../partials/common/components/wysiwyg.jade - section.comments .comments-wrapper tg-comment.comment( @@ -15,25 +13,11 @@ section.comments on-edit-mode="vm.onEditMode({commentId: commentId})" on-delete-comment="vm.onDeleteComment({commentId: commentId})" on-restore-deleted-comment="vm.onRestoreDeletedComment({commentId: commentId})" - on-edit-comment="vm.onEditComment({commentId: commentId, commentData: commentData})" + on-edit-comment="vm.onEditComment({commentId: commentId, commentData: commentData, callback: callback})" ) - tg-editable-wysiwyg.add-comment( - ng-model="vm.type" + + tg-comment-wysiwyg( tg-check-permission="{{::vm.canAddCommentPermission}}" - tg-toggle-comment + on-update="updateComment(text)" + type="vm.type" ) - textarea( - ng-attr-placeholder="{{'COMMENTS.TYPE_NEW_COMMENT' | translate}}" - tg-markitup="tg-markitup" - ng-model="vm.type.comment" - ) - +wysihelp - .save-comment-wrapper - button.button-green.save-comment( - type="button" - title="{{'COMMENTS.COMMENT' | translate}}" - translate="COMMENTS.COMMENT" - ng-disabled="!vm.type.comment.length || vm.loading" - ng-click="vm.onAddComment()" - tg-loading="vm.loading" - ) diff --git a/app/modules/history/history-lightbox/comment-history-lightbox.directive.coffee b/app/modules/history/history-lightbox/comment-history-lightbox.directive.coffee index 3fa4b966..2bcd1e4b 100644 --- a/app/modules/history/history-lightbox/comment-history-lightbox.directive.coffee +++ b/app/modules/history/history-lightbox/comment-history-lightbox.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/history/history-lightbox/history-entry.directive.coffee b/app/modules/history/history-lightbox/history-entry.directive.coffee index f6c573ce..3799ab9f 100644 --- a/app/modules/history/history-lightbox/history-entry.directive.coffee +++ b/app/modules/history/history-lightbox/history-entry.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/history/history-lightbox/history-entry.jade b/app/modules/history/history-lightbox/history-entry.jade index b3c5ca4a..80b7b3e8 100644 --- a/app/modules/history/history-lightbox/history-entry.jade +++ b/app/modules/history/history-lightbox/history-entry.jade @@ -15,5 +15,5 @@ ) .entry-text( ng-class="{'ellipsed': !displayFullEntry && entry.comment.length >= 75, 'blurry': entry.comment.length >= 75 && !displayFullEntry}" - ng-bind-html="entry.comment_html" + ng-bind-html="entry.comment | markdownToHTML" ) diff --git a/app/modules/history/history-tabs/history-tabs.directive.coffee b/app/modules/history/history-tabs/history-tabs.directive.coffee index e7e48e74..545ecf19 100644 --- a/app/modules/history/history-tabs/history-tabs.directive.coffee +++ b/app/modules/history/history-tabs/history-tabs.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/history/history-tabs/history-tabs.jade b/app/modules/history/history-tabs/history-tabs.jade index d9e25e30..74022b39 100644 --- a/app/modules/history/history-tabs/history-tabs.jade +++ b/app/modules/history/history-tabs/history-tabs.jade @@ -27,17 +27,17 @@ nav.history-tabs span( translate="COMMENTS.OLDER_FIRST" - ng-if="onReverse" - ) - tg-svg( - svg-icon="icon-arrow-down" - ng-if="onReverse" - ) - span( - translate="COMMENTS.RECENT_FIRST" ng-if="!onReverse" ) tg-svg( svg-icon="icon-arrow-up" ng-if="!onReverse" ) + span( + translate="COMMENTS.RECENT_FIRST" + ng-if="onReverse" + ) + tg-svg( + svg-icon="icon-arrow-up" + ng-if="onReverse" + ) diff --git a/app/modules/history/history.controller.coffee b/app/modules/history/history.controller.coffee index d80a5ec0..492975bf 100644 --- a/app/modules/history/history.controller.coffee +++ b/app/modules/history/history.controller.coffee @@ -32,8 +32,8 @@ class HistorySectionController @.deleting = null @.editMode = {} @.viewComments = true - @._loadHistory() @.reverse = @storage.get("orderComments") + @._loadHistory() _loadHistory: () -> @rs.history.get(@.name, @.id).then (history) => @@ -72,7 +72,7 @@ class HistorySectionController @.deleting = commentId return @rs.history.deleteComment(type, objectId, activityId).then => @._loadHistory() - @.deleting = commentId + @.deleting = null editComment: (commentId, comment) -> type = @.name @@ -93,12 +93,10 @@ class HistorySectionController @._loadHistory() @.editing = null - addComment: () -> - type = @.type - @.loading = true + addComment: (cb) -> @repo.save(@.type).then => @._loadHistory() - @.loading = false + cb() onOrderComments: () -> @.reverse = !@.reverse diff --git a/app/modules/history/history.controller.spec.coffee b/app/modules/history/history.controller.spec.coffee index 2a97b2ca..69b70db5 100644 --- a/app/modules/history/history.controller.spec.coffee +++ b/app/modules/history/history.controller.spec.coffee @@ -149,12 +149,16 @@ describe "HistorySection", -> objectId = historyCtrl.id commentId = 7 - promise = mocks.tgResources.history.deleteComment.withArgs(type, objectId, commentId).promise().resolve() + deleteCommentPromise = mocks.tgResources.history.deleteComment.withArgs(type, objectId, commentId).promise() - historyCtrl.deleting = true - historyCtrl.deleteComment(commentId).then () -> + ctrlPromise = historyCtrl.deleteComment(commentId) + expect(historyCtrl.deleting).to.be.equal(7) + + deleteCommentPromise.resolve() + + ctrlPromise.then () -> expect(historyCtrl._loadHistory).have.been.called - expect(historyCtrl.deleting).to.be.equal(7) + expect(historyCtrl.deleting).to.be.null it "edit comment", () -> historyCtrl = controller "HistorySection" @@ -201,13 +205,15 @@ describe "HistorySection", -> historyCtrl.type = "type" type = historyCtrl.type - historyCtrl.loading = true + + cb = sinon.spy() promise = mocks.tgRepo.save.withArgs(type).promise().resolve() - historyCtrl.addComment().then () -> + historyCtrl.addComment(cb).then () -> expect(historyCtrl._loadHistory).has.been.called - expect(historyCtrl.loading).to.be.false + expect(cb).to.have.been.called + it "order comments", () -> historyCtrl = controller "HistorySection" diff --git a/app/modules/history/history.directive.coffee b/app/modules/history/history.directive.coffee index eebaf063..c0170525 100644 --- a/app/modules/history/history.directive.coffee +++ b/app/modules/history/history.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/history/history.jade b/app/modules/history/history.jade index eaa9af8d..12ef2b08 100644 --- a/app/modules/history/history.jade +++ b/app/modules/history/history.jade @@ -18,8 +18,8 @@ section.history( on-delete-comment="vm.deleteComment(commentId)" on-restore-deleted-comment="vm.restoreDeletedComment(commentId)" on-edit-mode="vm.toggleEditMode(commentId)" - on-add-comment="vm.addComment()" - on-edit-comment="vm.editComment(commentId, commentData)" + on-add-comment="vm.addComment(callback)" + on-edit-comment="vm.editComment(commentId, commentData, callback)" edit-mode="vm.editMode" object="{{vm.id}}" diff --git a/app/modules/history/history.module.coffee b/app/modules/history/history.module.coffee index 6089087a..194f3c48 100644 --- a/app/modules/history/history.module.coffee +++ b/app/modules/history/history.module.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/history/history/history-diff.directive.coffee b/app/modules/history/history/history-diff.directive.coffee index 481c27ec..dfa06f74 100644 --- a/app/modules/history/history/history-diff.directive.coffee +++ b/app/modules/history/history/history-diff.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/history/history/history-templates/history-custom-attributes.jade b/app/modules/history/history/history-templates/history-custom-attributes.jade index 69d6a1bf..d8ba2873 100644 --- a/app/modules/history/history/history-templates/history-custom-attributes.jade +++ b/app/modules/history/history/history-templates/history-custom-attributes.jade @@ -1,19 +1,29 @@ -.diff-custom-new( +.diff-status-wrapper( ng-if="vm.diff.new.length" ng-repeat="newCustom in vm.diff.new" ) span.key(translate="ACTIVITY.CREATED_CUSTOM_ATTRIBUTE") span.diff ({{newCustom.name}}) - span.diff {{newCustom.value}} - -.diff-custom-new( + + span(ng-if="newCustom.type == 'richtext'") + p.diff(tg-bo-html="newCustom.value_diff") + + span(ng-if="newCustom.type != 'richtext'") + span.diff {{newCustom.value}} + +.diff-status-wrapper( ng-if="vm.diff.changed.length" ng-repeat="changeCustom in vm.diff.changed" ) span.key(translate="ACTIVITY.UPDATED_CUSTOM_ATTRIBUTE") span.diff ({{changeCustom.name}}) - span.diff {{changeCustom.changes.value[0]}} - tg-svg( - svg-icon="icon-arrow-right" - ) - span.diff {{changeCustom.changes.value[1]}} + + span(ng-if="changeCustom.type == 'richtext'") + p.diff(tg-bo-html="changeCustom.value_diff") + + span(ng-if="changeCustom.type != 'richtext'") + span.diff {{changeCustom.changes.value[0]}} + tg-svg( + svg-icon="icon-arrow-right" + ) + span.diff {{changeCustom.changes.value[1]}} diff --git a/app/modules/history/history/history.directive.coffee b/app/modules/history/history/history.directive.coffee index 40862178..1ea979d9 100644 --- a/app/modules/history/history/history.directive.coffee +++ b/app/modules/history/history/history.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/home/duties/duty.directive.coffee b/app/modules/home/duties/duty.directive.coffee index e4f40268..4ca2cb65 100644 --- a/app/modules/home/duties/duty.directive.coffee +++ b/app/modules/home/duties/duty.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/home/duties/duty.directive.spec.coffee b/app/modules/home/duties/duty.directive.spec.coffee index ff797881..9ca24ded 100644 --- a/app/modules/home/duties/duty.directive.spec.coffee +++ b/app/modules/home/duties/duty.directive.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/home/home.module.coffee b/app/modules/home/home.module.coffee index a5152998..7c0d18f1 100644 --- a/app/modules/home/home.module.coffee +++ b/app/modules/home/home.module.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/home/home.service.coffee b/app/modules/home/home.service.coffee index f6a9e69b..06a9e89f 100644 --- a/app/modules/home/home.service.coffee +++ b/app/modules/home/home.service.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/home/home.service.spec.coffee b/app/modules/home/home.service.spec.coffee index 30f605b3..c1fb818d 100644 --- a/app/modules/home/home.service.spec.coffee +++ b/app/modules/home/home.service.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/home/projects/home-project-list-directive.spec.coffee b/app/modules/home/projects/home-project-list-directive.spec.coffee index d19de5ee..ac895c46 100644 --- a/app/modules/home/projects/home-project-list-directive.spec.coffee +++ b/app/modules/home/projects/home-project-list-directive.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -40,12 +40,6 @@ describe "homeProjectListDirective", () -> provide.value "tgCurrentUserService", mocks.currentUserService - _mockTgProjectsService = () -> - mocks.projectsService = { - newProject: sinon.stub() - } - provide.value "tgProjectsService", mocks.projectsService - _mockTranslateFilter = () -> mockTranslateFilter = (value) -> return value @@ -55,7 +49,6 @@ describe "homeProjectListDirective", () -> module ($provide) -> provide = $provide _mockTgCurrentUserService() - _mockTgProjectsService() _mockTranslateFilter() return null @@ -82,11 +75,3 @@ describe "homeProjectListDirective", () -> elm = createDirective() scope.$apply() expect(elm.isolateScope().vm.projects.size).to.be.equal(3) - - it "home project list directive newProject", () -> - elm = createDirective() - scope.$apply() - - expect(mocks.projectsService.newProject.callCount).to.be.equal(0) - elm.isolateScope().vm.newProject() - expect(mocks.projectsService.newProject.callCount).to.be.equal(1) diff --git a/app/modules/home/projects/home-project-list.directive.coffee b/app/modules/home/projects/home-project-list.directive.coffee index d59a28e3..9a820c3c 100644 --- a/app/modules/home/projects/home-project-list.directive.coffee +++ b/app/modules/home/projects/home-project-list.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -17,15 +17,12 @@ # File: home-project-list.directive.coffee ### -HomeProjectListDirective = (currentUserService, projectsService) -> +HomeProjectListDirective = (currentUserService) -> link = (scope, el, attrs, ctrl) -> scope.vm = {} taiga.defineImmutableProperty(scope.vm, "projects", () -> currentUserService.projects.get("recents")) - scope.vm.newProject = -> - projectsService.newProject() - directive = { templateUrl: "home/projects/home-project-list.html" scope: {} @@ -35,8 +32,7 @@ HomeProjectListDirective = (currentUserService, projectsService) -> return directive HomeProjectListDirective.$inject = [ - "tgCurrentUserService", - "tgProjectsService" + "tgCurrentUserService" ] angular.module("taigaHome").directive("tgHomeProjectList", HomeProjectListDirective) diff --git a/app/modules/home/projects/home-project-list.jade b/app/modules/home/projects/home-project-list.jade index beecb13c..73cf4ca6 100644 --- a/app/modules/home/projects/home-project-list.jade +++ b/app/modules/home/projects/home-project-list.jade @@ -84,14 +84,7 @@ section.projects-empty(ng-if="vm.projects != undefined && vm.projects.size === 0 p(translate="HOME.EMPTY_PROJECT_LIST") a.create-project-button.button-green( href="#" - ng-click="vm.newProject()" + tg-nav="create-project" title="{{'PROJECT.NAVIGATION.TITLE_CREATE_PROJECT' | translate}}" translate="PROJECT.NAVIGATION.ACTION_CREATE_PROJECT" ) - span(tg-import-project-button) - a.import-project-button.button-blackish( - href="#" - title="{{'PROJECT.NAVIGATION.TITLE_IMPORT_PROJECT' | translate}}" - translate="PROJECT.NAVIGATION.ACTION_IMPORT_PROJECT" - ) - input.import-file.hidden(type="file") diff --git a/app/modules/home/working-on/working-on.controller.coffee b/app/modules/home/working-on/working-on.controller.coffee index b02d341d..25c56c15 100644 --- a/app/modules/home/working-on/working-on.controller.coffee +++ b/app/modules/home/working-on/working-on.controller.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/home/working-on/working-on.controller.spec.coffee b/app/modules/home/working-on/working-on.controller.spec.coffee index d255ab18..a91c5555 100644 --- a/app/modules/home/working-on/working-on.controller.spec.coffee +++ b/app/modules/home/working-on/working-on.controller.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/home/working-on/working-on.directive.coffee b/app/modules/home/working-on/working-on.directive.coffee index 909f0669..c93ef816 100644 --- a/app/modules/home/working-on/working-on.directive.coffee +++ b/app/modules/home/working-on/working-on.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/invite-members/invite-members-form/invite-members-form.controller.coffee b/app/modules/invite-members/invite-members-form/invite-members-form.controller.coffee new file mode 100644 index 00000000..2fb48350 --- /dev/null +++ b/app/modules/invite-members/invite-members-form/invite-members-form.controller.coffee @@ -0,0 +1,81 @@ +### +# Copyright (C) 2014-2015 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: add-members.controller.coffee +### + +taiga = @.taiga + + +class InviteMembersFormController + @.$inject = [ + "tgProjectService", + "$tgResources", + "lightboxService", + "$tgConfirm", + "$rootScope" + ] + + constructor: (@projectService, @rs, @lightboxService, @confirm, @rootScope) -> + @.project = @projectService.project + @.roles = @projectService.project.get('roles') + @.rolesValues = {} + @.loading = false + @.defaultMaxInvites = 4 + + _areRolesValidated: () -> + Object.defineProperty @, 'areRolesValidated', { + get: () => + roleIds = _.filter Object.values(@.rolesValues), (it) -> return it + return roleIds.length == @.contactsToInvite.size + @.emailsToInvite.size + } + + _checkLimitMemberships: () -> + if @.project.get('max_memberships') == null + @.membersLimit = @.defaultMaxInvites + else + pendingMembersCount = Math.max(@.project.get('max_memberships') - @.project.get('total_memberships'), 0) + @.membersLimit = Math.min(pendingMembersCount, @.defaultMaxInvites) + + @.showWarningMessage = @.membersLimit < @.defaultMaxInvites + + sendInvites: () -> + @.setInvitedContacts = [] + _.forEach(@.rolesValues, (key, value) => + @.setInvitedContacts.push({ + 'role_id': key + 'username': value + }) + ) + @.loading = true + @rs.memberships.bulkCreateMemberships( + @.project.get('id'), + @.setInvitedContacts, + @.inviteContactsMessage + ) + .then (response) => # On success + @projectService.fetchProject().then => + @.loading = false + @lightboxService.closeAll() + @rootScope.$broadcast("membersform:new:success") + @confirm.notify('success') + .catch (response) => # On error + @.loading = false + if response.data._error_message + @confirm.notify("error", response.data._error_message) + + +angular.module("taigaAdmin").controller("InviteMembersFormCtrl", InviteMembersFormController) diff --git a/app/modules/invite-members/invite-members-form/invite-members-form.controller.spec.coffee b/app/modules/invite-members/invite-members-form/invite-members-form.controller.spec.coffee new file mode 100644 index 00000000..ffae1ce0 --- /dev/null +++ b/app/modules/invite-members/invite-members-form/invite-members-form.controller.spec.coffee @@ -0,0 +1,137 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: invite-members-form.controller.spec.coffee +### + +describe "InviteMembersFormController", -> + inviteMembersFormCtrl = null + provide = null + controller = null + mocks = {} + + _mockProjectService = () -> + mocks.projectService = { + project: sinon.stub() + fetchProject: sinon.stub() + } + + provide.value "tgProjectService", mocks.projectService + + _mockTgResources = () -> + mocks.tgResources = { + memberships: { + bulkCreateMemberships: sinon.stub() + } + } + + provide.value "$tgResources", mocks.tgResources + + _mockLightboxService = () -> + mocks.lightboxService = { + closeAll: sinon.stub() + } + + provide.value "lightboxService", mocks.lightboxService + + _mockTgConfirm = () -> + mocks.tgConfirm = { + notify: sinon.stub() + } + + provide.value "$tgConfirm", mocks.tgConfirm + + _mockRootScope = -> + mocks.rootScope = { + $broadcast: sinon.stub() + } + + provide.value("$rootScope", mocks.rootScope) + + _mocks = () -> + module ($provide) -> + provide = $provide + _mockProjectService() + _mockTgResources() + _mockLightboxService() + _mockTgConfirm() + _mockRootScope() + return null + + beforeEach -> + module "taigaAdmin" + + _mocks() + + inject ($controller) -> + controller = $controller + + mocks.projectService.project = Immutable.fromJS([{ + 'roles': 'role1' + }]) + + it "check limit memberships - no limit", () -> + inviteMembersFormCtrl = controller "InviteMembersFormCtrl" + + inviteMembersFormCtrl.project = Immutable.fromJS({ + 'max_memberships': null, + }) + + inviteMembersFormCtrl.defaultMaxInvites = 4 + + inviteMembersFormCtrl._checkLimitMemberships() + expect(inviteMembersFormCtrl.membersLimit).to.be.equal(4) + expect(inviteMembersFormCtrl.showWarningMessage).to.be.false + + it "check limit memberships", () -> + inviteMembersFormCtrl = controller "InviteMembersFormCtrl" + + inviteMembersFormCtrl.project = Immutable.fromJS({ + 'max_memberships': 15, + 'total_memberships': 13 + }) + inviteMembersFormCtrl.defaultMaxInvites = 4 + + inviteMembersFormCtrl._checkLimitMemberships() + expect(inviteMembersFormCtrl.membersLimit).to.be.equal(2) + expect(inviteMembersFormCtrl.showWarningMessage).to.be.true + + + it "send invites", (done) -> + inviteMembersFormCtrl = controller "InviteMembersFormCtrl" + inviteMembersFormCtrl.project = Immutable.fromJS( + {'id': 1} + ) + inviteMembersFormCtrl.rolesValues = {'user1': 1} + inviteMembersFormCtrl.inviteContactsMessage = 'Message' + inviteMembersFormCtrl.loading = true + + mocks.tgResources.memberships.bulkCreateMemberships.withArgs( + 1, + [{ + 'role_id': 1 + 'username': 'user1' + }], + 'Message' + ).promise().resolve() + + mocks.projectService.fetchProject.withArgs().promise().resolve() + + inviteMembersFormCtrl.sendInvites().then () -> + expect(inviteMembersFormCtrl.loading).to.be.false + expect(mocks.rootScope.$broadcast).to.have.been.calledWith("membersform:new:success") + expect(mocks.tgConfirm.notify).to.have.been.calledWith("success") + done() diff --git a/app/modules/invite-members/invite-members-form/invite-members-form.directive.coffee b/app/modules/invite-members/invite-members-form/invite-members-form.directive.coffee new file mode 100644 index 00000000..8bbe8d9f --- /dev/null +++ b/app/modules/invite-members/invite-members-form/invite-members-form.directive.coffee @@ -0,0 +1,41 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: invite-members.directive.coffee +### + +InviteMembersFormDirective = () -> + link = (scope, el, attrs, ctrl) -> + ctrl._areRolesValidated() + ctrl._checkLimitMemberships() + + return { + scope: {}, + templateUrl:"invite-members/invite-members-form/invite-members-form.html", + controller: "InviteMembersFormCtrl", + controllerAs: "vm", + bindToController: { + contactsToInvite: '<', + emailsToInvite: '=', + onDisplayContactList: '&', + onRemoveInvitedContact: '&', + onRemoveInvitedEmail: '&', + onSendInvites: '&' + }, + link: link + } + +angular.module("taigaAdmin").directive("tgInviteMembersForm", InviteMembersFormDirective) diff --git a/app/modules/invite-members/invite-members-form/invite-members-form.jade b/app/modules/invite-members/invite-members-form/invite-members-form.jade new file mode 100644 index 00000000..b2642606 --- /dev/null +++ b/app/modules/invite-members/invite-members-form/invite-members-form.jade @@ -0,0 +1,69 @@ +form.invite-members-form(ng-submit="vm.sendInvites(vm.inviteContacts)") + ul.invite-members-form-list + li.invite-members-single.e2e-invite-members-single( + ng-repeat="contact in vm.contactsToInvite | toMutable track by contact.id" + ) + .invite-members-single-data + img.invite-members-single-avatar( + tg-avatar="contact" + alt="{{contact.full_name}}" + ) + span.invite-members-single-name {{contact.full_name}} + a.invite-members-single-remove.e2e-invite-members-single-remove( + href="" + ng-click="vm.onRemoveInvitedContact({contact: contact})" + translate="LIGHTBOX.ADD_MEMBER.REMOVE" + ) + select.invite-members-single-role.e2e-invite-members-single-role( + ng-model="vm.rolesValues[contact.username]" + id="add-member-suggest-role-dropdown" + ng-options="role.id as role.name for role in vm.roles | toMutable track by role.id" + required + ) + option( + value="" + selected="selected" + translate="LIGHTBOX.ADD_MEMBER.CHOOSE_ROLE" + ) + li.invite-members-single.e2e-invite-members-single( + ng-repeat="userMail in vm.emailsToInvite | toMutable" + ) + .invite-members-single-data + span.invite-members-single-email {{userMail.email}} + a.invite-members-single-remove.e2e-invite-members-single-remove( + href="" + ng-click="vm.onRemoveInvitedEmail({email: userMail})" + translate="LIGHTBOX.ADD_MEMBER.REMOVE" + ) + select.invite-members-single-role.e2e-invite-members-single-role( + ng-model="vm.rolesValues[userMail.email]" + id="add-email-suggest-role-dropdown" + ng-options="role.id as role.name for role in vm.roles | toMutable track by role.id" + required + ) + option( + value="" + translate="LIGHTBOX.ADD_MEMBER.CHOOSE_ROLE" + ) + .invite-members-single-new.e2e-invite-members-single-new( + ng-if="vm.contactsToInvite.size + vm.emailsToInvite.size < vm.membersLimit" + ) + tg-svg.invite-members-single-new-btn( + svg-icon="icon-add" + ng-click="vm.onDisplayContactList()" + ) + tg-lightbox-add-members-warning-message( + ng-if="vm.showWarningMessage" + project="vm.project" + ) + textarea.invite-members-single-msg( + ng-model="vm.inviteContactsMessage" + placeholder="{{'LIGHTBOX.ADD_MEMBER.PLACEHOLDER_INVITATION_TEXT' | translate}}" + ) + button.button-green.invite-members-single-send.e2e-invite-members-single-send( + type="submit" + translate="LIGHTBOX.ADD_MEMBER.INVITE" + ng-disabled="!vm.areRolesValidated" + tg-loading="vm.loading" + ) + p.invite-members-single-help(translate="LIGHTBOX.ADD_MEMBER.HELP_TEXT") diff --git a/app/modules/invite-members/invite-members-form/invite-members-form.scss b/app/modules/invite-members/invite-members-form/invite-members-form.scss new file mode 100644 index 00000000..9f5099f9 --- /dev/null +++ b/app/modules/invite-members/invite-members-form/invite-members-form.scss @@ -0,0 +1,67 @@ +.invite-members-form { + border-top: 1px solid $whitish; + margin: 0 5rem; + .invite-members-form-list { + margin: 0; + margin-bottom: 1rem; + } + .invite-members-single { + align-items: center; + border-bottom: 1px solid $whitish; + display: flex; + justify-content: space-between; + padding: 1rem; + } + .invite-members-single-data { + align-items: center; + display: flex; + flex: 1; + } + .invite-members-single-avatar { + height: 4rem; + margin-right: 1rem; + width: 4rem; + } + .invite-members-single-remove { + color: $red-light; + margin-left: 1rem; + transition: color .2s; + &:hover { + color: $red; + } + } + .invite-members-single-role { + flex-basis: 40%; + flex-shrink: 0; + } + .invite-members-single-new { + align-items: center; + display: flex; + justify-content: center; + padding: 1rem 0; + .invite-members-single-new-btn { + cursor: pointer; + } + .icon-add { + @include svg-size(2rem); + fill: $grayer; + transition: fill .2s; + } + &:hover { + .icon-add { + fill: $primary-light; + } + } + } + .invite-members-single-send { + @include font-size(large); + display: block; + margin: 1.5rem 0 1rem; + padding: 1rem; + width: 100%; + } + .invite-members-single-help { + @include font-size(small); + @include font-type(light); + } +} diff --git a/app/modules/invite-members/lightbox-add-members.controller.coffee b/app/modules/invite-members/lightbox-add-members.controller.coffee new file mode 100644 index 00000000..5ad60891 --- /dev/null +++ b/app/modules/invite-members/lightbox-add-members.controller.coffee @@ -0,0 +1,74 @@ +### +# Copyright (C) 2014-2015 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: add-members.controller.coffee +### + +taiga = @.taiga + +class AddMembersController + @.$inject = [ + "tgUserService", + "tgCurrentUserService", + "tgProjectService", + ] + + constructor: (@userService, @currentUserService, @projectService) -> + @.contactsToInvite = Immutable.List() + @.emailsToInvite = Immutable.List() + @.displayContactList = false + + _getContacts: () -> + userId = @currentUserService.getUser().get("id") + excludeProjectId = @projectService.project.get("id") + + @userService.getContacts(userId, excludeProjectId).then (contacts) => + @.contacts = contacts + + _filterContacts: (invited) -> + @.contacts = @.contacts.filter( (contact) => + contact.get('id') != invited.get('id') + ) + + inviteSuggested: (contact) -> + @.contactsToInvite = @.contactsToInvite.push(contact) + @._filterContacts(contact) + @.displayContactList = true + + removeContact: (invited) -> + @.contactsToInvite = @.contactsToInvite.filter( (contact) => + return contact.get('id') != invited.id + ) + invited = Immutable.fromJS(invited) + @.contacts = @.contacts.push(invited) + @.testEmptyContacts() + + inviteEmail: (email) -> + emailData = Immutable.Map({'email': email}) + @.emailsToInvite = @.emailsToInvite.push(emailData) + @.displayContactList = true + + removeEmail: (invited) -> + @.emailsToInvite = @.emailsToInvite.filter( (email) => + return email.get('email') != invited.email + ) + @.testEmptyContacts() + + testEmptyContacts: () -> + if @.emailsToInvite.size + @.contactsToInvite.size == 0 + @.displayContactList = false + +angular.module("taigaAdmin").controller("AddMembersCtrl", AddMembersController) diff --git a/app/modules/invite-members/lightbox-add-members.controller.spec.coffee b/app/modules/invite-members/lightbox-add-members.controller.spec.coffee new file mode 100644 index 00000000..d1a6fbdd --- /dev/null +++ b/app/modules/invite-members/lightbox-add-members.controller.spec.coffee @@ -0,0 +1,180 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: lightbox-add-members.controller.spec.coffee +### + +describe "AddMembersController", -> + addMembersCtrl = null + provide = null + controller = null + mocks = {} + + _mockUserService = () -> + mocks.userService = { + getContacts: sinon.stub() + } + + provide.value "tgUserService", mocks.userService + + _mockCurrentUser = () -> + mocks.currentUser = { + getUser: sinon.stub() + } + + provide.value "tgCurrentUserService", mocks.currentUser + + _mockProjectService = () -> + mocks.projectService = { + project: sinon.stub() + } + + provide.value "tgProjectService", mocks.projectService + + _mocks = () -> + module ($provide) -> + provide = $provide + _mockCurrentUser() + _mockUserService() + _mockProjectService() + return null + + beforeEach -> + module "taigaAdmin" + + _mocks() + + inject ($controller) -> + controller = $controller + + + it "get user contacts", (done) -> + + userId = 1 + excludeProjectId = 1 + + mocks.currentUser.getUser.returns(Immutable.fromJS({ + id: userId + })) + mocks.projectService.project = Immutable.fromJS({ + id: excludeProjectId + }) + + contacts = Immutable.fromJS({ + username: "username", + full_name_display: "full-name-display", + bio: "bio" + }) + + mocks.userService.getContacts.withArgs(userId, excludeProjectId).promise().resolve(contacts) + + addMembersCtrl = controller "AddMembersCtrl" + + addMembersCtrl._getContacts().then () -> + expect(addMembersCtrl.contacts).to.be.equal(contacts) + done() + + it "filterContacts", () -> + + addMembersCtrl = controller "AddMembersCtrl" + addMembersCtrl.contacts = Immutable.fromJS([ + {id: 1} + {id: 2} + ]) + invited = Immutable.fromJS({id: 1}) + + addMembersCtrl._filterContacts(invited) + + expect(addMembersCtrl.contacts.size).to.be.equal(1) + + it "invite suggested", () -> + addMembersCtrl = controller "AddMembersCtrl" + addMembersCtrl.contactsToInvite = Immutable.List() + addMembersCtrl.displayContactList = false + + contact = Immutable.fromJS({id: 1}) + + addMembersCtrl._filterContacts = sinon.stub() + + addMembersCtrl.inviteSuggested(contact) + expect(addMembersCtrl.contactsToInvite.size).to.be.equal(1) + expect(addMembersCtrl._filterContacts).to.be.calledWith(contact) + expect(addMembersCtrl.displayContactList).to.be.true + + it "remove contact", () -> + addMembersCtrl = controller "AddMembersCtrl" + addMembersCtrl.contactsToInvite = Immutable.fromJS([ + {id: 1} + {id: 2} + ]) + invited = {id: 1} + addMembersCtrl.contacts = Immutable.fromJS([]) + + addMembersCtrl.testEmptyContacts = sinon.stub() + + addMembersCtrl.removeContact(invited) + expect(addMembersCtrl.contactsToInvite.size).to.be.equal(1) + expect(addMembersCtrl.contacts.size).to.be.equal(1) + expect(addMembersCtrl.testEmptyContacts).to.be.called + + it "invite email", () -> + addMembersCtrl = controller "AddMembersCtrl" + email = 'email@example.com' + emailData = Immutable.Map({'email': email}) + addMembersCtrl.displayContactList = false + + addMembersCtrl.emailsToInvite = Immutable.fromJS([]) + + addMembersCtrl.inviteEmail(email) + expect(emailData.get('email')).to.be.equal(email) + expect(addMembersCtrl.emailsToInvite.size).to.be.equal(1) + expect(addMembersCtrl.displayContactList).to.be.true + + it "remove email", () -> + addMembersCtrl = controller "AddMembersCtrl" + invited = {email: 'email@example.com'} + addMembersCtrl.emailsToInvite = Immutable.fromJS([ + {'email': 'email@example.com'} + {'email': 'email@example2.com'} + ]) + + addMembersCtrl.testEmptyContacts = sinon.stub() + + addMembersCtrl.removeEmail(invited) + expect(addMembersCtrl.emailsToInvite.size).to.be.equal(1) + expect(addMembersCtrl.testEmptyContacts).to.be.called + + it "test empty contacts - not empty", () -> + addMembersCtrl = controller "AddMembersCtrl" + addMembersCtrl.displayContactList = true + addMembersCtrl.emailsToInvite = Immutable.fromJS([ + {'email': 'email@example.com'} + {'email': 'email@example2.com'} + ]) + addMembersCtrl.contactsToInvite = Immutable.fromJS([ + {'id': 1} + {'id': 1} + ]) + addMembersCtrl.testEmptyContacts() + expect(addMembersCtrl.displayContactList).to.be.true + + it "test empty contacts - empty", () -> + addMembersCtrl = controller "AddMembersCtrl" + addMembersCtrl.displayContactList = true + addMembersCtrl.emailsToInvite = Immutable.fromJS([]) + addMembersCtrl.contactsToInvite = Immutable.fromJS([]) + addMembersCtrl.testEmptyContacts() + expect(addMembersCtrl.displayContactList).to.be.false diff --git a/app/modules/invite-members/lightbox-add-members.directive.coffee b/app/modules/invite-members/lightbox-add-members.directive.coffee new file mode 100644 index 00000000..44778fd4 --- /dev/null +++ b/app/modules/invite-members/lightbox-add-members.directive.coffee @@ -0,0 +1,33 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: add-member.directive.coffee +### + +LightboxAddMembersDirective = (lightboxService) -> + link = (scope, el, attrs, ctrl) -> + lightboxService.open(el) + ctrl._getContacts() + + return { + scope: {}, + templateUrl:"invite-members/lightbox-add-members.html", + controller: "AddMembersCtrl", + controllerAs: "vm", + link: link + } + +angular.module("taigaAdmin").directive("tgLbAddMembers", ["lightboxService", LightboxAddMembersDirective]) diff --git a/app/modules/invite-members/lightbox-add-members.jade b/app/modules/invite-members/lightbox-add-members.jade new file mode 100644 index 00000000..c88bebdb --- /dev/null +++ b/app/modules/invite-members/lightbox-add-members.jade @@ -0,0 +1,18 @@ +tg-lightbox-close +.add-members-wrapper + h2.title(translate="LIGHTBOX.ADD_MEMBER.TITLE") + tg-suggest-add-members( + ng-show="!vm.displayContactList" + contacts="vm.contacts" + on-invite-suggested="vm.inviteSuggested(contact)" + on-invite-email="vm.inviteEmail(email)" + ) + tg-invite-members-form( + ng-show="vm.displayContactList" + on-display-contact-list="vm.displayContactList = false" + contacts-to-invite="vm.contactsToInvite" + emails-to-invite="vm.emailsToInvite" + on-remove-invited-contact="vm.removeContact(contact)" + on-remove-invited-email="vm.removeEmail(email)" + on-send-invites="vm.submit(invites)" + ) diff --git a/app/modules/invite-members/lightbox-add-members.scss b/app/modules/invite-members/lightbox-add-members.scss new file mode 100644 index 00000000..3b0d3076 --- /dev/null +++ b/app/modules/invite-members/lightbox-add-members.scss @@ -0,0 +1,6 @@ +.lightbox-add-member { + .add-members-wrapper { + max-width: 900px; + width: 90%; + } +} diff --git a/app/modules/invite-members/suggest-add-members/suggest-add-members.controller.coffee b/app/modules/invite-members/suggest-add-members/suggest-add-members.controller.coffee new file mode 100644 index 00000000..03bde373 --- /dev/null +++ b/app/modules/invite-members/suggest-add-members/suggest-add-members.controller.coffee @@ -0,0 +1,39 @@ +### +# Copyright (C) 2014-2015 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: suggest-add-members.controller.coffee +### + +taiga = @.taiga + +class SuggestAddMembersController + @.$inject = [] + + constructor: () -> + @.contactQuery = "" + + isEmail: () -> + return taiga.isEmail(@.contactQuery) + + filterContacts: () -> + @.filteredContacts = @.contacts.filter( (contact) => + contact.get('full_name_display').toLowerCase().includes(@.contactQuery.toLowerCase()) || contact.get('username').toLowerCase().includes(@.contactQuery.toLowerCase()); + ) + + setInvited: (contact) -> + @.onInviteSuggested({'contact': contact}) + +angular.module("taigaAdmin").controller("SuggestAddMembersCtrl", SuggestAddMembersController) diff --git a/app/modules/invite-members/suggest-add-members/suggest-add-members.controller.spec.coffee b/app/modules/invite-members/suggest-add-members/suggest-add-members.controller.spec.coffee new file mode 100644 index 00000000..40e65a2d --- /dev/null +++ b/app/modules/invite-members/suggest-add-members/suggest-add-members.controller.spec.coffee @@ -0,0 +1,79 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: suggest-add-members.controller.spec.coffee +### + +describe "SuggestAddMembersController", -> + suggestAddMembersCtrl = null + provide = null + controller = null + mocks = {} + + _mocks = () -> + module ($provide) -> + provide = $provide + return null + + beforeEach -> + module "taigaAdmin" + + _mocks() + + inject ($controller) -> + controller = $controller + + it "is email - wrong", () -> + suggestAddMembersCtrl = controller "SuggestAddMembersCtrl" + suggestAddMembersCtrl.contactQuery = 'lololo' + + result = suggestAddMembersCtrl.isEmail() + expect(result).to.be.false + + it "is email - true", () -> + suggestAddMembersCtrl = controller "SuggestAddMembersCtrl" + suggestAddMembersCtrl.contactQuery = 'lololo@lolo.com' + + result = suggestAddMembersCtrl.isEmail() + expect(result).to.be.true + + it "filter contacts", () -> + suggestAddMembersCtrl = controller "SuggestAddMembersCtrl" + suggestAddMembersCtrl.contacts = Immutable.fromJS([ + { + full_name_display: 'Abel Sonofadan' + username: 'abel' + }, + { + full_name_display: 'Cain Sonofadan' + username: 'cain' + } + ]) + + suggestAddMembersCtrl.contactQuery = 'Cain Sonofadan' + + suggestAddMembersCtrl.filterContacts() + expect(suggestAddMembersCtrl.filteredContacts.size).to.be.equal(1) + + it "set invited", () -> + suggestAddMembersCtrl = controller "SuggestAddMembersCtrl" + + contact = 'contact' + + suggestAddMembersCtrl.onInviteSuggested = sinon.stub() + + suggestAddMembersCtrl.setInvited(contact) + expect(suggestAddMembersCtrl.onInviteSuggested).has.been.calledWith({'contact': contact}) diff --git a/app/modules/invite-members/suggest-add-members/suggest-add-members.directive.coffee b/app/modules/invite-members/suggest-add-members/suggest-add-members.directive.coffee new file mode 100644 index 00000000..beb9d9cb --- /dev/null +++ b/app/modules/invite-members/suggest-add-members/suggest-add-members.directive.coffee @@ -0,0 +1,34 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: suggest-add-member.directive.coffee +### + +SuggestAddMembersDirective = (lightboxService) -> + return { + scope: {}, + templateUrl:"invite-members/suggest-add-members/suggest-add-members.html", + controller: "SuggestAddMembersCtrl", + controllerAs: "vm", + bindToController: { + contacts: '=', + filteredContacts: ' +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/navigation-bar/dropdown-project-list/dropdown-project-list.directive.spec.coffee b/app/modules/navigation-bar/dropdown-project-list/dropdown-project-list.directive.spec.coffee index 56bf5b94..71b910cc 100644 --- a/app/modules/navigation-bar/dropdown-project-list/dropdown-project-list.directive.spec.coffee +++ b/app/modules/navigation-bar/dropdown-project-list/dropdown-project-list.directive.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/navigation-bar/dropdown-project-list/dropdown-project-list.jade b/app/modules/navigation-bar/dropdown-project-list/dropdown-project-list.jade index 7940b928..b273ae62 100644 --- a/app/modules/navigation-bar/dropdown-project-list/dropdown-project-list.jade +++ b/app/modules/navigation-bar/dropdown-project-list/dropdown-project-list.jade @@ -29,14 +29,6 @@ div.navbar-dropdown.dropdown-project-list div.create-options a.create-project-btn.button-green( href="#", - ng-click="vm.newProject()", + tg-nav="create-project" title="{{'PROJECT.NAVIGATION.ACTION_CREATE_PROJECT' | translate}}", translate="PROJECT.NAVIGATION.ACTION_CREATE_PROJECT") - - span(tg-import-project-button) - a.button-blackish.import-project-button( - href="" - title="{{'PROJECT.NAVIGATION.TITLE_IMPORT_PROJECT' | translate}}" - ) - tg-svg(svg-icon="icon-upload") - input.import-file.hidden(type="file") diff --git a/app/modules/navigation-bar/dropdown-user/dropdown-user.directive.coffee b/app/modules/navigation-bar/dropdown-user/dropdown-user.directive.coffee index 6602996e..effab3b1 100644 --- a/app/modules/navigation-bar/dropdown-user/dropdown-user.directive.coffee +++ b/app/modules/navigation-bar/dropdown-user/dropdown-user.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/navigation-bar/dropdown-user/dropdown-user.directive.spec.coffee b/app/modules/navigation-bar/dropdown-user/dropdown-user.directive.spec.coffee index 87287d6a..f991e3f7 100644 --- a/app/modules/navigation-bar/dropdown-user/dropdown-user.directive.spec.coffee +++ b/app/modules/navigation-bar/dropdown-user/dropdown-user.directive.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/navigation-bar/navigation-bar.directive.coffee b/app/modules/navigation-bar/navigation-bar.directive.coffee index 47b0da51..78632ad4 100644 --- a/app/modules/navigation-bar/navigation-bar.directive.coffee +++ b/app/modules/navigation-bar/navigation-bar.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/navigation-bar/navigation-bar.directive.spec.coffee b/app/modules/navigation-bar/navigation-bar.directive.spec.coffee index d8742bfe..661b09dc 100644 --- a/app/modules/navigation-bar/navigation-bar.directive.spec.coffee +++ b/app/modules/navigation-bar/navigation-bar.directive.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/navigation-bar/navigation-bar.module.coffee b/app/modules/navigation-bar/navigation-bar.module.coffee index 94481f23..4728cea5 100644 --- a/app/modules/navigation-bar/navigation-bar.module.coffee +++ b/app/modules/navigation-bar/navigation-bar.module.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/navigation-bar/navigation-bar.scss b/app/modules/navigation-bar/navigation-bar.scss index a04122cc..887bb87b 100644 --- a/app/modules/navigation-bar/navigation-bar.scss +++ b/app/modules/navigation-bar/navigation-bar.scss @@ -23,22 +23,16 @@ $dropdown-width: 350px; display: flex; } .nav-left { - >a { + a { color: $white; padding: .5rem 1.5rem; - &.logo { - background: rgba($black, .2); - padding: .4rem .75rem; - } - svg { - height: 1.6rem; - max-height: 1.6rem; - max-width: 2rem; - width: 1.6rem; - } - path { - fill: $white; - } + } + .logo { + background: rgba($black, .2); + padding: .3rem .75rem; + } + svg { + @include svg-size(1.6rem); } } .nav-right { @@ -47,15 +41,16 @@ $dropdown-width: 350px; color: $white; padding: .5rem 2rem; } + svg { + @include svg-size(1.2rem); + fill: rgba($primary-dark, .8); + transition: all .2s linear; + } } a { color: $white; display: inline-block; transition: all .2s linear; - svg { - fill: rgba($primary-dark, .8); - transition: all .2s linear; - } &:hover { background: rgba($black, .2); color: $primary-light; @@ -80,12 +75,6 @@ $dropdown-width: 350px; margin-left: .5rem; vertical-align: middle; } - svg { - height: 1.2rem; - max-height: 1.2rem; - max-width: 1.2rem; - width: 1.2rem; - } .topnav-dropdown-wrapper { position: relative; &:hover { @@ -163,9 +152,6 @@ $dropdown-width: 350px; &.see-more-projects-btn { margin-bottom: .3rem; } - &.import-project-button { - padding: .8rem 1rem; - } &.create-project-btn { flex: 1; } @@ -178,16 +164,6 @@ $dropdown-width: 350px; } } } - .import-project-button { - &:hover { - svg { - fill: $primary-light; - } - } - svg { - fill: $white; - } - } .create-options { display: flex; flex-direction: row; diff --git a/app/modules/navigation-bar/navigation-bar.service.coffee b/app/modules/navigation-bar/navigation-bar.service.coffee index c043fa4f..da27907d 100644 --- a/app/modules/navigation-bar/navigation-bar.service.coffee +++ b/app/modules/navigation-bar/navigation-bar.service.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/profile/profile-bar/profile-bar.controller.coffee b/app/modules/profile/profile-bar/profile-bar.controller.coffee index f317b71f..f790b39b 100644 --- a/app/modules/profile/profile-bar/profile-bar.controller.coffee +++ b/app/modules/profile/profile-bar/profile-bar.controller.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/profile/profile-bar/profile-bar.controller.spec.coffee b/app/modules/profile/profile-bar/profile-bar.controller.spec.coffee index 66c83ac5..8f9b1134 100644 --- a/app/modules/profile/profile-bar/profile-bar.controller.spec.coffee +++ b/app/modules/profile/profile-bar/profile-bar.controller.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/profile/profile-bar/profile-bar.directive.coffee b/app/modules/profile/profile-bar/profile-bar.directive.coffee index 8e9a2a51..7a331f9b 100644 --- a/app/modules/profile/profile-bar/profile-bar.directive.coffee +++ b/app/modules/profile/profile-bar/profile-bar.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/profile/profile-contacts/profile-contacts.controller.coffee b/app/modules/profile/profile-contacts/profile-contacts.controller.coffee index 81fa0e45..20c39713 100644 --- a/app/modules/profile/profile-contacts/profile-contacts.controller.coffee +++ b/app/modules/profile/profile-contacts/profile-contacts.controller.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/profile/profile-contacts/profile-contacts.controller.spec.coffee b/app/modules/profile/profile-contacts/profile-contacts.controller.spec.coffee index 2c265083..c2d91a2e 100644 --- a/app/modules/profile/profile-contacts/profile-contacts.controller.spec.coffee +++ b/app/modules/profile/profile-contacts/profile-contacts.controller.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/profile/profile-contacts/profile-contacts.directive.coffee b/app/modules/profile/profile-contacts/profile-contacts.directive.coffee index 3fca94c3..ac541d8b 100644 --- a/app/modules/profile/profile-contacts/profile-contacts.directive.coffee +++ b/app/modules/profile/profile-contacts/profile-contacts.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/profile/profile-favs/items/items.directive.coffee b/app/modules/profile/profile-favs/items/items.directive.coffee index 8d1a437a..0cf607b1 100644 --- a/app/modules/profile/profile-favs/items/items.directive.coffee +++ b/app/modules/profile/profile-favs/items/items.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/profile/profile-favs/profile-favs.controller.coffee b/app/modules/profile/profile-favs/profile-favs.controller.coffee index 2fc3ac7c..d9a5213d 100644 --- a/app/modules/profile/profile-favs/profile-favs.controller.coffee +++ b/app/modules/profile/profile-favs/profile-favs.controller.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/profile/profile-favs/profile-favs.controller.spec.coffee b/app/modules/profile/profile-favs/profile-favs.controller.spec.coffee index a761fe64..fceaf51f 100644 --- a/app/modules/profile/profile-favs/profile-favs.controller.spec.coffee +++ b/app/modules/profile/profile-favs/profile-favs.controller.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/profile/profile-favs/profile-favs.directive.coffee b/app/modules/profile/profile-favs/profile-favs.directive.coffee index 267236a0..a9e6644e 100644 --- a/app/modules/profile/profile-favs/profile-favs.directive.coffee +++ b/app/modules/profile/profile-favs/profile-favs.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/profile/profile-hints/profile-hints.controller.coffee b/app/modules/profile/profile-hints/profile-hints.controller.coffee index 11991f95..54daaaa8 100644 --- a/app/modules/profile/profile-hints/profile-hints.controller.coffee +++ b/app/modules/profile/profile-hints/profile-hints.controller.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/profile/profile-hints/profile-hints.controller.spec.coffee b/app/modules/profile/profile-hints/profile-hints.controller.spec.coffee index c91eea4d..3bc87391 100644 --- a/app/modules/profile/profile-hints/profile-hints.controller.spec.coffee +++ b/app/modules/profile/profile-hints/profile-hints.controller.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/profile/profile-hints/profile-hints.directive.coffee b/app/modules/profile/profile-hints/profile-hints.directive.coffee index 4383b501..b4a64d56 100644 --- a/app/modules/profile/profile-hints/profile-hints.directive.coffee +++ b/app/modules/profile/profile-hints/profile-hints.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/profile/profile-projects/profile-projects.controller.coffee b/app/modules/profile/profile-projects/profile-projects.controller.coffee index bd43164d..1b18e742 100644 --- a/app/modules/profile/profile-projects/profile-projects.controller.coffee +++ b/app/modules/profile/profile-projects/profile-projects.controller.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/profile/profile-projects/profile-projects.controller.spec.coffee b/app/modules/profile/profile-projects/profile-projects.controller.spec.coffee index 604c67b9..b35bfcff 100644 --- a/app/modules/profile/profile-projects/profile-projects.controller.spec.coffee +++ b/app/modules/profile/profile-projects/profile-projects.controller.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/profile/profile-projects/profile-projects.directive.coffee b/app/modules/profile/profile-projects/profile-projects.directive.coffee index 2236e563..99eed514 100644 --- a/app/modules/profile/profile-projects/profile-projects.directive.coffee +++ b/app/modules/profile/profile-projects/profile-projects.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/profile/profile-tab/profile-tab.directive.coffee b/app/modules/profile/profile-tab/profile-tab.directive.coffee index 308a97ba..1bfd39ca 100644 --- a/app/modules/profile/profile-tab/profile-tab.directive.coffee +++ b/app/modules/profile/profile-tab/profile-tab.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/profile/profile-tabs/profile-tabs.controller.coffee b/app/modules/profile/profile-tabs/profile-tabs.controller.coffee index 3c32a897..a130d2a9 100644 --- a/app/modules/profile/profile-tabs/profile-tabs.controller.coffee +++ b/app/modules/profile/profile-tabs/profile-tabs.controller.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/profile/profile-tabs/profile-tabs.controller.spec.coffee b/app/modules/profile/profile-tabs/profile-tabs.controller.spec.coffee index f8b1382f..08143102 100644 --- a/app/modules/profile/profile-tabs/profile-tabs.controller.spec.coffee +++ b/app/modules/profile/profile-tabs/profile-tabs.controller.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/profile/profile-tabs/profile-tabs.directive.coffee b/app/modules/profile/profile-tabs/profile-tabs.directive.coffee index 2ccc23d5..47846161 100644 --- a/app/modules/profile/profile-tabs/profile-tabs.directive.coffee +++ b/app/modules/profile/profile-tabs/profile-tabs.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/profile/profile.controller.coffee b/app/modules/profile/profile.controller.coffee index d275db72..c5234f23 100644 --- a/app/modules/profile/profile.controller.coffee +++ b/app/modules/profile/profile.controller.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/profile/profile.controller.spec.coffee b/app/modules/profile/profile.controller.spec.coffee index c306682a..a10fac63 100644 --- a/app/modules/profile/profile.controller.spec.coffee +++ b/app/modules/profile/profile.controller.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/profile/profile.module.coffee b/app/modules/profile/profile.module.coffee index 4654dbc1..89167125 100644 --- a/app/modules/profile/profile.module.coffee +++ b/app/modules/profile/profile.module.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/projects/components/blocked-project-explanation.directive.coffee b/app/modules/projects/components/blocked-project-explanation.directive.coffee index fac3ed91..fe266e9b 100644 --- a/app/modules/projects/components/blocked-project-explanation.directive.coffee +++ b/app/modules/projects/components/blocked-project-explanation.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/projects/components/contact-project-button/contact-project-button.controller.coffee b/app/modules/projects/components/contact-project-button/contact-project-button.controller.coffee new file mode 100644 index 00000000..da8e0ec1 --- /dev/null +++ b/app/modules/projects/components/contact-project-button/contact-project-button.controller.coffee @@ -0,0 +1,38 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: like-project-button.controller.coffee +### + +class ContactProjectButtonController + @.$inject = ['tgLightboxFactory'] + + constructor: (@lightboxFactory)-> + + launchContactForm: () -> + @lightboxFactory.create( + 'tg-lb-contact-project', + { + "class": "lightbox lightbox-contact-project e2e-lightbox-contact-project", + "project": "project" + }, + { + "project": @.project + } + ) + + +angular.module("taigaProjects").controller("ContactProjectButtonCtrl", ContactProjectButtonController) diff --git a/app/modules/projects/components/contact-project-button/contact-project-button.controller.spec.coffee b/app/modules/projects/components/contact-project-button/contact-project-button.controller.spec.coffee new file mode 100644 index 00000000..58926118 --- /dev/null +++ b/app/modules/projects/components/contact-project-button/contact-project-button.controller.spec.coffee @@ -0,0 +1,50 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: contact-project-button.controller.spec.coffee +### + +describe "ContactProjectButton", -> + provide = null + controller = null + mocks = {} + + _mockTgLightboxFactory = () -> + mocks.tgLightboxFactory = { + create: sinon.stub() + } + + provide.value "tgLightboxFactory", mocks.tgLightboxFactory + + _mocks = () -> + module ($provide) -> + provide = $provide + _mockTgLightboxFactory() + + return null + + beforeEach -> + module "taigaProjects" + + _mocks() + + inject ($controller) -> + controller = $controller + + it "Launch Contact Form", () -> + ctrl = controller("ContactProjectButtonCtrl") + ctrl.launchContactForm() + expect(mocks.tgLightboxFactory.create).have.been.called diff --git a/app/modules/projects/components/contact-project-button/contact-project-button.directive.coffee b/app/modules/projects/components/contact-project-button/contact-project-button.directive.coffee new file mode 100644 index 00000000..fbe00106 --- /dev/null +++ b/app/modules/projects/components/contact-project-button/contact-project-button.directive.coffee @@ -0,0 +1,32 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: contact-project-button.directive.coffee +### + +ContactProjectButtonDirective = -> + return { + scope: {} + controller: "ContactProjectButtonCtrl", + bindToController: { + project: '=' + layout: '@' + } + controllerAs: "vm", + templateUrl: "projects/components/contact-project-button/contact-project-button.html", + } + +angular.module("taigaProjects").directive("tgContactProjectButton", ContactProjectButtonDirective) diff --git a/app/modules/projects/components/contact-project-button/contact-project-button.jade b/app/modules/projects/components/contact-project-button/contact-project-button.jade new file mode 100644 index 00000000..7b6638f4 --- /dev/null +++ b/app/modules/projects/components/contact-project-button/contact-project-button.jade @@ -0,0 +1,10 @@ +button.track-button.contact-team.e2e-contact-team( + title="{{ 'PROJECT.CONTACT_BUTTON.CONTACT_TITLE' | translate }}" + ng-click="vm.launchContactForm()" + ng-class="{'contact-team-large': vm.layout == 'large'}" +) + tg-svg(svg-icon="icon-mail") + span( + ng-if="vm.layout == 'large'" + translate="PROJECT.CONTACT_BUTTON.CONTACT_BUTTON" + ) diff --git a/app/modules/projects/components/contact-project-button/contact-project-button.scss b/app/modules/projects/components/contact-project-button/contact-project-button.scss new file mode 100644 index 00000000..ece4ccba --- /dev/null +++ b/app/modules/projects/components/contact-project-button/contact-project-button.scss @@ -0,0 +1,14 @@ +.contact-team { + margin-left: .75rem; + &-large { + @include font-size(small); + @include font-type(light); + justify-content: center; + margin-left: 0; + width: 100%; + .icon-mail { + margin-right: .5rem; + vertical-align: center; + } + } +} diff --git a/app/modules/projects/components/lb-contact-project/lb-contact-project.controller.coffee b/app/modules/projects/components/lb-contact-project/lb-contact-project.controller.coffee new file mode 100644 index 00000000..760babd4 --- /dev/null +++ b/app/modules/projects/components/lb-contact-project/lb-contact-project.controller.coffee @@ -0,0 +1,41 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: lb-contact-team.controller.coffee +### + +class ContactProjectLbController + @.$inject = [ + "lightboxService", + "tgResources", + "$tgConfirm", + ] + + constructor: (@lightboxService, @rs, @confirm) -> + @.contact = {} + + contactProject: () -> + project = @.project.get('id') + message = @.contact.message + + promise = @rs.projects.contactProject(project, message) + @.sendingFeedback = true + promise.then => + @lightboxService.closeAll() + @.sendingFeedback = false + @confirm.notify("success") + +angular.module("taigaProjects").controller("ContactProjectLbCtrl", ContactProjectLbController) diff --git a/app/modules/projects/components/lb-contact-project/lb-contact-project.controller.spec.coffee b/app/modules/projects/components/lb-contact-project/lb-contact-project.controller.spec.coffee new file mode 100644 index 00000000..9fe479d7 --- /dev/null +++ b/app/modules/projects/components/lb-contact-project/lb-contact-project.controller.spec.coffee @@ -0,0 +1,85 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: lb/contact-project-button.controller.spec.coffee +### + +describe "LbContactProject", -> + provide = null + controller = null + mocks = {} + + _mockTgLightboxSercice = () -> + mocks.tglightboxService = { + closeAll: sinon.stub() + } + + provide.value "lightboxService", mocks.tglightboxService + + _mockTgResources = () -> + mocks.tgResources = { + projects: { + contactProject: sinon.stub() + } + } + + provide.value "tgResources", mocks.tgResources + + _mockTgConfirm = () -> + mocks.tgConfirm = { + notify: sinon.stub() + } + + provide.value "$tgConfirm", mocks.tgConfirm + + _mocks = () -> + module ($provide) -> + provide = $provide + _mockTgLightboxSercice() + _mockTgResources() + _mockTgConfirm() + + return null + + beforeEach -> + module "taigaProjects" + + _mocks() + + inject ($controller) -> + controller = $controller + + it "Contact Project", (done) -> + ctrl = controller("ContactProjectLbCtrl") + ctrl.contact = { + message: 'abcde' + } + ctrl.project = Immutable.fromJS({ + id: 1 + }) + + project = ctrl.project.get('id') + message = ctrl.contact.message + + promise = mocks.tgResources.projects.contactProject.withArgs(project, message).promise().resolve() + + ctrl.sendingFeedback = true + + ctrl.contactProject().then () -> + expect(mocks.tglightboxService.closeAll).have.been.called + expect(ctrl.sendingFeedback).to.be.false + expect(mocks.tgConfirm.notify).have.been.calledWith("success") + done() diff --git a/app/modules/projects/components/lb-contact-project/lb-contact-project.directive.coffee b/app/modules/projects/components/lb-contact-project/lb-contact-project.directive.coffee new file mode 100644 index 00000000..56ee7767 --- /dev/null +++ b/app/modules/projects/components/lb-contact-project/lb-contact-project.directive.coffee @@ -0,0 +1,37 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: lb-contact-team.directive.coffee +### + +ContactProjectLbDirective = (lightboxService) -> + + @.inject = ['lightboxService'] + + link = (scope, el) -> + lightboxService.open(el) + + return { + controller: "ContactProjectLbCtrl", + bindToController: { + project: '=' + } + controllerAs: "vm", + templateUrl: "projects/components/lb-contact-project/lb-contact-project.html", + link: link + } + +angular.module("taigaProjects").directive("tgLbContactProject", ["lightboxService", ContactProjectLbDirective]) diff --git a/app/modules/projects/components/lb-contact-project/lb-contact-project.jade b/app/modules/projects/components/lb-contact-project/lb-contact-project.jade new file mode 100644 index 00000000..f43fd711 --- /dev/null +++ b/app/modules/projects/components/lb-contact-project/lb-contact-project.jade @@ -0,0 +1,27 @@ +tg-lightbox-close + +form.lightbox-contact-project-container + img.lightbox-contact-project-logo( + ng-if="vm.project.logo_big_url" + alt="{{vm.project.get('name')}}" + ng-src="vm.project.logo_big_url" + ) + img.lightbox-contact-project-logo( + ng-if="!vm.project.logo_big_url" + tg-project-logo-big-src="vm.project" + alt="{{vm.project.get('name')}}" + ) + h2.lightbox-contact-project-title(translate="LIGHTBOX.CONTACT_PROJECT.TITLE") + h3.lightbox-contact-project-name {{vm.project.get('name')}} + p(translate="LIGHTBOX.CONTACT_PROJECT.WARNING") + textarea.lightbox-contact-project-message.e2e-lightbox-contact-project-message( + ng-model="vm.contact.message" + required + placeholder="{{'LIGHTBOX.CONTACT_PROJECT.PLACEHOLDER' | translate}}" + ) + button.button-green.lightbox-contact-project-button.e2e-lightbox-contact-project-button( + translate="LIGHTBOX.CONTACT_PROJECT.SEND" + ng-click="vm.contactProject()" + tg-loading="vm.sendingFeedback" + ng-disabled="!vm.contact.message.length" + ) diff --git a/app/modules/projects/components/lb-contact-project/lb-contact-project.scss b/app/modules/projects/components/lb-contact-project/lb-contact-project.scss new file mode 100644 index 00000000..4cc6e3af --- /dev/null +++ b/app/modules/projects/components/lb-contact-project/lb-contact-project.scss @@ -0,0 +1,29 @@ +.lightbox-contact-project { + align-items: center; + display: flex; + justify-content: center; + &-container { + max-width: 600px; + text-align: center; + width: 90%; + } + &-logo { + width: 5rem; + } + &-title { + margin: 0; + } + &-name { + @include font-size(larger); + color: $primary; + margin-bottom: 1rem; + } + &-message { + max-height: 400px; + } + &-button { + display: block; + margin-top: .5rem; + width: 100%; + } +} diff --git a/app/modules/projects/components/like-project-button/like-project-button.controller.coffee b/app/modules/projects/components/like-project-button/like-project-button.controller.coffee index 0322e17d..1e6caf93 100644 --- a/app/modules/projects/components/like-project-button/like-project-button.controller.coffee +++ b/app/modules/projects/components/like-project-button/like-project-button.controller.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/projects/components/like-project-button/like-project-button.controller.spec.coffee b/app/modules/projects/components/like-project-button/like-project-button.controller.spec.coffee index f29bbc33..8b9a8ce2 100644 --- a/app/modules/projects/components/like-project-button/like-project-button.controller.spec.coffee +++ b/app/modules/projects/components/like-project-button/like-project-button.controller.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/projects/components/like-project-button/like-project-button.directive.coffee b/app/modules/projects/components/like-project-button/like-project-button.directive.coffee index 7b9c1d60..08e0a979 100644 --- a/app/modules/projects/components/like-project-button/like-project-button.directive.coffee +++ b/app/modules/projects/components/like-project-button/like-project-button.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/projects/components/like-project-button/like-project-button.jade b/app/modules/projects/components/like-project-button/like-project-button.jade index de8da23f..57fc69b0 100644 --- a/app/modules/projects/components/like-project-button/like-project-button.jade +++ b/app/modules/projects/components/like-project-button/like-project-button.jade @@ -1,5 +1,4 @@ -a.track-button.like-button.like-container( - href="", +button.track-button.like-button( title="{{ 'PROJECT.LIKE_BUTTON.BUTTON_TITLE' | translate }}" ng-click="vm.toggleLike()" ng-class="{'active':vm.project.get('is_fan'), 'is-hover':vm.project.get('is_fan') && vm.isMouseOver}" @@ -21,9 +20,7 @@ a.track-button.like-button.like-container( ng-if="vm.project.get('is_fan') && vm.isMouseOver" translate="PROJECT.LIKE_BUTTON.UNLIKE" ) - span.track-button-counter( title="{{ 'PROJECT.LIKE_BUTTON.COUNTER_TITLE'|translate:{total:vm.project.get(\"total_fans\")||0}:'messageformat' }}", tg-loading="vm.loading" - ) - | {{ vm.project.get('total_fans') }} + ) {{ vm.project.get('total_fans') }} diff --git a/app/modules/projects/components/like-project-button/like-project-button.service.coffee b/app/modules/projects/components/like-project-button/like-project-button.service.coffee index d8e5a7fa..4ebfc966 100644 --- a/app/modules/projects/components/like-project-button/like-project-button.service.coffee +++ b/app/modules/projects/components/like-project-button/like-project-button.service.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/projects/components/like-project-button/like-project-button.service.spec.coffee b/app/modules/projects/components/like-project-button/like-project-button.service.spec.coffee index cfb3285b..6353f040 100644 --- a/app/modules/projects/components/like-project-button/like-project-button.service.spec.coffee +++ b/app/modules/projects/components/like-project-button/like-project-button.service.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/projects/components/sort-projects.directive.coffee b/app/modules/projects/components/sort-projects.directive.coffee index d432de2d..10194ba8 100644 --- a/app/modules/projects/components/sort-projects.directive.coffee +++ b/app/modules/projects/components/sort-projects.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/projects/components/watch-project-button/watch-project-button.controller.coffee b/app/modules/projects/components/watch-project-button/watch-project-button.controller.coffee index e24316a4..ba337380 100644 --- a/app/modules/projects/components/watch-project-button/watch-project-button.controller.coffee +++ b/app/modules/projects/components/watch-project-button/watch-project-button.controller.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/projects/components/watch-project-button/watch-project-button.controller.spec.coffee b/app/modules/projects/components/watch-project-button/watch-project-button.controller.spec.coffee index 1d6ce2fe..3e36f46e 100644 --- a/app/modules/projects/components/watch-project-button/watch-project-button.controller.spec.coffee +++ b/app/modules/projects/components/watch-project-button/watch-project-button.controller.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/projects/components/watch-project-button/watch-project-button.directive.coffee b/app/modules/projects/components/watch-project-button/watch-project-button.directive.coffee index 048554cb..a3c57996 100644 --- a/app/modules/projects/components/watch-project-button/watch-project-button.directive.coffee +++ b/app/modules/projects/components/watch-project-button/watch-project-button.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/projects/components/watch-project-button/watch-project-button.jade b/app/modules/projects/components/watch-project-button/watch-project-button.jade index dff7401a..2ad65e58 100644 --- a/app/modules/projects/components/watch-project-button/watch-project-button.jade +++ b/app/modules/projects/components/watch-project-button/watch-project-button.jade @@ -1,5 +1,4 @@ -a.track-button.watch-button.watch-container( - href="", +button.track-button.watch-button( title="{{ 'PROJECT.WATCH_BUTTON.BUTTON_TITLE' | translate }}" ng-click="vm.toggleWatcherOptions()" ng-class="{'active': vm.project.get('is_watcher')}" @@ -7,24 +6,25 @@ a.track-button.watch-button.watch-container( span.track-inner span.track-icon tg-svg(svg-icon="icon-watch") - span(ng-if="!vm.project.get('is_watcher')", translate="PROJECT.WATCH_BUTTON.WATCH") - span(ng-if="vm.project.get('is_watcher')", translate="PROJECT.WATCH_BUTTON.WATCHING") + span( + ng-if="!vm.project.get('is_watcher')" + translate="PROJECT.WATCH_BUTTON.WATCH" + ) + span( + ng-if="vm.project.get('is_watcher')" + translate="PROJECT.WATCH_BUTTON.WATCHING" + ) tg-svg.watch-options-arrow(svg-icon="icon-arrow-down") span.track-button-counter( - title="{{ 'PROJECT.WATCH_BUTTON.COUNTER_TITLE'|translate:{total:vm.project.get(\"total_watchers\")||0}:'messageformat' }}", + title="{{ 'PROJECT.WATCH_BUTTON.COUNTER_TITLE'|translate:{total:vm.project.get(\"total_watchers\")||0}:'messageformat' }}" tg-loading="vm.loading" - ) - | {{ vm.project.get('total_watchers') }} + ) {{ vm.project.get('total_watchers') }} ul.watch-options( ng-class="{'hidden': !vm.showWatchOptions}" ng-mouseleave="vm.closeWatcherOptions()" ) - //- NOTIFY LEVEL CHOICES: - //- 1 - Only involved - //- 2 - Receive all - //- 3 - No notifications li a( diff --git a/app/modules/projects/components/watch-project-button/watch-project-button.service.coffee b/app/modules/projects/components/watch-project-button/watch-project-button.service.coffee index 52f4ec22..ff42b864 100644 --- a/app/modules/projects/components/watch-project-button/watch-project-button.service.coffee +++ b/app/modules/projects/components/watch-project-button/watch-project-button.service.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/projects/components/watch-project-button/watch-project-button.service.spec.coffee b/app/modules/projects/components/watch-project-button/watch-project-button.service.spec.coffee index a782887d..d8522144 100644 --- a/app/modules/projects/components/watch-project-button/watch-project-button.service.spec.coffee +++ b/app/modules/projects/components/watch-project-button/watch-project-button.service.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/projects/create/asana-import/asana-import-project-form/asana-import-project-form.controller.coffee b/app/modules/projects/create/asana-import/asana-import-project-form/asana-import-project-form.controller.coffee new file mode 100644 index 00000000..fbd49dea --- /dev/null +++ b/app/modules/projects/create/asana-import/asana-import-project-form/asana-import-project-form.controller.coffee @@ -0,0 +1,55 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: asana-import-project-form.controller.coffee +### + +class AsanaImportProjectFormController + @.$inject = [ + "tgCurrentUserService" + ] + + constructor: (@currentUserService) -> + @.canCreatePublicProjects = @currentUserService.canCreatePublicProjects() + @.canCreatePrivateProjects = @currentUserService.canCreatePrivateProjects() + + @.projectForm = @.project.toJS() + + @.platformName = "Asana" + @.projectForm.is_private = false + @.projectForm.keepExternalReference = false + @.projectForm.project_type = "scrum" + + if !@.canCreatePublicProjects.valid && @.canCreatePrivateProjects.valid + @.projectForm.is_private = true + + checkUsersLimit: () -> + @.limitMembersPrivateProject = @currentUserService.canAddMembersPrivateProject(@.members.size) + @.limitMembersPublicProject = @currentUserService.canAddMembersPublicProject(@.members.size) + + saveForm: () -> + @.onSaveProjectDetails({project: Immutable.fromJS(@.projectForm)}) + + canCreateProject: () -> + if @.projectForm.is_private + return @.canCreatePrivateProjects.valid + else + return @.canCreatePublicProjects.valid + + isDisabled: () -> + return !@.canCreateProject() + +angular.module('taigaProjects').controller('AsanaImportProjectFormCtrl', AsanaImportProjectFormController) diff --git a/app/modules/projects/create/asana-import/asana-import-project-form/asana-import-project-form.directive.coffee b/app/modules/projects/create/asana-import/asana-import-project-form/asana-import-project-form.directive.coffee new file mode 100644 index 00000000..be627013 --- /dev/null +++ b/app/modules/projects/create/asana-import/asana-import-project-form/asana-import-project-form.directive.coffee @@ -0,0 +1,40 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: asana-import-project-form.directive.coffee +### + +AsanaImportProjectFormDirective = () -> + return { + link: (scope, elm, attr, ctrl) -> + scope.$watch('vm.members', ctrl.checkUsersLimit.bind(ctrl)) + + templateUrl:"projects/create/asana-import/asana-import-project-form/asana-import-project-form.html", + controller: "AsanaImportProjectFormCtrl", + controllerAs: "vm", + bindToController: true, + scope: { + members: '<', + project: '<', + onSaveProjectDetails: '&', + onCancelForm: '&', + fetchingUsers: '<' + } + } + +AsanaImportProjectFormDirective.$inject = [] + +angular.module("taigaProjects").directive("tgAsanaImportProjectForm", AsanaImportProjectFormDirective) diff --git a/app/modules/projects/create/asana-import/asana-import-project-form/asana-import-project-form.jade b/app/modules/projects/create/asana-import/asana-import-project-form/asana-import-project-form.jade new file mode 100644 index 00000000..681f9f1c --- /dev/null +++ b/app/modules/projects/create/asana-import/asana-import-project-form/asana-import-project-form.jade @@ -0,0 +1,63 @@ +.import-project-asana-form + div(ng-include="'projects/create/import/import-header.html'") + + .spin(tg-loading="vm.fetchingUsers") + + form( + ng-if="!vm.fetchingUsers", + name="projectForm", + ng-submit="vm.saveForm()" + ) + div(ng-include="'projects/create/import-project-form-common/name.html'") + div(ng-include="'projects/create/import-project-form-common/description.html'") + .create-project-import-type(role="group") + fieldset + input( + type="radio" + name="project_type" + id="template-scrum" + data-required="true" + aria-hidden="true" + ng-value="'scrum'" + ng-model="vm.projectForm.project_type" + required + ) + label(for="template-scrum") + tg-svg(svg-icon="icon-scrum") + span(translate="PROJECT.IMPORT.ASANA.SCRUM_PROJECT") + fieldset + input( + type="radio" + name="project_type" + id="template-kanban" + data-required="true" + aria-hidden="true" + ng-value="'kanban'" + ng-model="vm.projectForm.project_type" + required + ) + label(for="template-kanban") + tg-svg(svg-icon="icon-kanban") + span(translate="PROJECT.IMPORT.ASANA.KANBAN_PROJECT") + + p.create-project-import-type-info( + ng-if="vm.projectForm.project_type == 'scrum'" + translate='PROJECT.IMPORT.ASANA.CREATE_AS_SCRUM_DESCRIPTION' + ) + p.create-project-import-type-info( + ng-if="vm.projectForm.project_type == 'kanban'" + translate='PROJECT.IMPORT.ASANA.CREATE_AS_KANBAN_DESCRIPTION' + ) + div(ng-include="'projects/create/import-project-form-common/project-privacy.html'") + tg-create-project-restrictions( + is-private="vm.projectForm.is_private" + can-create-public-projects="vm.canCreatePublicProjects" + can-create-private-projects="vm.canCreatePrivateProjects" + ) + tg-create-project-members-restrictions( + is-private="vm.projectForm.is_private" + limit-members-private-project="vm.limitMembersPrivateProject" + limit-members-public-project="vm.limitMembersPublicProject" + ) + div(ng-include="'projects/create/import-project-form-common/links.html'") + div(ng-include="'projects/create/import-project-form-common/actions.html'") diff --git a/app/modules/projects/create/asana-import/asana-import-project-form/asana-import-project-form.scss b/app/modules/projects/create/asana-import/asana-import-project-form/asana-import-project-form.scss new file mode 100644 index 00000000..e31c798c --- /dev/null +++ b/app/modules/projects/create/asana-import/asana-import-project-form/asana-import-project-form.scss @@ -0,0 +1,57 @@ +.import-project-asana-form { + @include create-project; +} + +.create-project-asana-import-type { + margin-bottom: 1rem; + text-align: center; + + &-question { + align-content: stretch; + align-items: stretch; + display: flex; + } + + fieldset { + background: $white; + border-right: 1px solid $whitish; + transition: background .2s linear; + + &:last-child { + border: 0; + } + } + + input { + display: none; + + &:checked { + +label { + background: rgba($primary, .1); + } + } + } + + label { + background: $white; + height: 100%; + padding: 1rem; + transition: background .2s ease-in; + + &:hover { + background: rgba($primary, .1); + cursor: pointer; + } + } + + &-name { + @include font-type(normal); + display: inline-block; + margin-bottom: .5rem; + } + + &-description { + @include font-type(light); + @include font-size(small); + } +} diff --git a/app/modules/projects/create/asana-import/asana-import.controller.coffee b/app/modules/projects/create/asana-import/asana-import.controller.coffee new file mode 100644 index 00000000..139d62b9 --- /dev/null +++ b/app/modules/projects/create/asana-import/asana-import.controller.coffee @@ -0,0 +1,73 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: asana-import.controller.coffee +### + +class AsanaImportController + @.$inject = [ + 'tgAsanaImportService', + '$tgConfirm', + '$translate', + 'tgImportProjectService', + ] + + constructor: (@asanaImportService, @confirm, @translate, @importProjectService) -> + @.step = 'autorization-asana' + @.project = null + taiga.defineImmutableProperty @, 'projects', () => return @asanaImportService.projects + taiga.defineImmutableProperty @, 'members', () => return @asanaImportService.projectUsers + + startProjectSelector: () -> + @.step = 'project-select-asana' + @asanaImportService.fetchProjects() + + onSelectProject: (project) -> + @.step = 'project-form-asana' + @.project = project + @.fetchingUsers = true + + @asanaImportService.fetchUsers(@.project.get('id')).then () => @.fetchingUsers = false + + onSaveProjectDetails: (project) -> + @.project = project + @.step = 'project-members-asana' + + onCancelMemberSelection: () -> + @.step = 'project-form-asana' + + startImport: (users) -> + loader = @confirm.loader(@translate.instant('PROJECT.IMPORT.IN_PROGRESS.TITLE'), @translate.instant('PROJECT.IMPORT.IN_PROGRESS.DESCRIPTION'), true) + + loader.start() + + promise = @asanaImportService.importProject( + @.project.get('name'), + @.project.get('description'), + @.project.get('id'), + users, + @.project.get('keepExternalReference'), + @.project.get('is_private') + @.project.get('project_type') + ) + + @importProjectService.importPromise(promise).then () => loader.stop() + + submitUserSelection: (users) -> + @.startImport(users) + return null + +angular.module('taigaProjects').controller('AsanaImportCtrl', AsanaImportController) diff --git a/app/modules/projects/create/asana-import/asana-import.controller.spec.coffee b/app/modules/projects/create/asana-import/asana-import.controller.spec.coffee new file mode 100644 index 00000000..49720ae1 --- /dev/null +++ b/app/modules/projects/create/asana-import/asana-import.controller.spec.coffee @@ -0,0 +1,172 @@ +### +# Copyright (C) 2014-2015 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: asana-import.controller.spec.coffee +### + +describe "AsanaImportCtrl", -> + $provide = null + $controller = null + mocks = {} + + _mockCurrentUserService = -> + mocks.currentUserService = { + canAddMembersPrivateProject: sinon.stub() + canAddMembersPublicProject: sinon.stub() + } + + $provide.value("tgCurrentUserService", mocks.currentUserService) + + _mockAsanaImportService = -> + mocks.asanaService = { + fetchProjects: sinon.stub(), + fetchUsers: sinon.stub(), + importProject: sinon.stub() + } + + $provide.value("tgAsanaImportService", mocks.asanaService) + + _mockImportProjectService = -> + mocks.importProjectService = { + importPromise: sinon.stub() + } + + $provide.value("tgImportProjectService", mocks.importProjectService) + + _mockConfirm = -> + mocks.confirm = { + loader: sinon.stub() + } + + $provide.value("$tgConfirm", mocks.confirm) + + _mockTranslate = -> + mocks.translate = { + instant: sinon.stub() + } + + $provide.value("$translate", mocks.translate) + + _mocks = -> + module (_$provide_) -> + $provide = _$provide_ + + _mockAsanaImportService() + _mockConfirm() + _mockTranslate() + _mockImportProjectService() + _mockCurrentUserService() + + return null + + _inject = -> + inject (_$controller_) -> + $controller = _$controller_ + + _setup = -> + _mocks() + _inject() + + beforeEach -> + module "taigaProjects" + + _setup() + + it "start project selector", () -> + ctrl = $controller("AsanaImportCtrl") + ctrl.startProjectSelector() + + expect(ctrl.step).to.be.equal('project-select-asana') + expect(mocks.asanaService.fetchProjects).have.been.called + + it "on select project reload projects", (done) -> + project = Immutable.fromJS({ + id: 1, + name: "project-name" + }) + + mocks.asanaService.fetchUsers.promise().resolve() + + ctrl = $controller("AsanaImportCtrl") + + promise = ctrl.onSelectProject(project) + + expect(ctrl.fetchingUsers).to.be.true + + promise.then () -> + expect(ctrl.fetchingUsers).to.be.false + expect(ctrl.step).to.be.equal('project-form-asana') + expect(ctrl.project).to.be.equal(project) + done() + + it "on save project details reload users", () -> + project = Immutable.fromJS({ + id: 1, + name: "project-name" + }) + + ctrl = $controller("AsanaImportCtrl") + ctrl.onSaveProjectDetails(project) + + expect(ctrl.step).to.be.equal('project-members-asana') + expect(ctrl.project).to.be.equal(project) + + it "on select user init import", (done) -> + users = Immutable.fromJS([ + { + id: 0 + }, + { + id: 1 + }, + { + id: 2 + } + ]) + + loaderObj = { + start: sinon.spy(), + update: sinon.stub(), + stop: sinon.spy() + } + + projectResult = { + id: 3, + name: "name" + } + + mocks.confirm.loader.returns(loaderObj) + + mocks.importProjectService.importPromise.promise().resolve() + + ctrl = $controller("AsanaImportCtrl") + ctrl.project = Immutable.fromJS({ + id: 1, + name: 'project-name', + description: 'project-description', + keepExternalReference: false, + is_private: true + }) + + + mocks.asanaService.importProject.promise().resolve(projectResult) + + ctrl.startImport(users).then () -> + expect(loaderObj.start).have.been.called + expect(loaderObj.stop).have.been.called + expect(mocks.asanaService.importProject).have.been.calledWith('project-name', 'project-description', 1, users, false, true) + + done() diff --git a/app/modules/projects/create/asana-import/asana-import.directive.coffee b/app/modules/projects/create/asana-import/asana-import.directive.coffee new file mode 100644 index 00000000..a8b0b40d --- /dev/null +++ b/app/modules/projects/create/asana-import/asana-import.directive.coffee @@ -0,0 +1,35 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: asana-import.directive.coffee +### + +AsanaImportDirective = () -> + return { + link: (scope, elm, attrs, ctrl) -> + ctrl.startProjectSelector() + templateUrl:"projects/create/asana-import/asana-import.html", + controller: "AsanaImportCtrl", + controllerAs: "vm", + bindToController: true, + scope: { + onCancel: '&' + } + } + +AsanaImportDirective.$inject = [] + +angular.module("taigaProjects").directive("tgAsanaImport", AsanaImportDirective) diff --git a/app/modules/projects/create/asana-import/asana-import.jade b/app/modules/projects/create/asana-import/asana-import.jade new file mode 100644 index 00000000..f36a9614 --- /dev/null +++ b/app/modules/projects/create/asana-import/asana-import.jade @@ -0,0 +1,32 @@ +.create-project.import-project(ng-if="vm.step == 'autorization-asana'") + p autorization... + + +tg-import-project-selector( + logo="/#{v}/images/import-logos/asana.png" + search="{{ 'PROJECT.IMPORT.ASANA.CHOOSE_PROJECT' | translate }}" + no-projects-msg="{{ 'PROJECT.IMPORT.ASANA.NO_PROJECTS' | translate }}" + projects="vm.projects" + on-cancel="vm.onCancel()" + on-select-project="vm.onSelectProject(project)" + ng-if="vm.step == 'project-select-asana'" +) + +tg-asana-import-project-form( + ng-if="vm.step == 'project-form-asana'" + project="vm.project" + members="vm.members" + fetching-users="vm.fetchingUsers" + on-save-project-details="vm.onSaveProjectDetails(project)" + on-cancel-form="vm.step = 'project-select-asana'" +) + +tg-import-project-members( + ng-if="vm.step == 'project-members-asana'" + platform="Asana" + logo="/#{v}/images/import-logos/asana.png" + project="vm.project" + members="vm.members" + on-submit="vm.submitUserSelection(users)" + on-cancel="vm.onCancelMemberSelection()" +) diff --git a/app/modules/projects/create/asana-import/asana-import.service.coffee b/app/modules/projects/create/asana-import/asana-import.service.coffee new file mode 100644 index 00000000..7bfb88df --- /dev/null +++ b/app/modules/projects/create/asana-import/asana-import.service.coffee @@ -0,0 +1,57 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: asana-import.service.coffee +### + +class AsanaImportService extends taiga.Service + @.$inject = [ + 'tgResources', + '$location' + ] + + constructor: (@resources, @location) -> + @.projects = Immutable.List() + @.projectUsers = Immutable.List() + @.token = null + + setToken: (token) -> + @.token = token + + fetchProjects: () -> + @resources.asanaImporter.listProjects(@.token).then (projects) => @.projects = projects + + fetchUsers: (projectId) -> + @resources.asanaImporter.listUsers(@.token, projectId).then (users) => @.projectUsers = users + + importProject: (name, description, projectId, userBindings, keepExternalReference, isPrivate, projectType) -> + return @resources.asanaImporter.importProject(@.token, name, description, projectId, userBindings, keepExternalReference, isPrivate, projectType) + + getAuthUrl: () -> + return new Promise (resolve) => + @resources.asanaImporter.getAuthUrl().then (response) => + @.authUrl = response.data.url + resolve(@.authUrl) + + authorize: (code) -> + return new Promise (resolve, reject) => + @resources.asanaImporter.authorize(code).then ((response) => + @.token = response.data.token + resolve(@.token) + ), (error) -> + reject(new Error(error.status)) + +angular.module("taigaProjects").service("tgAsanaImportService", AsanaImportService) diff --git a/app/modules/projects/create/asana-import/asana-import.service.spec.coffee b/app/modules/projects/create/asana-import/asana-import.service.spec.coffee new file mode 100644 index 00000000..0574e582 --- /dev/null +++ b/app/modules/projects/create/asana-import/asana-import.service.spec.coffee @@ -0,0 +1,128 @@ +### +# Copyright (C) 2014-2015 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: asana-import.controller.spec.coffee +### + +describe "tgAsanaImportService", -> + $provide = null + service = null + mocks = {} + + _mockResources = -> + mocks.resources = { + asanaImporter: { + listProjects: sinon.stub(), + listUsers: sinon.stub(), + importProject: sinon.stub(), + getAuthUrl: sinon.stub(), + authorize: sinon.stub() + } + } + + $provide.value("tgResources", mocks.resources) + + _mockLocation = -> + mocks.location = { + search: sinon.stub() + } + + mocks.location.search.returns({ + from: 'asana' + token: 123 + }) + + $provide.value("$location", mocks.location) + + _mocks = -> + module (_$provide_) -> + $provide = _$provide_ + + _mockResources() + _mockLocation() + + return null + + _inject = -> + inject (_tgAsanaImportService_) -> + service = _tgAsanaImportService_ + + _setup = -> + _mocks() + _inject() + + beforeEach -> + module "taigaProjects" + + _setup() + + it "fetch projects", (done) -> + service.setToken(123) + mocks.resources.asanaImporter.listProjects.withArgs(123).promise().resolve('projects') + + service.fetchProjects().then () -> + service.projects = "projects" + done() + + it "fetch user", (done) -> + service.setToken(123) + projectId = 3 + mocks.resources.asanaImporter.listUsers.withArgs(123, projectId).promise().resolve('users') + + service.fetchUsers(projectId).then () -> + service.projectUsers = 'users' + done() + + it "import project", () -> + service.setToken(123) + projectId = 2 + + service.importProject(projectId, true, true ,true) + + expect(mocks.resources.asanaImporter.importProject).to.have.been.calledWith(123, projectId, true, true, true) + + it "get auth url", (done) -> + service.setToken(123) + projectId = 3 + + response = { + data: { + url: "url123" + } + } + + mocks.resources.asanaImporter.getAuthUrl.promise().resolve(response) + + service.getAuthUrl().then (url) -> + expect(url).to.be.equal("url123") + done() + + it "authorize", (done) -> + service.setToken(123) + projectId = 3 + verifyCode = 12345 + + response = { + data: { + token: "token123" + } + } + + mocks.resources.asanaImporter.authorize.withArgs(verifyCode).promise().resolve(response) + + service.authorize(verifyCode).then (token) -> + expect(token).to.be.equal("token123") + done() diff --git a/app/modules/projects/create/create-project-form/create-project-form.controller.coffee b/app/modules/projects/create/create-project-form/create-project-form.controller.coffee new file mode 100644 index 00000000..1632f7a6 --- /dev/null +++ b/app/modules/projects/create/create-project-form/create-project-form.controller.coffee @@ -0,0 +1,63 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: create-project-form.controller.coffee +### + +class CreatetProjectFormController + @.$inject = [ + "tgCurrentUserService", + "tgProjectsService", + "$projectUrl", + "$location", + "$tgNavUrls" + ] + + constructor: (@currentUserService, @projectsService, @projectUrl, @location, @navUrls) -> + @.projectForm = { + is_private: false + } + + @.canCreatePublicProjects = @currentUserService.canCreatePublicProjects() + @.canCreatePrivateProjects = @currentUserService.canCreatePrivateProjects() + + if !@.canCreatePublicProjects.valid && @.canCreatePrivateProjects.valid + @.projectForm.is_private = true + + if @.type == 'scrum' + @.projectForm.creation_template = 1 + else + @.projectForm.creation_template = 2 + + submit: () -> + @.formSubmitLoading = true + + @projectsService.create(@.projectForm).then (project) => + @location.url(@projectUrl.get(project)) + + onCancelForm: () -> + @location.path(@navUrls.resolve("create-project")) + + canCreateProject: () -> + if @.projectForm.is_private + return @.canCreatePrivateProjects.valid + else + return @.canCreatePublicProjects.valid + + isDisabled: () -> + return @.formSubmitLoading || !@.canCreateProject() + +angular.module('taigaProjects').controller('CreateProjectFormCtrl', CreatetProjectFormController) diff --git a/app/modules/projects/create/create-project-form/create-project-form.controller.spec.coffee b/app/modules/projects/create/create-project-form/create-project-form.controller.spec.coffee new file mode 100644 index 00000000..bc68c788 --- /dev/null +++ b/app/modules/projects/create/create-project-form/create-project-form.controller.spec.coffee @@ -0,0 +1,139 @@ +### +# Copyright (C) 2014-2015 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: create-project-form.controller.spec.coffee +### + +describe "CreateProjectFormCtrl", -> + $provide = null + $controller = null + mocks = {} + + _mockNavUrlsService = -> + mocks.navUrls = { + resolve: sinon.stub() + } + + $provide.value("$tgNavUrls", mocks.navUrls) + + _mockCurrentUserService = -> + mocks.currentUserService = { + canCreatePublicProjects: sinon.stub().returns({valid: true}), + canCreatePrivateProjects: sinon.stub().returns({valid: true}) + } + + $provide.value("tgCurrentUserService", mocks.currentUserService) + + _mockProjectsService = -> + mocks.projectsService = { + create: sinon.stub() + } + + $provide.value("tgProjectsService", mocks.projectsService) + + _mockProjectUrl = -> + mocks.projectUrl = { + get: sinon.stub() + } + + $provide.value("$projectUrl", mocks.projectUrl) + + _mockLocation = -> + mocks.location = { + url: sinon.stub() + } + + $provide.value("$location", mocks.location) + + _mocks = -> + module (_$provide_) -> + $provide = _$provide_ + + _mockCurrentUserService() + _mockProjectsService() + _mockProjectUrl() + _mockLocation() + _mockNavUrlsService() + + return null + + _inject = -> + inject (_$controller_) -> + $controller = _$controller_ + + _setup = -> + _mocks() + _inject() + + beforeEach -> + module "taigaProjects" + + _setup() + + it "submit project form", () -> + ctrl = $controller("CreateProjectFormCtrl") + + ctrl.projectForm = 'form' + + mocks.projectsService.create.withArgs('form').promise().resolve('project1') + mocks.projectUrl.get.returns('project-url') + + ctrl.submit().then () -> + expect(ctrl.formSubmitLoading).to.be.true + + expect(mocks.location.url).to.have.been.calledWith('project-url') + + it 'check if the user can create a private projects', () -> + mocks.currentUserService.canCreatePrivateProjects = sinon.stub().returns({valid: true}) + + ctrl = $controller("CreateProjectFormCtrl") + + ctrl.projectForm = { + is_private: true + } + + expect(ctrl.canCreateProject()).to.be.true + + mocks.currentUserService.canCreatePrivateProjects = sinon.stub().returns({valid: false}) + + ctrl = $controller("CreateProjectFormCtrl") + + ctrl.projectForm = { + is_private: true + } + + expect(ctrl.canCreateProject()).to.be.false + + it 'check if the user can create a public projects', () -> + mocks.currentUserService.canCreatePublicProjects = sinon.stub().returns({valid: true}) + + ctrl = $controller("CreateProjectFormCtrl") + + ctrl.projectForm = { + is_private: false + } + + expect(ctrl.canCreateProject()).to.be.true + + mocks.currentUserService.canCreatePublicProjects = sinon.stub().returns({valid: false}) + + ctrl = $controller("CreateProjectFormCtrl") + + ctrl.projectForm = { + is_private: false + } + + expect(ctrl.canCreateProject()).to.be.false diff --git a/app/modules/projects/create/create-project-form/create-project-form.directive.coffee b/app/modules/projects/create/create-project-form/create-project-form.directive.coffee new file mode 100644 index 00000000..f462ce5f --- /dev/null +++ b/app/modules/projects/create/create-project-form/create-project-form.directive.coffee @@ -0,0 +1,31 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: create-project-form.directive.coffee +### + +CreateProjectFormDirective = () -> + return { + templateUrl:"projects/create/create-project-form/create-project-form.html", + controller: "CreateProjectFormCtrl", + controllerAs: "vm", + bindToController: true, + scope: { + type: '@' + } + } + +angular.module("taigaProjects").directive("tgCreateProjectForm", CreateProjectFormDirective) diff --git a/app/modules/projects/create/create-project-form/create-project-form.jade b/app/modules/projects/create/create-project-form/create-project-form.jade new file mode 100644 index 00000000..31c0c01c --- /dev/null +++ b/app/modules/projects/create/create-project-form/create-project-form.jade @@ -0,0 +1,32 @@ +.create-project + .create-project-title-wrapper(ng-if="vm.type == 'scrum'") + tg-svg(svg-icon="icon-scrum") + h1.create-project-title(translate="PROJECT.CREATE.TEMPLATE_SCRUM") + h3.create-project-description( + ng-if="vm.type == 'scrum'" + translate="PROJECT.CREATE.TEMPLATE_SCRUM_DESC" + ) + + .create-project-title-wrapper(ng-if="vm.type == 'kanban'") + tg-svg(svg-icon="icon-kanban") + h1.create-project-title(translate="PROJECT.CREATE.TEMPLATE_KANBAN") + h3.create-project-description( + ng-if="vm.type == 'kanban'" + translate="PROJECT.CREATE.TEMPLATE_KANBAN_DESC" + ) + + form( + name="projectForm", + ng-submit="vm.submit()" + ) + div(ng-include="'projects/create/import-project-form-common/name.html'") + div(ng-include="'projects/create/import-project-form-common/description.html'") + div(ng-include="'projects/create/import-project-form-common/project-privacy.html'") + + tg-create-project-restrictions( + is-private="vm.projectForm.is_private" + can-create-public-projects="vm.canCreatePublicProjects" + can-create-private-projects="vm.canCreatePrivateProjects" + ) + + div(ng-include="'projects/create/import-project-form-common/actions.html'") diff --git a/app/modules/projects/create/create-project-members-restrictions/create-project-members-restrictions.directive.coffee b/app/modules/projects/create/create-project-members-restrictions/create-project-members-restrictions.directive.coffee new file mode 100644 index 00000000..da6d0c90 --- /dev/null +++ b/app/modules/projects/create/create-project-members-restrictions/create-project-members-restrictions.directive.coffee @@ -0,0 +1,13 @@ +module = angular.module("taigaProject") + +createProjectMembersRestrictionsDirective = () -> + return { + scope: { + isPrivate: '=', + limitMembersPrivateProject: '=', + limitMembersPublicProject: '=' + }, + templateUrl: "projects/create/create-project-members-restrictions/create-project-members-restrictions.html" + } + +module.directive('tgCreateProjectMembersRestrictions', [createProjectMembersRestrictionsDirective]) diff --git a/app/modules/projects/create/create-project-members-restrictions/create-project-members-restrictions.jade b/app/modules/projects/create/create-project-members-restrictions/create-project-members-restrictions.jade new file mode 100644 index 00000000..c65b9d6e --- /dev/null +++ b/app/modules/projects/create/create-project-members-restrictions/create-project-members-restrictions.jade @@ -0,0 +1,13 @@ +div.create-project-warning(ng-if="!limitMembersPublicProject.valid && !isPrivate") + tg-svg(svg-icon="icon-exclamation") + span( + translate="PROJECT.IMPORT.PROJECT_RESTRICTIONS.PROJECT_MEMBERS_DESC_PUBLIC", + translate-values="{'members': limitMembersPublicProject.current, 'max_memberships': limitMembersPublicProject.max}" + ) + +div.create-project-warning(ng-if="!limitMembersPrivateProject.valid && isPrivate") + tg-svg(svg-icon="icon-exclamation") + span( + translate="PROJECT.IMPORT.PROJECT_RESTRICTIONS.PROJECT_MEMBERS_DESC_PRIVATE", + translate-values="{'members': limitMembersPrivateProject.current, 'max_memberships': limitMembersPrivateProject.max}" + ) \ No newline at end of file diff --git a/app/modules/projects/create/create-project-restrictions/create-project-restrictions.directive.coffee b/app/modules/projects/create/create-project-restrictions/create-project-restrictions.directive.coffee new file mode 100644 index 00000000..e825a916 --- /dev/null +++ b/app/modules/projects/create/create-project-restrictions/create-project-restrictions.directive.coffee @@ -0,0 +1,13 @@ +module = angular.module("taigaProject") + +createProjectRestrictionsDirective = () -> + return { + scope: { + isPrivate: '=', + canCreatePrivateProjects: '=', + canCreatePublicProjects: '=' + }, + templateUrl: "projects/create/create-project-restrictions/create-project-restrictions.html" + } + +module.directive('tgCreateProjectRestrictions', [createProjectRestrictionsDirective]) diff --git a/app/modules/projects/create/create-project-restrictions/create-project-restrictions.jade b/app/modules/projects/create/create-project-restrictions/create-project-restrictions.jade new file mode 100644 index 00000000..4121ac01 --- /dev/null +++ b/app/modules/projects/create/create-project-restrictions/create-project-restrictions.jade @@ -0,0 +1,11 @@ +.create-project-warning( + ng-if="isPrivate && !canCreatePrivateProjects.valid && canCreatePrivateProjects.reason == 'max_private_projects'" +) + tg-svg(svg-icon="icon-exclamation") + span {{ 'PROJECT.CREATE.MAX_PRIVATE_PROJECTS' | translate }} + +.create-project-warning( + ng-if="!isPrivate && !canCreatePublicProjects.valid && canCreatePublicProjects.reason == 'max_public_projects'" +) + tg-svg(svg-icon="icon-exclamation") + span {{ 'PROJECT.CREATE.MAX_PUBLIC_PROJECTS' | translate }} diff --git a/app/modules/projects/create/create-project.controller.coffee b/app/modules/projects/create/create-project.controller.coffee new file mode 100644 index 00000000..d77903c8 --- /dev/null +++ b/app/modules/projects/create/create-project.controller.coffee @@ -0,0 +1,56 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: project.controller.coffee +### + +class CreateProjectController + @.$inject = [ + "tgAppMetaService", + "$translate", + "tgProjectService", + "$location" + ] + + constructor: (@appMetaService, @translate, @projectService, @location) -> + taiga.defineImmutableProperty @, "project", () => return @projectService.project + + @appMetaService.setfn @._setMeta.bind(this) + + @.displayScrumDesc = false + @.displayKanbanDesc = false + + _setMeta: () -> + return null if !@.project + + ctx = {projectName: @.project.get("name")} + + return { + title: @translate.instant("PROJECT.PAGE_TITLE", ctx) + description: @.project.get("description") + } + + displayHelp: (type, $event) -> + $event.stopPropagation() + $event.preventDefault() + + if type == 'scrum' + @.displayScrumDesc = !@.displayScrumDesc + if type == 'kanban' + @.displayKanbanDesc = !@.displayKanbanDesc + + +angular.module("taigaProjects").controller("CreateProjectCtrl", CreateProjectController) diff --git a/app/modules/projects/create/create-project.controller.spec.coffee b/app/modules/projects/create/create-project.controller.spec.coffee new file mode 100644 index 00000000..fc3faadc --- /dev/null +++ b/app/modules/projects/create/create-project.controller.spec.coffee @@ -0,0 +1,45 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: create-project.controller.spec.coffee +### + +describe "CreateProjectController", -> + provide = null + controller = null + mocks = {} + + _inject = (callback) -> + inject (_$controller_, _$q_, _$rootScope_) -> + controller = _$controller_ + + beforeEach -> + module "taigaProjects" + _inject() + + # it "get Home Step", () -> + # ctrl = controller "CreateProjectCtrl" + # ctrl.inDefaultStep = true + # ctrl.getStep('home') + # expect(ctrl.inDefaultStep).to.be.true + # expect(ctrl.inStepDuplicateProject).to.be.false + # + # it "get Duplicate Project Step", () -> + # ctrl = controller "CreateProjectCtrl" + # ctrl.inDefaultStep = true + # ctrl.getStep('duplicate') + # expect(ctrl.inDefaultStep).to.be.false + # expect(ctrl.inStepDuplicateProject).to.be.true diff --git a/app/modules/projects/create/create-project.jade b/app/modules/projects/create/create-project.jade new file mode 100644 index 00000000..2fdc47de --- /dev/null +++ b/app/modules/projects/create/create-project.jade @@ -0,0 +1,69 @@ +.create-project + .create-project-wrapper + h1.create-project-title(translate="PROJECT.CREATE.TITLE") + h3.create-project-description(translate="PROJECT.CREATE.CHOOSE_TEMPLATE") + ul.create-project-selector.e2e-create-project-selector + li + a.e2e-create-project-scrum( + title="{{'PROJECT.CREATE.TEMPLATE_SCRUM' | translate}}", + tg-nav="create-project-scrum" + href="" + ) + .create-project-selector-icon + tg-svg(svg-icon="icon-scrum") + .create-project-selector-template-wrapper + p.create-project-selector-template(translate="PROJECT.CREATE.TEMPLATE_SCRUM") + p.create-project-selector-description(translate="PROJECT.CREATE.TEMPLATE_SCRUM_DESC") + .create-project-selector-question + tg-svg( + svg-icon="icon-question" + ng-click="vm.displayHelp('scrum', $event)" + ) + .create-project-selector-long-description(ng-show="vm.displayScrumDesc") + p(translate="PROJECT.CREATE.TEMPLATE_SCRUM_LONGDESC") + li + a.e2e-create-project-kanban( + tg-nav="create-project-kanban" + title="{{'PROJECT.CREATE.TEMPLATE_KANBAN' | translate}}", + href="" + ) + .create-project-selector-icon + tg-svg(svg-icon="icon-kanban") + + .create-project-selector-template-wrapper + p.create-project-selector-template(translate="PROJECT.CREATE.TEMPLATE_KANBAN") + p.create-project-selector-description(translate="PROJECT.CREATE.TEMPLATE_KANBAN_DESC") + .create-project-selector-question + tg-svg( + svg-icon="icon-question" + ng-click="vm.displayHelp('kanban', $event)" + ) + .create-project-selector-long-description(ng-show="vm.displayKanbanDesc") + p(translate="PROJECT.CREATE.TEMPLATE_KANBAN_LONGDESC") + li + a.e2e-duplicate-project( + tg-nav="create-project-duplicate" + title="{{'PROJECT.CREATE.DUPLICATE' | translate}}", + href="" + ) + .create-project-selector-icon + tg-svg(svg-icon="icon-duplicate") + .create-project-selector-template-wrapper + p.create-project-selector-template(translate="PROJECT.CREATE.DUPLICATE") + p.create-project-selector-description(translate="PROJECT.CREATE.DUPLICATE_DESC") + + li + a( + tg-nav="create-project-import" + title="{{'PROJECT.CREATE.IMPORT' | translate}}", + href="" + ) + .create-project-selector-icon + tg-svg(svg-icon="icon-upload") + .create-project-selector-template-wrapper + p.create-project-selector-template( + href="#" + title="{{'PROJECT.CREATE.IMPORT' | translate}}", + translate="PROJECT.CREATE.IMPORT" + ) + p.create-project-selector-description(translate="PROJECT.CREATE.IMPORT_DESC") diff --git a/app/modules/projects/create/create-project.scss b/app/modules/projects/create/create-project.scss new file mode 100644 index 00000000..9d120830 --- /dev/null +++ b/app/modules/projects/create/create-project.scss @@ -0,0 +1,3 @@ +.create-project { + @include create-project; +} diff --git a/app/modules/projects/create/duplicate/duplicate-project.controller.coffee b/app/modules/projects/create/duplicate/duplicate-project.controller.coffee new file mode 100644 index 00000000..7395a941 --- /dev/null +++ b/app/modules/projects/create/duplicate/duplicate-project.controller.coffee @@ -0,0 +1,86 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: project.controller.coffee +### + +class DuplicateProjectController + @.$inject = [ + "tgCurrentUserService", + "tgProjectsService", + "$tgLocation", + "$tgNavUrls" + ] + + constructor: (@currentUserService, @projectsService, @location, @navUrls) -> + @.user = @currentUserService.getUser() + @.members = Immutable.List() + + @.canCreatePublicProjects = @currentUserService.canCreatePublicProjects() + @.canCreatePrivateProjects = @currentUserService.canCreatePrivateProjects() + + taiga.defineImmutableProperty @, 'projects', () => @currentUserService.projects.get("all") + + @.projectForm = { + is_private: false + } + + if !@.canCreatePublicProjects.valid && @.canCreatePrivateProjects.valid + @.projectForm.is_private = true + + refreshReferenceProject: (slug) -> + @projectsService.getProjectBySlug(slug).then (project) => + @.referenceProject = project + @.members = project.get('members').filter (it) => return it.get('id') != @.user.get('id') + @.invitedMembers = @.members.map (it) -> return it.get('id') + @.checkUsersLimit() + + toggleInvitedMember: (member) -> + if @.invitedMembers.includes(member) + @.invitedMembers = @.invitedMembers.filter (it) -> it != member + else + @.invitedMembers = @.invitedMembers.push(member) + + @.checkUsersLimit() + + checkUsersLimit: () -> + @.limitMembersPrivateProject = @currentUserService.canAddMembersPrivateProject(@.invitedMembers.size + 1) + @.limitMembersPublicProject = @currentUserService.canAddMembersPublicProject(@.invitedMembers.size + 1) + + submit: () -> + projectId = @.referenceProject.get('id') + data = @.projectForm + data.users = @.invitedMembers + + @.formSubmitLoading = true + @projectsService.duplicate(projectId, data).then (newProject) => + @.formSubmitLoading = false + @location.path(@navUrls.resolve("project", {project: newProject.data.slug})) + @currentUserService.loadProjects() + + canCreateProject: () -> + if @.projectForm.is_private + return @.canCreatePrivateProjects.valid && @.limitMembersPrivateProject.valid + else + return @.canCreatePublicProjects.valid && @.limitMembersPublicProject.valid + + isDisabled: () -> + return @.formSubmitLoading || !@.canCreateProject() + + onCancelForm: () -> + @location.path(@navUrls.resolve("create-project")) + +angular.module("taigaProjects").controller("DuplicateProjectCtrl", DuplicateProjectController) diff --git a/app/modules/projects/create/duplicate/duplicate-project.controller.spec.coffee b/app/modules/projects/create/duplicate/duplicate-project.controller.spec.coffee new file mode 100644 index 00000000..dc06e995 --- /dev/null +++ b/app/modules/projects/create/duplicate/duplicate-project.controller.spec.coffee @@ -0,0 +1,226 @@ +### +# Copyright (C) 2014-2015 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: home.controller.spec.coffee +### + +describe "DuplicateProjectController", -> + ctrl = null + provide = null + controller = null + mocks = {} + + _mockCurrentUserService = () -> + mocks.currentUserService = {} + mocks.currentUserService.getUser = sinon.stub() + mocks.currentUserService.canCreatePublicProjects = sinon.stub().returns(true) + mocks.currentUserService.canCreatePrivateProjects = sinon.stub().returns(true) + + mocks.currentUserService.projects = {} + mocks.currentUserService.projects.get = sinon.stub().returns([]) + + mocks.currentUserService.loadProjects = sinon.stub() + + mocks.currentUserService.canAddMembersPrivateProject = sinon.stub() + mocks.currentUserService.canAddMembersPublicProject = sinon.stub() + + provide.value "tgCurrentUserService", mocks.currentUserService + + _mockProjectService = () -> + mocks.projectsService = {} + mocks.projectsService.getProjectBySlug = sinon.stub() + mocks.projectsService.duplicate = sinon.stub() + + provide.value "tgProjectsService", mocks.projectsService + + _mockLocation = () -> + mocks.location = { + path: sinon.stub() + } + provide.value "$tgLocation", mocks.location + + _mockTgNav = () -> + mocks.urlservice = { + resolve: sinon.stub() + } + provide.value "$tgNavUrls", mocks.urlservice + + _mocks = () -> + module ($provide) -> + provide = $provide + _mockCurrentUserService() + _mockProjectService() + _mockLocation() + _mockTgNav() + + return null + + beforeEach -> + module "taigaProjects" + + _mocks() + + inject ($controller) -> + controller = $controller + + ctrl = controller "DuplicateProjectCtrl" + + ctrl.projects = Immutable.fromJS([ + { + id: 1 + }, + { + id: 2 + } + ]) + + ctrl.user = Immutable.fromJS([ + { + id: 1 + } + ]) + + ctrl.canCreatePublicProjects = mocks.currentUserService.canCreatePublicProjects() + ctrl.canCreatePrivateProjects = mocks.currentUserService.canCreatePublicProjects() + ctrl.projectForm = {} + + it "toggle invited Member", () -> + ctrl = controller "DuplicateProjectCtrl" + + ctrl.invitedMembers = Immutable.List([1, 2, 3]) + ctrl.checkUsersLimit = sinon.spy() + + ctrl.toggleInvitedMember(2) + + expect(ctrl.invitedMembers.toJS()).to.be.eql([1, 3]) + + ctrl.toggleInvitedMember(5) + + expect(ctrl.invitedMembers.toJS()).to.be.eql([1, 3, 5]) + + expect(ctrl.checkUsersLimit).to.have.been.called + + it "get project to duplicate", () -> + project = Immutable.fromJS({ + members: [ + {id: 1}, + {id: 2}, + {id: 3} + ] + }) + + slug = 'slug' + ctrl._getInvitedMembers = sinon.stub() + + promise = mocks.projectsService.getProjectBySlug.withArgs(slug).promise().resolve(project) + + ctrl.refreshReferenceProject(slug).then () -> + expect(ctrl.referenceProject).to.be.equal(project) + expect(ctrl.members.toJS()).to.be.eql(project.get('members').toJS()) + expect(ctrl.invitedMembers.toJS()).to.be.eql([1, 2, 3]) + + it 'check users limits', () -> + mocks.currentUserService.canAddMembersPrivateProject.withArgs(4).returns(1) + mocks.currentUserService.canAddMembersPublicProject.withArgs(4).returns(2) + + members = Immutable.fromJS([ + {id: 1}, + {id: 2}, + {id: 3} + ]) + size = members.size #3 + + ctrl.user = Immutable.fromJS({ + max_memberships_public_projects: 1 + max_memberships_private_projects: 1 + }) + + ctrl.projectForm = {} + ctrl.projectForm.is_private = false + ctrl.invitedMembers = members + + ctrl.checkUsersLimit() + expect(ctrl.limitMembersPrivateProject).to.be.equal(1) + expect(ctrl.limitMembersPublicProject).to.be.equal(2) + + it 'duplicate project', (done) -> + ctrl.referenceProject = Immutable.fromJS({ + id: 1 + }) + ctrl.projectForm = Immutable.fromJS({ + id: 1 + }) + projectId = ctrl.referenceProject.get('id') + data = ctrl.projectForm + + newProject = {} + newProject.data = { + slug: 'slug' + } + + mocks.urlservice.resolve.withArgs("project", {project: newProject.data.slug}).returns("/project/slug/") + + promise = mocks.projectsService.duplicate.withArgs(projectId, data).promise().resolve(newProject) + + ctrl.submit().then () -> + expect(ctrl.formSubmitLoading).to.be.false + expect(mocks.location.path).to.be.calledWith("/project/slug/") + expect(mocks.currentUserService.loadProjects).to.have.been.called + done() + + it 'check if the user can create a private projects', () -> + mocks.currentUserService.canCreatePrivateProjects = sinon.stub().returns({valid: true}) + + ctrl = controller "DuplicateProjectCtrl" + ctrl.limitMembersPrivateProject = {valid: true} + + ctrl.projectForm = { + is_private: true + } + + expect(ctrl.canCreateProject()).to.be.true + + mocks.currentUserService.canCreatePrivateProjects = sinon.stub().returns({valid: false}) + + ctrl = controller "DuplicateProjectCtrl" + + ctrl.projectForm = { + is_private: true + } + + expect(ctrl.canCreateProject()).to.be.false + + it 'check if the user can create a public projects', () -> + mocks.currentUserService.canCreatePublicProjects = sinon.stub().returns({valid: true}) + + ctrl = controller "DuplicateProjectCtrl" + ctrl.limitMembersPublicProject = {valid: true} + + ctrl.projectForm = { + is_private: false + } + + expect(ctrl.canCreateProject()).to.be.true + + mocks.currentUserService.canCreatePublicProjects = sinon.stub().returns({valid: false}) + + ctrl = controller "DuplicateProjectCtrl" + + ctrl.projectForm = { + is_private: false + } + + expect(ctrl.canCreateProject()).to.be.false diff --git a/app/modules/projects/create/duplicate/duplicate-project.directive.coffee b/app/modules/projects/create/duplicate/duplicate-project.directive.coffee new file mode 100644 index 00000000..4a90babc --- /dev/null +++ b/app/modules/projects/create/duplicate/duplicate-project.directive.coffee @@ -0,0 +1,35 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: duplicate-project.directive.coffee +### + +DuplicateProjectDirective = () -> + + link = (scope, el, attr, ctrl) -> + + return { + link: link, + templateUrl:"projects/create/duplicate/duplicate-project.html", + controller: "DuplicateProjectCtrl", + controllerAs: "vm", + bindToController: true, + scope: {} + } + +DuplicateProjectDirective.$inject = [] + +angular.module("taigaProjects").directive("tgDuplicateProject", DuplicateProjectDirective) diff --git a/app/modules/projects/create/duplicate/duplicate-project.jade b/app/modules/projects/create/duplicate/duplicate-project.jade new file mode 100644 index 00000000..d90643fb --- /dev/null +++ b/app/modules/projects/create/duplicate/duplicate-project.jade @@ -0,0 +1,57 @@ +.create-project + h1.create-project-title(translate="PROJECT.DUPLICATE.TITLE") + h3.create-project-description(translate="PROJECT.DUPLICATE.DESCRIPTION") + form.duplicate-project.e2e-duplicate-project( + name="projectForm" + ng-submit="vm.submit()" + ) + fieldset.duplicate-project-reference.e2e-duplicate-project-reference + select( + ng-model="vm.projectForm.project" + ng-change="vm.refreshReferenceProject(vm.projectForm.project)" + data-required="true" + ng-options="p.slug as p.name for p in vm.projects | toMutable| filter:{blocked_code: '!'}" + id="project-selector-dropdown" + autofocus + ) + option( + value="" + disabled + selected + translate="PROJECT.DUPLICATE.SELECT_PLACEHOLDER" + ) + + div(ng-include="'projects/create/import-project-form-common/name.html'") + div(ng-include="'projects/create/import-project-form-common/description.html'") + + div(ng-include="'projects/create/import-project-form-common/project-privacy.html'") + tg-create-project-restrictions( + is-private="vm.projectForm.is_private" + can-create-public-projects="vm.canCreatePublicProjects" + can-create-private-projects="vm.canCreatePrivateProjects" + ) + + + label(ng-if="vm.invitedMembers") + span(translate="PROJECT.CREATE.INVITE") + span.mumble( + ng-if="vm.displayUserWarning" + translate="PROJECT.CREATE.SOLO_PROJECT" + ) + span.mumble(translate="PROJECT.CREATE.INVITE_LATER") + + tg-invite-members( + ng-if="vm.members.size" + members="vm.members" + invited-members="vm.invitedMembers" + on-toggle-invited-member="vm.toggleInvitedMember(member)" + ) + + tg-create-project-members-restrictions( + ng-if="vm.referenceProject" + is-private="vm.projectForm.is_private" + limit-members-private-project="vm.limitMembersPrivateProject" + limit-members-public-project="vm.limitMembersPublicProject" + ) + + div(ng-include="'projects/create/import-project-form-common/actions.html'") diff --git a/app/modules/projects/create/duplicate/duplicate-project.scss b/app/modules/projects/create/duplicate/duplicate-project.scss new file mode 100644 index 00000000..63384b32 --- /dev/null +++ b/app/modules/projects/create/duplicate/duplicate-project.scss @@ -0,0 +1,5 @@ +.duplicate-project { + &-reference { + margin-bottom: 2rem; + } +} diff --git a/app/modules/projects/create/github-import/github-import-project-form/github-import-project-form.controller.coffee b/app/modules/projects/create/github-import/github-import-project-form/github-import-project-form.controller.coffee new file mode 100644 index 00000000..f8559303 --- /dev/null +++ b/app/modules/projects/create/github-import/github-import-project-form/github-import-project-form.controller.coffee @@ -0,0 +1,56 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: github-import-project-form.controller.coffee +### + +class GithubImportProjectFormController + @.$inject = [ + "tgCurrentUserService" + ] + + constructor: (@currentUserService) -> + @.canCreatePublicProjects = @currentUserService.canCreatePublicProjects() + @.canCreatePrivateProjects = @currentUserService.canCreatePrivateProjects() + + @.projectForm = @.project.toJS() + + @.platformName = "Github" + @.projectForm.is_private = false + @.projectForm.keepExternalReference = false + @.projectForm.project_type = "kanban" + + if !@.canCreatePublicProjects.valid && @.canCreatePrivateProjects.valid + @.projectForm.is_private = true + + checkUsersLimit: () -> + @.limitMembersPrivateProject = @currentUserService.canAddMembersPrivateProject(@.members.size) + @.limitMembersPublicProject = @currentUserService.canAddMembersPublicProject(@.members.size) + + saveForm: () -> + @.onSaveProjectDetails({project: Immutable.fromJS(@.projectForm)}) + + canCreateProject: () -> + if @.projectForm.is_private + return @.canCreatePrivateProjects.valid + else + return @.canCreatePublicProjects.valid + + isDisabled: () -> + return !@.canCreateProject() + + +angular.module('taigaProjects').controller('GithubImportProjectFormCtrl', GithubImportProjectFormController) diff --git a/app/modules/projects/create/github-import/github-import-project-form/github-import-project-form.directive.coffee b/app/modules/projects/create/github-import/github-import-project-form/github-import-project-form.directive.coffee new file mode 100644 index 00000000..c619f254 --- /dev/null +++ b/app/modules/projects/create/github-import/github-import-project-form/github-import-project-form.directive.coffee @@ -0,0 +1,40 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: github-import-project-form.directive.coffee +### + +GithubImportProjectFormDirective = () -> + return { + link: (scope, elm, attr, ctrl) -> + scope.$watch('vm.members', ctrl.checkUsersLimit.bind(ctrl)) + + templateUrl:"projects/create/github-import/github-import-project-form/github-import-project-form.html", + controller: "GithubImportProjectFormCtrl", + controllerAs: "vm", + bindToController: true, + scope: { + members: '<', + project: '<', + onSaveProjectDetails: '&', + onCancelForm: '&', + fetchingUsers: '<' + } + } + +GithubImportProjectFormDirective.$inject = [] + +angular.module("taigaProjects").directive("tgGithubImportProjectForm", GithubImportProjectFormDirective) diff --git a/app/modules/projects/create/github-import/github-import-project-form/github-import-project-form.jade b/app/modules/projects/create/github-import/github-import-project-form/github-import-project-form.jade new file mode 100644 index 00000000..936cb685 --- /dev/null +++ b/app/modules/projects/create/github-import/github-import-project-form/github-import-project-form.jade @@ -0,0 +1,71 @@ +.import-project-github-form + div(ng-include="'projects/create/import/import-header.html'") + + .spin(tg-loading="vm.fetchingUsers") + + form( + ng-if="!vm.fetchingUsers", + name="projectForm", + ng-submit="vm.saveForm()" + ) + div(ng-include="'projects/create/import-project-form-common/name.html'") + div(ng-include="'projects/create/import-project-form-common/description.html'") + + .create-project-github-import-type(role="group") + p.question(translate="PROJECT.IMPORT.GITHUB.HOW_DO_YOU_WANT_TO_IMPORT") + .create-project-github-import-type-question + fieldset + input( + type="radio" + name="project_type" + id="template-issues" + data-required="true" + aria-hidden="true" + ng-value="'issues'" + ng-model="vm.projectForm.project_type" + required + ) + label(for="template-issues") + span.create-project-github-import-type-name(translate="PROJECT.IMPORT.GITHUB.ISSUES_PROJECT") + p.create-project-github-import-type-description(translate="PROJECT.IMPORT.GITHUB.ISSUES_PROJECT_DESCRIPTION") + fieldset + input( + type="radio" + name="project_type" + id="template-scrum" + data-required="true" + aria-hidden="true" + ng-value="'scrum'" + ng-model="vm.projectForm.project_type" + required + ) + label(for="template-scrum") + span.create-project-github-import-type-name(translate="PROJECT.IMPORT.GITHUB.SCRUM_PROJECT") + p.create-project-github-import-type-description(translate="PROJECT.IMPORT.GITHUB.SCRUM_PROJECT_DESCRIPTION") + fieldset + input( + type="radio" + name="project_type" + id="template-kanban" + data-required="true" + aria-hidden="true" + ng-value="'kanban'" + ng-model="vm.projectForm.project_type" + required + ) + label(for="template-kanban") + span.create-project-github-import-type-name(translate="PROJECT.IMPORT.GITHUB.KANBAN_PROJECT") + p.create-project-github-import-type-description(translate="PROJECT.IMPORT.GITHUB.KANBAN_PROJECT_DESCRIPTION") + div(ng-include="'projects/create/import-project-form-common/project-privacy.html'") + tg-create-project-restrictions( + is-private="vm.projectForm.is_private" + can-create-public-projects="vm.canCreatePublicProjects" + can-create-private-projects="vm.canCreatePrivateProjects" + ) + tg-create-project-members-restrictions( + is-private="vm.projectForm.is_private" + limit-members-private-project="vm.limitMembersPrivateProject" + limit-members-public-project="vm.limitMembersPublicProject" + ) + div(ng-include="'projects/create/import-project-form-common/links.html'") + div(ng-include="'projects/create/import-project-form-common/actions.html'") diff --git a/app/modules/projects/create/github-import/github-import-project-form/github-import-project-form.scss b/app/modules/projects/create/github-import/github-import-project-form/github-import-project-form.scss new file mode 100644 index 00000000..fe6578ec --- /dev/null +++ b/app/modules/projects/create/github-import/github-import-project-form/github-import-project-form.scss @@ -0,0 +1,61 @@ +.import-project-github-form { + @include create-project; +} + +.create-project-github-import-type { + margin-bottom: 1rem; + text-align: center; + + p { + margin-bottom: .5rem; + } + + &-question { + align-content: stretch; + align-items: stretch; + display: flex; + } + + fieldset { + background: $white; + border-right: 1px solid $whitish; + transition: background .2s linear; + + &:last-child { + border: 0; + } + } + + input { + display: none; + + &:checked { + +label { + background: rgba($primary, .1); + } + } + } + + label { + background: $white; + height: 100%; + padding: 1rem; + transition: background .2s ease-in; + + &:hover { + background: rgba($primary, .1); + cursor: pointer; + } + } + + &-name { + @include font-type(normal); + display: inline-block; + margin-bottom: .5rem; + } + + &-description { + @include font-type(light); + @include font-size(small); + } +} diff --git a/app/modules/projects/create/github-import/github-import.controller.coffee b/app/modules/projects/create/github-import/github-import.controller.coffee new file mode 100644 index 00000000..5ea46878 --- /dev/null +++ b/app/modules/projects/create/github-import/github-import.controller.coffee @@ -0,0 +1,74 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: github-import.controller.coffee +### + +class GithubImportController + @.$inject = [ + 'tgGithubImportService', + '$tgConfirm', + '$translate', + 'tgImportProjectService', + ] + + constructor: (@githubImportService, @confirm, @translate, @importProjectService) -> + @.step = 'autorization-github' + @.project = null + + taiga.defineImmutableProperty @, 'projects', () => return @githubImportService.projects + taiga.defineImmutableProperty @, 'members', () => return @githubImportService.projectUsers + + startProjectSelector: () -> + @.step = 'project-select-github' + @githubImportService.fetchProjects() + + onSelectProject: (project) -> + @.step = 'project-form-github' + @.project = project + @.fetchingUsers = true + + @githubImportService.fetchUsers(@.project.get('id')).then () => @.fetchingUsers = false + + onSaveProjectDetails: (project) -> + @.project = project + @.step = 'project-members-github' + + onCancelMemberSelection: () -> + @.step = 'project-form-github' + + startImport: (users) -> + loader = @confirm.loader(@translate.instant('PROJECT.IMPORT.IN_PROGRESS.TITLE'), @translate.instant('PROJECT.IMPORT.IN_PROGRESS.DESCRIPTION'), true) + + loader.start() + + promise = @githubImportService.importProject( + @.project.get('name'), + @.project.get('description'), + @.project.get('id'), + users, + @.project.get('keepExternalReference'), + @.project.get('is_private') + @.project.get('project_type') + ) + + @importProjectService.importPromise(promise).then () => loader.stop() + + submitUserSelection: (users) -> + @.startImport(users) + return null + +angular.module('taigaProjects').controller('GithubImportCtrl', GithubImportController) diff --git a/app/modules/projects/create/github-import/github-import.controller.spec.coffee b/app/modules/projects/create/github-import/github-import.controller.spec.coffee new file mode 100644 index 00000000..5a975f7f --- /dev/null +++ b/app/modules/projects/create/github-import/github-import.controller.spec.coffee @@ -0,0 +1,172 @@ +### +# Copyright (C) 2014-2015 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: github-import.controller.spec.coffee +### + +describe "GithubImportCtrl", -> + $provide = null + $controller = null + mocks = {} + + _mockCurrentUserService = -> + mocks.currentUserService = { + canAddMembersPrivateProject: sinon.stub() + canAddMembersPublicProject: sinon.stub() + } + + $provide.value("tgCurrentUserService", mocks.currentUserService) + + _mockImportProjectService = -> + mocks.importProjectService = { + importPromise: sinon.stub() + } + + $provide.value("tgImportProjectService", mocks.importProjectService) + + _mockGithubImportService = -> + mocks.githubService = { + fetchProjects: sinon.stub(), + fetchUsers: sinon.stub(), + importProject: sinon.stub() + } + + $provide.value("tgGithubImportService", mocks.githubService) + + _mockConfirm = -> + mocks.confirm = { + loader: sinon.stub() + } + + $provide.value("$tgConfirm", mocks.confirm) + + _mockTranslate = -> + mocks.translate = { + instant: sinon.stub() + } + + $provide.value("$translate", mocks.translate) + + _mocks = -> + module (_$provide_) -> + $provide = _$provide_ + + _mockGithubImportService() + _mockConfirm() + _mockTranslate() + _mockImportProjectService() + _mockCurrentUserService() + + return null + + _inject = -> + inject (_$controller_) -> + $controller = _$controller_ + + _setup = -> + _mocks() + _inject() + + beforeEach -> + module "taigaProjects" + + _setup() + + it "start project selector", () -> + ctrl = $controller("GithubImportCtrl") + ctrl.startProjectSelector() + + expect(ctrl.step).to.be.equal('project-select-github') + expect(mocks.githubService.fetchProjects).have.been.called + + it "on select project reload projects", (done) -> + project = Immutable.fromJS({ + id: 1, + name: "project-name" + }) + + mocks.githubService.fetchUsers.promise().resolve() + + ctrl = $controller("GithubImportCtrl") + + promise = ctrl.onSelectProject(project) + + expect(ctrl.fetchingUsers).to.be.true + + promise.then () -> + expect(ctrl.fetchingUsers).to.be.false + expect(ctrl.step).to.be.equal('project-form-github') + expect(ctrl.project).to.be.equal(project) + done() + + it "on save project details reload users", () -> + project = Immutable.fromJS({ + id: 1, + name: "project-name" + }) + + ctrl = $controller("GithubImportCtrl") + ctrl.onSaveProjectDetails(project) + + expect(ctrl.step).to.be.equal('project-members-github') + expect(ctrl.project).to.be.equal(project) + + it "on select user init import", (done) -> + users = Immutable.fromJS([ + { + id: 0 + }, + { + id: 1 + }, + { + id: 2 + } + ]) + + loaderObj = { + start: sinon.spy(), + update: sinon.stub(), + stop: sinon.spy() + } + + projectResult = { + id: 3, + name: "name" + } + + mocks.confirm.loader.returns(loaderObj) + + mocks.importProjectService.importPromise.promise().resolve() + + ctrl = $controller("GithubImportCtrl") + ctrl.project = Immutable.fromJS({ + id: 1, + name: 'project-name', + description: 'project-description', + keepExternalReference: false, + is_private: true + }) + + + mocks.githubService.importProject.promise().resolve(projectResult) + + ctrl.startImport(users).then () -> + expect(loaderObj.start).have.been.called + expect(loaderObj.stop).have.been.called + expect(mocks.githubService.importProject).have.been.calledWith('project-name', 'project-description', 1, users, false, true) + + done() diff --git a/app/modules/projects/create/github-import/github-import.directive.coffee b/app/modules/projects/create/github-import/github-import.directive.coffee new file mode 100644 index 00000000..7d23b042 --- /dev/null +++ b/app/modules/projects/create/github-import/github-import.directive.coffee @@ -0,0 +1,35 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: github-import.directive.coffee +### + +GithubImportDirective = () -> + return { + link: (scope, elm, attrs, ctrl) -> + ctrl.startProjectSelector() + templateUrl:"projects/create/github-import/github-import.html", + controller: "GithubImportCtrl", + controllerAs: "vm", + bindToController: true, + scope: { + onCancel: '&' + } + } + +GithubImportDirective.$inject = [] + +angular.module("taigaProjects").directive("tgGithubImport", GithubImportDirective) diff --git a/app/modules/projects/create/github-import/github-import.jade b/app/modules/projects/create/github-import/github-import.jade new file mode 100644 index 00000000..a85e1de8 --- /dev/null +++ b/app/modules/projects/create/github-import/github-import.jade @@ -0,0 +1,32 @@ +.create-project.import-project(ng-if="vm.step == 'autorization-github'") + p autorization... + + +tg-import-project-selector( + logo="/#{v}/images/import-logos/github.png" + search="{{ 'PROJECT.IMPORT.GITHUB.CHOOSE_PROJECT' | translate }}" + no-projects-msg="{{ 'PROJECT.IMPORT.GITHUB.NO_PROJECTS' | translate }}" + projects="vm.projects" + on-cancel="vm.onCancel()" + on-select-project="vm.onSelectProject(project)" + ng-if="vm.step == 'project-select-github'" +) + +tg-github-import-project-form( + ng-if="vm.step == 'project-form-github'" + project="vm.project" + members="vm.members" + fetching-users="vm.fetchingUsers" + on-save-project-details="vm.onSaveProjectDetails(project)" + on-cancel-form="vm.step = 'project-select-github'" +) + +tg-import-project-members( + ng-if="vm.step == 'project-members-github'" + platform="Github" + logo="/#{v}/images/import-logos/github.png" + project="vm.project" + members="vm.members" + on-submit="vm.submitUserSelection(users)" + on-cancel="vm.onCancelMemberSelection()" +) diff --git a/app/modules/projects/create/github-import/github-import.service.coffee b/app/modules/projects/create/github-import/github-import.service.coffee new file mode 100644 index 00000000..5735f862 --- /dev/null +++ b/app/modules/projects/create/github-import/github-import.service.coffee @@ -0,0 +1,55 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: github-import.service.coffee +### + +class GithubImportService extends taiga.Service + @.$inject = [ + 'tgResources' + ] + + constructor: (@resources, @location) -> + @.projects = Immutable.List() + @.projectUsers = Immutable.List() + + setToken: (token) -> + @.token = token + + fetchProjects: () -> + @resources.githubImporter.listProjects(@.token).then (projects) => @.projects = projects + + fetchUsers: (projectId) -> + @resources.githubImporter.listUsers(@.token, projectId).then (users) => @.projectUsers = users + + importProject: (name, description, projectId, userBindings, keepExternalReference, isPrivate, projectType) -> + return @resources.githubImporter.importProject(@.token, name, description, projectId, userBindings, keepExternalReference, isPrivate, projectType) + + getAuthUrl: (callbackUri) -> + return new Promise (resolve) => + @resources.githubImporter.getAuthUrl(callbackUri).then (response) => + @.authUrl = response.data.url + resolve(@.authUrl) + + authorize: (code) -> + return new Promise (resolve, reject) => + @resources.githubImporter.authorize(code).then ((response) => + @.token = response.data.token + resolve(@.token) + ), (error) -> + reject(new Error(error.status)) + +angular.module("taigaProjects").service("tgGithubImportService", GithubImportService) diff --git a/app/modules/projects/create/github-import/github-import.service.spec.coffee b/app/modules/projects/create/github-import/github-import.service.spec.coffee new file mode 100644 index 00000000..be9732f5 --- /dev/null +++ b/app/modules/projects/create/github-import/github-import.service.spec.coffee @@ -0,0 +1,129 @@ +### +# Copyright (C) 2014-2015 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: github-import.controller.spec.coffee +### + +describe "tgGithubImportService", -> + $provide = null + service = null + mocks = {} + + _mockResources = -> + mocks.resources = { + githubImporter: { + listProjects: sinon.stub(), + listUsers: sinon.stub(), + importProject: sinon.stub(), + getAuthUrl: sinon.stub(), + authorize: sinon.stub() + } + } + + $provide.value("tgResources", mocks.resources) + + _mockLocation = -> + mocks.location = { + search: sinon.stub() + } + + mocks.location.search.returns({ + token: 123 + }) + + $provide.value("$location", mocks.location) + + _mocks = -> + module (_$provide_) -> + $provide = _$provide_ + + _mockResources() + _mockLocation() + + return null + + _inject = -> + inject (_tgGithubImportService_) -> + service = _tgGithubImportService_ + + _setup = -> + _mocks() + _inject() + + beforeEach -> + module "taigaProjects" + + _setup() + + it "fetch projects", (done) -> + service.setToken(123) + + mocks.resources.githubImporter.listProjects.withArgs(123).promise().resolve('projects') + + service.fetchProjects().then () -> + service.projects = "projects" + done() + + it "fetch user", (done) -> + service.setToken(123) + + projectId = 3 + mocks.resources.githubImporter.listUsers.withArgs(123, projectId).promise().resolve('users') + + service.fetchUsers(projectId).then () -> + service.projectUsers = 'users' + done() + + it "import project", () -> + service.setToken(123) + projectId = 2 + + service.importProject(projectId, true, true ,true) + + expect(mocks.resources.githubImporter.importProject).to.have.been.calledWith(123, projectId, true, true, true) + + it "get auth url", (done) -> + service.setToken(123) + projectId = 3 + + response = { + data: { + url: "url123" + } + } + + mocks.resources.githubImporter.getAuthUrl.promise().resolve(response) + + service.getAuthUrl().then (url) -> + expect(url).to.be.equal("url123") + done() + + it "authorize", (done) -> + service.setToken(123) + projectId = 3 + verifyCode = 12345 + + response = { + data: { + token: "token123" + } + } + + mocks.resources.githubImporter.authorize.withArgs(verifyCode).promise().resolve(response) + + service.authorize(verifyCode).then (token) -> + expect(token).to.be.equal("token123") + done() diff --git a/app/modules/projects/create/import-project-form-common/actions.jade b/app/modules/projects/create/import-project-form-common/actions.jade new file mode 100644 index 00000000..0ad2f57a --- /dev/null +++ b/app/modules/projects/create/import-project-form-common/actions.jade @@ -0,0 +1,13 @@ +.create-project-action + button.trans-button.create-project-action-cancel( + type="button" + ng-click="vm.onCancelForm()" + title="{{'PROJECT.CREATE.BACK' | translate}}" + translate="PROJECT.CREATE.BACK" + ) + button.button-green.create-project-action-submit.e2e-create-project-action-submit( + type="submit" + ng-disabled="projectForm.$invalid || vm.isDisabled()" + tg-loading="vm.formSubmitLoading" + translate="PROJECT.CREATE.TITLE" + ) diff --git a/app/modules/projects/create/import-project-form-common/description.jade b/app/modules/projects/create/import-project-form-common/description.jade new file mode 100644 index 00000000..72105418 --- /dev/null +++ b/app/modules/projects/create/import-project-form-common/description.jade @@ -0,0 +1,7 @@ +fieldset + textarea.e2e-create-project-description( + ng-model="vm.projectForm.description" + placeholder="{{'PROJECT.COMMON.PROJECT_DESCRIPTION' | translate}}" + data-required="true" + required + ) diff --git a/app/modules/projects/create/import-project-form-common/links.jade b/app/modules/projects/create/import-project-form-common/links.jade new file mode 100644 index 00000000..05e3f94c --- /dev/null +++ b/app/modules/projects/create/import-project-form-common/links.jade @@ -0,0 +1,20 @@ +fieldset.create-project-check + label(for="links") + span.title( + translate="PROJECT.IMPORT.LINKS" + translate-values="{platform: vm.platformName}" + ) + span.description( + translate="PROJECT.IMPORT.LINKS_DESCRIPTION" + translate-values="{platform: vm.platformName}" + ) + + .check + input.activate-input( + ng-model="vm.projectForm.keepExternalReference" + name="links" + type="checkbox" + ) + div + span.check-text.check-yes(translate="COMMON.YES") + span.check-text.check-no(translate="COMMON.NO") \ No newline at end of file diff --git a/app/modules/projects/create/import-project-form-common/name.jade b/app/modules/projects/create/import-project-form-common/name.jade new file mode 100644 index 00000000..8d329172 --- /dev/null +++ b/app/modules/projects/create/import-project-form-common/name.jade @@ -0,0 +1,13 @@ +fieldset + label( + translate="PROJECT.COMMON.DETAILS" + for="project-name" + ) + input.e2e-create-project-title( + type="text" + ng-model="vm.projectForm.name" + placeholder="{{'PROJECT.COMMON.PROJECT_TITLE' | translate}}" + name="project-name" + data-required="true" + required + ) \ No newline at end of file diff --git a/app/modules/projects/create/import-project-form-common/project-privacy.jade b/app/modules/projects/create/import-project-form-common/project-privacy.jade new file mode 100644 index 00000000..aebbd5f4 --- /dev/null +++ b/app/modules/projects/create/import-project-form-common/project-privacy.jade @@ -0,0 +1,30 @@ +.create-project-privacity(role="group") + fieldset + input( + type="radio" + name="is_private" + id="template-public" + data-required="true" + aria-hidden="true" + ng-value="false" + ng-model="vm.projectForm.is_private" + required + ng-checked="vm.canCreatePublicProjects" + ) + label(for="template-public") + tg-svg(svg-icon="icon-discover") + span(translate="PROJECT.CREATE.PUBLIC_PROJECT") + fieldset + input( + type="radio" + name="is_private" + id="template-private" + data-required="true" + ng-value="true" + ng-model="vm.projectForm.is_private" + aria-hidden="true" + required + ) + label(for="template-private") + tg-svg(svg-icon="icon-lock") + span(translate="PROJECT.CREATE.PRIVATE_PROJECT") diff --git a/app/modules/projects/create/import-project-members/import-project-members.controller.coffee b/app/modules/projects/create/import-project-members/import-project-members.controller.coffee new file mode 100644 index 00000000..c88ab21e --- /dev/null +++ b/app/modules/projects/create/import-project-members/import-project-members.controller.coffee @@ -0,0 +1,154 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: import-project-members.controller.coffee +### + +class ImportProjectMembersController + @.$inject = [ + 'tgCurrentUserService', + 'tgUserService' + ] + + constructor: (@currentUserService, @userService) -> + @.selectImportUserLightbox = false + @.warningImportUsers = false + @.displayEmailSelector = true + @.cancelledUsers = Immutable.List() + @.selectedUsers = Immutable.List() + @.selectableUsers = Immutable.List() + @.userContacts = Immutable.List() + + fetchUser: () -> + @.currentUser = @currentUserService.getUser() + + @userService.getContacts(@.currentUser.get('id')).then (userContacts) => + @.userContacts = userContacts + @.refreshSelectableUsers() + + searchUser: (user) -> + @.selectImportUserLightbox = true + @.searchingUser = user + + beforeSubmitUsers: () -> + if @.selectedUsers.size != @.members.size + @.warningImportUsers = true + else + @.submit() + + confirmUser: (externalUser, taigaUser) -> + @.selectImportUserLightbox = false + + user = Immutable.Map() + user = user.set('user', externalUser) + user = user.set('taigaUser', taigaUser) + + @.selectedUsers = @.selectedUsers.push(user) + + @.discardSuggestedUser(externalUser) + + @.refreshSelectableUsers() + + unselectUser: (user) -> + index = @.selectedUsers.findIndex (it) -> it.getIn(['user', 'id']) == user.get('id') + + @.selectedUsers = @.selectedUsers.delete(index) + @.refreshSelectableUsers() + + discardSuggestedUser: (member) -> + @.cancelledUsers = @.cancelledUsers.push(member.get('id')) + + getSelectedMember: (member) -> + return @.selectedUsers.find (it) -> + return it.getIn(['user', 'id']) == member.get('id') + + isMemberSelected: (member) -> + return !!@.getSelectedMember(member) + + getUser: (user) -> + userSelected = @.getSelectedMember(user) + + if userSelected + return userSelected.get('taigaUser') + else + return null + + submit: () -> + @.warningImportUsers = false + + users = Immutable.Map() + + @.selectedUsers.map (it) -> + id = '' + + if _.isString(it.get('taigaUser')) + id = it.get('taigaUser') + else + id = it.getIn(['taigaUser', 'id']) + + users = users.set(it.getIn(['user', 'id']), id) + + @.onSubmit({users: users}) + + checkUsersLimit: () -> + @.limitMembersPrivateProject = @currentUserService.canAddMembersPrivateProject(@.members.size + 1) + @.limitMembersPublicProject = @currentUserService.canAddMembersPublicProject(@.members.size + 1) + + showSuggestedMatch: (member) -> + return member.get('user') && @.cancelledUsers.indexOf(member.get('id')) == -1 && !@.isMemberSelected(member) + + getDistinctSelectedTaigaUsers: () -> + ids = [] + + users = @.selectedUsers.filter (it) -> + id = it.getIn(['taigaUser', 'id']) + + if ids.indexOf(id) == -1 + ids.push(id) + return true + + return false + + return users.filter (it) => + return it.getIn(['taigaUser', 'id']) != @.currentUser.get('id') + + refreshSelectableUsers: () -> + @.importMoreUsersDisabled = @.isImportMoreUsersDisabled() + + if @.importMoreUsersDisabled + users = @.getDistinctSelectedTaigaUsers() + + @.selectableUsers = users.map (it) -> return it.get('taigaUser') + @.displayEmailSelector = false + else + @.selectableUsers = @.userContacts + @.displayEmailSelector = true + + @.selectableUsers = @.selectableUsers.push(@.currentUser) + + isImportMoreUsersDisabled: () -> + users = @.getDistinctSelectedTaigaUsers() + + # currentUser + newUser = +2 + total = users.size + 2 + + + if @.project.get('is_private') + return !@currentUserService.canAddMembersPrivateProject(total).valid + else + return !@currentUserService.canAddMembersPublicProject(total).valid + +angular.module('taigaProjects').controller('ImportProjectMembersCtrl', ImportProjectMembersController) diff --git a/app/modules/projects/create/import-project-members/import-project-members.controller.spec.coffee b/app/modules/projects/create/import-project-members/import-project-members.controller.spec.coffee new file mode 100644 index 00000000..47be1b10 --- /dev/null +++ b/app/modules/projects/create/import-project-members/import-project-members.controller.spec.coffee @@ -0,0 +1,371 @@ +### +# Copyright (C) 2014-2015 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: import.controller.spec.coffee +### + +describe "ImportProjectMembersCtrl", -> + $provide = null + $controller = null + mocks = {} + + _mockCurrentUserService = -> + mocks.currentUserService = { + getUser: sinon.stub().returns(Immutable.fromJS({ + id: 1 + })), + canAddMembersPrivateProject: sinon.stub(), + canAddMembersPublicProject: sinon.stub() + } + + $provide.value("tgCurrentUserService", mocks.currentUserService) + + _mockUserService = -> + mocks.userService = { + getContacts: sinon.stub() + } + + $provide.value("tgUserService", mocks.userService) + + _inject = -> + inject (_$controller_) -> + $controller = _$controller_ + + _mocks = -> + module (_$provide_) -> + $provide = _$provide_ + + _mockCurrentUserService() + _mockUserService() + + return null + + _setup = -> + _mocks() + _inject() + + beforeEach -> + module "taigaProjects" + + _setup() + + it "fetch user info", (done) -> + ctrl = $controller("ImportProjectMembersCtrl") + + ctrl.refreshSelectableUsers = sinon.spy() + + mocks.userService.getContacts.withArgs(1).promise().resolve('contacts') + + ctrl.fetchUser().then () -> + expect(ctrl.userContacts).to.be.equal('contacts') + expect(ctrl.refreshSelectableUsers).have.been.called + done() + + it "search user", () -> + ctrl = $controller("ImportProjectMembersCtrl") + + user = { + id: 1, + name: "username" + } + + ctrl.searchUser(user) + + expect(ctrl.selectImportUserLightbox).to.be.true + expect(ctrl.searchingUser).to.be.equal(user) + + it "prepare submit users, warning if needed", () -> + ctrl = $controller("ImportProjectMembersCtrl") + + user = { + id: 1, + name: "username" + } + + ctrl.selectedUsers = Immutable.fromJS([ + {id: 1}, + {id: 2} + ]) + + ctrl.members = Immutable.fromJS([ + {id: 1} + ]) + + ctrl.beforeSubmitUsers() + + expect(ctrl.warningImportUsers).to.be.true + + it "prepare submit users, submit", () -> + ctrl = $controller("ImportProjectMembersCtrl") + + user = { + id: 1, + name: "username" + } + + ctrl.selectedUsers = Immutable.fromJS([ + {id: 1} + ]) + + ctrl.members = Immutable.fromJS([ + {id: 1} + ]) + + + ctrl.submit = sinon.spy() + ctrl.beforeSubmitUsers() + + expect(ctrl.warningImportUsers).to.be.false + expect(ctrl.submit).have.been.called + + it "confirm user", () -> + ctrl = $controller("ImportProjectMembersCtrl") + + ctrl.discardSuggestedUser = sinon.spy() + ctrl.refreshSelectableUsers = sinon.spy() + + ctrl.confirmUser('user', 'taiga-user') + + expect(ctrl.selectedUsers.size).to.be.equal(1) + + expect(ctrl.selectedUsers.get(0).get('user')).to.be.equal('user') + expect(ctrl.selectedUsers.get(0).get('taigaUser')).to.be.equal('taiga-user') + expect(ctrl.discardSuggestedUser).have.been.called + expect(ctrl.refreshSelectableUsers).have.been.called + + it "discard suggested user", () -> + ctrl = $controller("ImportProjectMembersCtrl") + + ctrl.discardSuggestedUser(Immutable.fromJS({ + id: 3 + })) + + expect(ctrl.cancelledUsers.get(0)).to.be.equal(3) + + it "clean member selection", () -> + ctrl = $controller("ImportProjectMembersCtrl") + + ctrl.refreshSelectableUsers = sinon.spy() + + ctrl.selectedUsers = Immutable.fromJS([ + { + user: { + id: 1 + } + }, + { + user: { + id: 2 + } + } + ]) + + ctrl.unselectUser(Immutable.fromJS({ + id: 2 + })) + + expect(ctrl.selectedUsers.size).to.be.equal(1) + expect(ctrl.refreshSelectableUsers).have.been.called + + + it "get a selected member", () -> + ctrl = $controller("ImportProjectMembersCtrl") + + member = Immutable.fromJS({ + id: 3 + }) + + ctrl.selectedUsers = ctrl.selectedUsers.push(Immutable.fromJS({ + user: { + id: 3 + } + })) + + user = ctrl.getSelectedMember(member) + + expect(user.getIn(['user', 'id'])).to.be.equal(3) + + it "submit", () -> + ctrl = $controller("ImportProjectMembersCtrl") + + ctrl.selectedUsers = ctrl.selectedUsers.push(Immutable.fromJS({ + user: { + id: 3 + }, + taigaUser: { + id: 2 + } + })) + + ctrl.selectedUsers = ctrl.selectedUsers.push(Immutable.fromJS({ + user: { + id: 3 + }, + taigaUser: "xx@yy.com" + })) + + + ctrl.onSubmit = sinon.stub() + + ctrl.submit() + + user = Immutable.Map() + user = user.set(3, 2) + + expect(ctrl.onSubmit).have.been.called + expect(ctrl.warningImportUsers).to.be.false + + it "show suggested match", () -> + ctrl = $controller("ImportProjectMembersCtrl") + + ctrl.isMemberSelected = sinon.stub().returns(false) + ctrl.cancelledUsers = [ + 3 + ] + + member = Immutable.fromJS({ + id: 1, + user: { + id: 10 + } + }) + + expect(ctrl.showSuggestedMatch(member)).to.be.true + + it "doesn't show suggested match", () -> + ctrl = $controller("ImportProjectMembersCtrl") + + ctrl.isMemberSelected = sinon.stub().returns(false) + ctrl.cancelledUsers = [ + 3 + ] + + member = Immutable.fromJS({ + id: 3, + user: { + id: 10 + } + }) + + expect(ctrl.showSuggestedMatch(member)).to.be.false + + it "check users limit", () -> + ctrl = $controller("ImportProjectMembersCtrl") + + ctrl.members = Immutable.fromJS([ + 1, 2, 3 + ]) + + mocks.currentUserService.canAddMembersPrivateProject.withArgs(4).returns('xx') + mocks.currentUserService.canAddMembersPublicProject.withArgs(4).returns('yy') + + ctrl.checkUsersLimit() + + expect(ctrl.limitMembersPrivateProject).to.be.equal('xx') + expect(ctrl.limitMembersPublicProject).to.be.equal('yy') + + + it "get distict select taiga users excluding the current user", () -> + ctrl = $controller("ImportProjectMembersCtrl") + ctrl.selectedUsers = Immutable.fromJS([ + { + taigaUser: { + id: 1 + } + }, + { + taigaUser: { + id: 1 + } + }, + { + taigaUser: { + id: 3 + } + }, + { + taigaUser: { + id: 5 + } + } + ]) + + ctrl.currentUser = Immutable.fromJS({ + id: 5 + }) + + users = ctrl.getDistinctSelectedTaigaUsers() + + expect(users.size).to.be.equal(2) + + it "refresh selectable users array with all users available", () -> + ctrl = $controller("ImportProjectMembersCtrl") + + ctrl.isImportMoreUsersDisabled = sinon.stub().returns(false) + ctrl.displayEmailSelector = false + + ctrl.userContacts = Immutable.fromJS([1]) + ctrl.currentUser = 2 + + ctrl.refreshSelectableUsers() + + expect(ctrl.selectableUsers.toJS()).to.be.eql([1, 2]) + expect(ctrl.displayEmailSelector).to.be.true + + + it.only "refresh selectable users array with the selected ones", () -> + ctrl = $controller("ImportProjectMembersCtrl") + + ctrl.getDistinctSelectedTaigaUsers = sinon.stub().returns(Immutable.fromJS([ + {taigaUser: 1} + ])) + ctrl.displayEmailSelector = false + + ctrl.isImportMoreUsersDisabled = sinon.stub().returns(true) + + ctrl.userContacts = Immutable.fromJS([1]) + ctrl.currentUser = 2 + + ctrl.refreshSelectableUsers() + + expect(ctrl.selectableUsers.toJS()).to.be.eql([1, 2]) + expect(ctrl.displayEmailSelector).to.be.false + + it "import more user disable in private project", () -> + ctrl = $controller("ImportProjectMembersCtrl") + + ctrl.project = Immutable.fromJS({ + is_private: true + }) + + ctrl.getDistinctSelectedTaigaUsers = sinon.stub().returns(Immutable.fromJS([1,2,3])) + + mocks.currentUserService.canAddMembersPrivateProject.withArgs(5).returns({valid: true}) + + expect(ctrl.isImportMoreUsersDisabled()).to.be.false + + it "import more user disable in public project", () -> + ctrl = $controller("ImportProjectMembersCtrl") + + ctrl.project = Immutable.fromJS({ + is_private: false + }) + + ctrl.getDistinctSelectedTaigaUsers = sinon.stub().returns(Immutable.fromJS([1,2,3])) + + mocks.currentUserService.canAddMembersPublicProject.withArgs(5).returns({valid: true}) + + expect(ctrl.isImportMoreUsersDisabled()).to.be.false diff --git a/app/modules/projects/create/import-project-members/import-project-members.directive.coffee b/app/modules/projects/create/import-project-members/import-project-members.directive.coffee new file mode 100644 index 00000000..5a39d2a8 --- /dev/null +++ b/app/modules/projects/create/import-project-members/import-project-members.directive.coffee @@ -0,0 +1,43 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: import-project-form.directive.coffee +### + +ImportProjectMembersDirective = () -> + return { + link: (scope, elm, attr, ctrl) -> + ctrl.fetchUser() + + scope.$watch('vm.members', ctrl.checkUsersLimit.bind(ctrl)) + + templateUrl:"projects/create/import-project-members/import-project-members.html", + controller: "ImportProjectMembersCtrl", + controllerAs: "vm", + bindToController: true, + scope: { + members: '<', + project: '<', + onSubmit: '&', + platform: '@', + logo: '@', + onCancel: '&' + } + } + +ImportProjectMembersDirective.$inject = [] + +angular.module("taigaProjects").directive("tgImportProjectMembers", ImportProjectMembersDirective) diff --git a/app/modules/projects/create/import-project-members/import-project-members.jade b/app/modules/projects/create/import-project-members/import-project-members.jade new file mode 100644 index 00000000..ec1b51d9 --- /dev/null +++ b/app/modules/projects/create/import-project-members/import-project-members.jade @@ -0,0 +1,86 @@ +.import-project-members + div(ng-include="'projects/create/import/import-header.html'") + + h2.import-project-members-title(translate="PROJECT.IMPORT.PROJECT_MEMBERS") + p( + translate="PROJECT.IMPORT.PROCESS_DESCRIPTION", + translate-values="{'platform': vm.platform}" + ) + + tg-create-project-members-restrictions( + is-private="vm.project.get('is_private')" + limit-members-private-project="vm.limitMembersPrivateProject" + limit-members-public-project="vm.limitMembersPublicProject" + ) + + .import-project-members-system(ng-if="vm.members.size") + .import-project-members-logo + img(ng-src="{{vm.logo}}") + .import-project-members-logo + img( + src="/#{v}/images/logo-color.png" + alt="Taiga Logo" + ) + + ul(ng-if="vm.members.size") + li.import-project-members-row(tg-repeat="member in vm.members track by member.get('id')") + .import-project-members-single + .avatar.empty(ng-if="!member.get('avatar')") {{member.get('full_name')[0].toUpperCase()}} + .avatar(ng-if="member.get('avatar')") + img(ng-src="{{member.get('avatar')}}") + span.import-project-members-username {{member.get('full_name') || member.get('username') }} + + .import-project-members-actions + .import-project-members-match(ng-if="vm.showSuggestedMatch(member)") + span( + translate="PROJECT.IMPORT.MATCH" + translate-values="{user_external:member.get('full_name'), user_internal: member.getIn(['user', 'full_name'])}" + ) + button.import-project-members-match-true(ng-click="vm.confirmUser(member, member.get('user'))") + tg-svg(svg-icon="icon-check-empty") + button.import-project-members-match-false(ng-click="vm.discardSuggestedUser(member)") + tg-svg(svg-icon="icon-close") + + .import-project-members-selected(ng-if="vm.getUser(member) && !vm.showSuggestedMatch(member)") + button.import-project-members-delete(ng-click="vm.unselectUser(member)") + tg-svg(svg-icon="icon-close") + span {{vm.getUser(member).get('full_name') || vm.getUser(member)}} + span.import-project-members-selected-img + img(tg-avatar="vm.getUser(member)") + + button.button.button-trans.import-project-members-choose.ng-animate-disabled( + ng-if="!vm.getUser(member) && !vm.showSuggestedMatch(member)" + ng-click="vm.searchUser(member)" + translate="PROJECT.IMPORT.CHOOSE" + ) + + .create-project-action + button.trans-button.create-project-action-cancel( + type="button" + ng-click="vm.onCancel()" + title="{{'PROJECT.CREATE.BACK' | translate}}" + translate="PROJECT.CREATE.BACK" + ) + button.button.button-green.create-project-action-submit( + ng-if="vm.members.size > 0" + ng-click="vm.beforeSubmitUsers()" + translate="PROJECT.IMPORT.IMPORT" + ) + + tg-select-import-user-lightbox.lightbox( + is-private="vm.project.get('is_private')" + limit-members-private-project="vm.limitMembersPrivateProject" + limit-members-public-project="vm.limitMembersPublicProject" + visible="vm.selectImportUserLightbox" + user="vm.searchingUser" + display-email-selector="vm.displayEmailSelector" + selectable-users="vm.selectableUsers" + on-close="vm.selectImportUserLightbox = false" + on-select-user="vm.confirmUser(user, taigaUser)" + ) + + tg-warning-user-import-lightbox.lightbox( + visible="vm.warningImportUsers" + on-confirm="vm.submit()" + on-close="vm.warningImportUsers = false" + ) diff --git a/app/modules/projects/create/import-project-members/import-project-members.scss b/app/modules/projects/create/import-project-members/import-project-members.scss new file mode 100644 index 00000000..a343b3ea --- /dev/null +++ b/app/modules/projects/create/import-project-members/import-project-members.scss @@ -0,0 +1,3 @@ +.import-project-members { + @include import-members; +} diff --git a/app/modules/projects/create/import-project-selector/import-project-selector.controller.coffee b/app/modules/projects/create/import-project-selector/import-project-selector.controller.coffee new file mode 100644 index 00000000..0201c1da --- /dev/null +++ b/app/modules/projects/create/import-project-selector/import-project-selector.controller.coffee @@ -0,0 +1,24 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: import-project-selector.controller.coffee +### + +class ImportProjectSelectorController + selectProject: (project) -> + @.onSelectProject({project: Immutable.fromJS(project)}) + +angular.module('taigaProjects').controller('ImportProjectSelectorCtrl', ImportProjectSelectorController) diff --git a/app/modules/projects/create/import-project-selector/import-project-selector.directive.coffee b/app/modules/projects/create/import-project-selector/import-project-selector.directive.coffee new file mode 100644 index 00000000..c9955674 --- /dev/null +++ b/app/modules/projects/create/import-project-selector/import-project-selector.directive.coffee @@ -0,0 +1,36 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: import-project-selector.directive.coffee +### + +ImportProjectSelectorDirective = () -> + return { + templateUrl:"projects/create/import-project-selector/import-project-selector.html", + controller: "ImportProjectSelectorCtrl", + controllerAs: "vm", + bindToController: true, + scope: { + projects: '<', + onCancel: '&', + onSelectProject: '&', + logo: '@', + noProjectsMsg: '@', + search: '@' + } + } + +angular.module("taigaProjects").directive("tgImportProjectSelector", ImportProjectSelectorDirective) diff --git a/app/modules/projects/create/import-project-selector/import-project-selector.jade b/app/modules/projects/create/import-project-selector/import-project-selector.jade new file mode 100644 index 00000000..80ffaef2 --- /dev/null +++ b/app/modules/projects/create/import-project-selector/import-project-selector.jade @@ -0,0 +1,46 @@ +.import-project-selector + div(ng-include="'projects/create/import/import-header.html'") + + .import-project-selector + + .import-project-selector-service + img( + ng-src="{{vm.logo}}" + ) + + .import-project-selector-boards + form.import-project-selector-filter(ng-if="vm.projects.size > 5") + input( + ng-model="vm.searchText" + placeholder="{{ vm.search }}" + ) + tg-svg( + svg-icon="icon-search" + title="{{ 'PROJECT.IMPORT.PROJECT_SELECTOR.ACTION_SEARCH' | translate }}" + ) + + ul.import-project-board-list + li.import-project-selector-title( + ng-repeat="project in vm.projects | toMutable | orderBy:'name' | filter:vm.searchText as filteredProjects track by project.id" + ng-click="vm.selectProject(project)" + ) {{project.name}} + + .import-project-board-no-projects.empty-large(ng-if="vm.projects.size == 0") + img( + src="/#{v}/images/empty/empty_tex.png", + alt="{{ vm.noProjectsMsg }}" + aria-hidden="true" + role="presentation" + ) + p.title {{ vm.noProjectsMsg }} + + .import-project-board-no-results.empty-filter(ng-if="vm.projects.size > 0 && filteredProjects.length == 0") + p(translate="PROJECT.IMPORT.PROJECT_SELECTOR.NO_RESULTS") + + .create-project-action + button.trans-button.create-project-action-cancel( + type="button" + ng-click="vm.onCancel()" + title="{{'PROJECT.IMPORT.PROJECT_SELECTOR.ACTION_BACK' | translate}}" + translate="PROJECT.IMPORT.PROJECT_SELECTOR.ACTION_BACK" + ) diff --git a/app/modules/projects/create/import-project-selector/import-project-selector.scss b/app/modules/projects/create/import-project-selector/import-project-selector.scss new file mode 100644 index 00000000..ac0fbf17 --- /dev/null +++ b/app/modules/projects/create/import-project-selector/import-project-selector.scss @@ -0,0 +1,3 @@ +.import-project-selector { + @include import-project-selector; +} diff --git a/app/modules/projects/create/import-taiga/import-taiga.controller.coffee b/app/modules/projects/create/import-taiga/import-taiga.controller.coffee new file mode 100644 index 00000000..65709af6 --- /dev/null +++ b/app/modules/projects/create/import-taiga/import-taiga.controller.coffee @@ -0,0 +1,43 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: import-project.controller.coffee +### + +class ImportTaigaController + @.$inject = [ + '$tgConfirm', + '$tgResources', + 'tgImportProjectService', + '$translate' + ] + + constructor: (@confirm, @rs, @importProjectService, @translate) -> + + importTaiga: (files) -> + file = files[0] + + loader = @confirm.loader(@translate.instant('PROJECT.IMPORT.IN_PROGRESS.TITLE'), @translate.instant('PROJECT.IMPORT.IN_PROGRESS.DESCRIPTION'), true) + + loader.start() + + promise = @rs.projects.import(file, loader.update) + + @importProjectService.importPromise(promise).finally () => loader.stop() + + return + +angular.module("taigaProjects").controller("ImportTaigaCtrl", ImportTaigaController) diff --git a/app/modules/projects/create/import-taiga/import-taiga.directive.coffee b/app/modules/projects/create/import-taiga/import-taiga.directive.coffee new file mode 100644 index 00000000..c9274943 --- /dev/null +++ b/app/modules/projects/create/import-taiga/import-taiga.directive.coffee @@ -0,0 +1,29 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: import-taiga.directive.coffee +### + +ImportTaigaDirective = () -> + return { + templateUrl:"projects/create/import-taiga/import-taiga.html", + controller: "ImportTaigaCtrl", + controllerAs: "vm", + bindToController: true, + scope: {} + } + +angular.module("taigaProjects").directive("tgImportTaiga", ImportTaigaDirective) diff --git a/app/modules/projects/create/import-taiga/import-taiga.jade b/app/modules/projects/create/import-taiga/import-taiga.jade new file mode 100644 index 00000000..da97034b --- /dev/null +++ b/app/modules/projects/create/import-taiga/import-taiga.jade @@ -0,0 +1,12 @@ +input.hidden( + tg-file-change="vm.importTaiga(files)" + type="file" +) +.import-project-logo + img( + src="/#{v}/images/logo-color.png" + alt="Taiga Logo" + ) +.import-project-name-wrapper + span.import-project-name Taiga + p.import-project-description(translate="PROJECT.IMPORT.TAIGA.SELECTOR") diff --git a/app/modules/projects/create/import/import-header.jade b/app/modules/projects/create/import/import-header.jade new file mode 100644 index 00000000..f2c0560f --- /dev/null +++ b/app/modules/projects/create/import/import-header.jade @@ -0,0 +1,3 @@ +section.import-project-from + h1.create-project-title(translate="PROJECT.IMPORT.TITLE") + h3.create-project-description(translate="PROJECT.IMPORT.DESCRIPTION") diff --git a/app/modules/projects/create/import/import-project-error-lb.directive.coffee b/app/modules/projects/create/import/import-project-error-lb.directive.coffee new file mode 100644 index 00000000..9c03cc19 --- /dev/null +++ b/app/modules/projects/create/import/import-project-error-lb.directive.coffee @@ -0,0 +1,16 @@ +LbImportErrorDirective = (lightboxService) -> + link = (scope, el, attrs) -> + lightboxService.open(el) + + scope.close = () -> + lightboxService.close(el) + return + + return { + templateUrl: "projects/create/import/import-project-error-lb.html", + link: link + } + +LbImportErrorDirective.$inject = ["lightboxService"] + +angular.module("taigaProjects").directive("tgLbImportError", LbImportErrorDirective) diff --git a/app/partials/common/lightbox/lightbox-import-error.jade b/app/modules/projects/create/import/import-project-error-lb.jade similarity index 100% rename from app/partials/common/lightbox/lightbox-import-error.jade rename to app/modules/projects/create/import/import-project-error-lb.jade diff --git a/app/modules/projects/create/import/import-project.controller.coffee b/app/modules/projects/create/import/import-project.controller.coffee new file mode 100644 index 00000000..d2967f64 --- /dev/null +++ b/app/modules/projects/create/import/import-project.controller.coffee @@ -0,0 +1,116 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: import-project.controller.coffee +### + +class ImportProjectController + @.$inject = [ + 'tgTrelloImportService', + 'tgJiraImportService', + 'tgGithubImportService', + 'tgAsanaImportService', + '$location', + '$window', + '$routeParams', + '$tgNavUrls', + '$tgConfig', + ] + + constructor: (@trelloService, @jiraService, @githubService, @asanaService, @location, @window, @routeParams, @tgNavUrls, @config) -> + + start: -> + @.token = null + @.from = @routeParams.platform + + locationSearch = @location.search() + + if @.from == "asana" + asanaOauthToken = locationSearch.code + if locationSearch.code + asanaOauthToken = locationSearch.code + + return @asanaService.authorize(asanaOauthToken).then ((token) => + @location.search({token: encodeURIComponent(JSON.stringify(token))}) + ), @.cancelCurrentImport.bind(this) + else + @.token = JSON.parse(decodeURIComponent(locationSearch.token)) + @asanaService.setToken(@.token) + + if @.from == 'trello' + if locationSearch.oauth_verifier + trelloOauthToken = locationSearch.oauth_verifier + return @trelloService.authorize(trelloOauthToken).then ((token) => + @location.search({token: token}) + ), @.cancelCurrentImport.bind(this) + else if locationSearch.token + @.token = locationSearch.token + @trelloService.setToken(locationSearch.token) + + if @.from == "github" + if locationSearch.code + githubOauthToken = locationSearch.code + + return @githubService.authorize(githubOauthToken).then ((token) => + @location.search({token: token}) + ), @.cancelCurrentImport.bind(this) + else if locationSearch.token + @.token = locationSearch.token + @githubService.setToken(locationSearch.token) + + if @.from == "jira" + jiraOauthToken = locationSearch.oauth_token + + if jiraOauthToken + return @jiraService.authorize().then ((data) => + @location.search({token: data.token, url: data.url}) + ), @.cancelCurrentImport.bind(this) + else + @.token = locationSearch.token + @jiraService.setToken(locationSearch.token, locationSearch.url) + + select: (from) -> + if from == "trello" + @trelloService.getAuthUrl().then (url) => + @window.open(url, "_self") + else if from == "jira" + @jiraService.getAuthUrl(@.jiraUrl).then (url) => + @window.open(url, "_self") + else if from == "github" + callbackUri = @location.absUrl() + "/github" + @githubService.getAuthUrl(callbackUri).then (url) => + @window.open(url, "_self") + else if from == "asana" + @asanaService.getAuthUrl().then (url) => + @window.open(url, "_self") + else + @.from = from + + unfoldOptions: (options) -> + @.unfoldedOptions = options + + isActiveImporter: (importer) -> + if @config.get('importers').indexOf(importer) == -1 + return false + return true + + cancelCurrentImport: () -> + @location.url(@tgNavUrls.resolve('create-project-import')) + + backToCreate: () -> + @location.url(@tgNavUrls.resolve('create-project')) + +angular.module("taigaProjects").controller("ImportProjectCtrl", ImportProjectController) diff --git a/app/modules/projects/create/import/import-project.controller.spec.coffee b/app/modules/projects/create/import/import-project.controller.spec.coffee new file mode 100644 index 00000000..670b6484 --- /dev/null +++ b/app/modules/projects/create/import/import-project.controller.spec.coffee @@ -0,0 +1,183 @@ +### +# Copyright (C) 2014-2015 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: import-project.controller.spec.coffee +### + +describe "ImportProjectCtrl", -> + $provide = null + $controller = null + mocks = {} + + _mockConfig = -> + mocks.config = Immutable.fromJS({ + importers: ['trello', 'github', 'jira', 'asana'] + }) + + $provide.value("$tgConfig", mocks.config) + + _mockTrelloImportService = -> + mocks.trelloService = { + authorize: sinon.stub(), + getAuthUrl: sinon.stub() + } + + $provide.value("tgTrelloImportService", mocks.trelloService) + + _mockJiraImportService = -> + mocks.jiraService = { + authorize: sinon.stub(), + getAuthUrl: sinon.stub() + } + + $provide.value("tgJiraImportService", mocks.jiraService) + + _mockGithubImportService = -> + mocks.githubService = { + authorize: sinon.stub(), + getAuthUrl: sinon.stub() + } + + $provide.value("tgGithubImportService", mocks.githubService) + + _mockAsanaImportService = -> + mocks.asanaService = { + authorize: sinon.stub(), + getAuthUrl: sinon.stub() + } + + $provide.value("tgAsanaImportService", mocks.asanaService) + + _mockWindow = -> + mocks.window = { + open: sinon.stub() + } + + $provide.value("$window", mocks.window) + + _mockLocation = -> + mocks.location = { + search: sinon.stub() + } + + $provide.value("$location", mocks.location) + + _mockRouteParams = -> + mocks.routeParams = { + platform: null + } + + $provide.value("$routeParams", mocks.routeParams) + + _mockTgNavUrls = -> + mocks.tgNavUrls = { + resolve: sinon.stub() + } + + $provide.value("$tgNavUrls", mocks.tgNavUrls) + + _mocks = -> + module (_$provide_) -> + $provide = _$provide_ + + _mockGithubImportService() + _mockTrelloImportService() + _mockJiraImportService() + _mockAsanaImportService() + _mockWindow() + _mockLocation() + _mockTgNavUrls() + _mockRouteParams() + _mockConfig() + + return null + + _inject = -> + inject (_$controller_) -> + $controller = _$controller_ + + _setup = -> + _mocks() + _inject() + + beforeEach -> + module "taigaProjects" + + _setup() + + it "initialize form with trello", (done) -> + searchResult = { + oauth_verifier: 123, + token: "token" + } + + mocks.location.search.returns(searchResult) + mocks.trelloService.authorize.withArgs(123).promise().resolve("token2") + + ctrl = $controller("ImportProjectCtrl") + + mocks.routeParams.platform = 'trello' + + ctrl.start().then () -> + expect(mocks.location.search).have.been.calledWith({token: "token2"}) + + done() + + it "initialize form with github", (done) -> + searchResult = { + code: 123, + token: "token", + from: "github" + } + + mocks.location.search.returns(searchResult) + mocks.githubService.authorize.withArgs(123).promise().resolve("token2") + + ctrl = $controller("ImportProjectCtrl") + + mocks.routeParams.platform = 'github' + + ctrl.start().then () -> + expect(mocks.location.search).have.been.calledWith({token: "token2"}) + + done() + + it "initialize form with asana", (done) -> + searchResult = { + code: 123, + token: encodeURIComponent("{\"token\": 222}") + from: "asana" + } + + mocks.location.search.returns(searchResult) + mocks.asanaService.authorize.withArgs(123).promise().resolve("token2") + + ctrl = $controller("ImportProjectCtrl") + + mocks.routeParams.platform = 'asana' + + ctrl.start().then () -> + expect(mocks.location.search).have.been.calledWith({token: encodeURIComponent(JSON.stringify("token2"))}) + + done() + + it "select trello import", () -> + ctrl = $controller("ImportProjectCtrl") + + mocks.trelloService.getAuthUrl.promise().resolve("url") + + ctrl.select("trello").then () -> + expect(mocks.window.open).have.been.calledWith("url", "_self") diff --git a/app/modules/projects/create/import/import-project.directive.coffee b/app/modules/projects/create/import/import-project.directive.coffee new file mode 100644 index 00000000..f32adec7 --- /dev/null +++ b/app/modules/projects/create/import/import-project.directive.coffee @@ -0,0 +1,38 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: import-project.directive.coffee +### + +ImportProjectDirective = () -> + + link = (scope, el, attr, ctrl) -> + ctrl.start() + + return { + link: link, + templateUrl:"projects/create/import/import-project.html", + controller: "ImportProjectCtrl", + controllerAs: "vm", + bindToController: true, + scope: { + onCancelImport: '&' + } + } + +ImportProjectDirective.$inject = [] + +angular.module("taigaProjects").directive("tgImportProject", ImportProjectDirective) diff --git a/app/modules/projects/create/import/import-project.jade b/app/modules/projects/create/import/import-project.jade new file mode 100644 index 00000000..aae83c75 --- /dev/null +++ b/app/modules/projects/create/import/import-project.jade @@ -0,0 +1,96 @@ +.create-project.import-project(ng-if="!vm.from") + div(ng-include="'projects/create/import/import-header.html'") + + ul.import-project-from + li.import-project-from-site( + tg-click-input-file + tg-import-taiga + ) + li.import-project-from-site( + ng-click="vm.unfoldOptions('jira')" + ng-if="vm.isActiveImporter('jira')" + ) + .import-project-logo + img( + src="/#{v}/images/import-logos/jira.png" + alt="Jira Logo" + ) + .import-project-name-wrapper + span.import-project-name Jira + p.import-project-description(translate="PROJECT.IMPORT.JIRA.SELECTOR") + fieldset.import-project-url(ng-if="vm.unfoldedOptions == 'jira'") + label( + for="jira-host" + translate="PROJECT.IMPORT.JIRA.URL" + ) + input.import-project-input( + ng-keyup="$event.keyCode == 13 && vm.select('jira')" + id="jira-host" + ng-model="vm.jiraUrl" + ) + button.button-green.import-project-button( + ng-click="vm.select('jira')" + title="{{'PROJECT.IMPORT.ACCEEDE' | translate}}" + translate="PROJECT.IMPORT.ACCEEDE" + ) + li.import-project-from-site( + ng-click="vm.select('github')" + ng-if="vm.isActiveImporter('github')" + ) + .import-project-logo + img( + src="/#{v}/images/import-logos/github.png" + alt="Github Logo" + ) + .import-project-name-wrapper + span.import-project-name Github + p.import-project-description(translate="PROJECT.IMPORT.GITHUB.SELECTOR") + li.import-project-from-site( + ng-click="vm.select('trello')" + ng-if="vm.isActiveImporter('trello')" + ) + .import-project-logo + img( + src="/#{v}/images/import-logos/trello.png" + alt="Trello Logo" + ) + .import-project-name-wrapper + span.import-project-name Trello + p.import-project-description(translate="PROJECT.IMPORT.TRELLO.SELECTOR") + li.import-project-from-site( + ng-click="vm.select('asana')" + ng-if="vm.isActiveImporter('asana')" + ) + .import-project-logo + img( + src="/#{v}/images/import-logos/asana.png" + alt="Asana Logo" + ) + .import-project-name-wrapper + span.import-project-name Asana + p.import-project-description(translate="PROJECT.IMPORT.ASANA.SELECTOR") + + .create-project-action + button.trans-button.create-project-action-cancel( + type="button" + ng-click="vm.backToCreate()" + title="{{'PROJECT.CREATE.BACK' | translate}}" + translate="PROJECT.CREATE.BACK" + ) + +tg-trello-import( + ng-if="vm.from == 'trello' && vm.token" + on-cancel="vm.cancelCurrentImport()" +) +tg-jira-import( + ng-if="vm.from == 'jira'" + on-cancel="vm.cancelCurrentImport()" +) +tg-github-import( + ng-if="vm.from == 'github' && vm.token" + on-cancel="vm.cancelCurrentImport()" +) +tg-asana-import( + ng-if="vm.from == 'asana' && vm.token" + on-cancel="vm.cancelCurrentImport()" +) diff --git a/app/modules/projects/create/import/import-project.scss b/app/modules/projects/create/import/import-project.scss new file mode 100644 index 00000000..2c84f33c --- /dev/null +++ b/app/modules/projects/create/import/import-project.scss @@ -0,0 +1,55 @@ +.import-project { + &-from-site { + align-items: center; + border-bottom: 1px solid $whitish; + color: $grayer; + cursor: pointer; + display: flex; + padding: 1rem; + position: relative; + + &:hover { + background: rgba($primary, .1); + transition: background .3s ease-in; + } + &:first-child { + border-top: 1px solid $whitish; + .import-project-name { + margin: 0; + } + .import-project-logo img { + padding: 0 .9rem 0 1rem; + width: 5.1rem; + } + } + } + &-logo { + align-self: flex-start; + margin-right: .5rem; + img { + padding: 0 1rem; + width: 5rem; + } + } + &-name-wrapper { + display: flex; + flex: 1; + flex-direction: column; + justify-content: center; + } + &-description { + @include font-type(light); + margin-bottom: 0; + } + &-url { + margin-top: .5rem; + } + &-input { + vertical-align: middle; + } + &-button { + background: $primary; + color: $white; + padding: .25rem 1rem; + } +} diff --git a/app/modules/projects/create/import/import-project.service.coffee b/app/modules/projects/create/import/import-project.service.coffee new file mode 100644 index 00000000..481d40cb --- /dev/null +++ b/app/modules/projects/create/import/import-project.service.coffee @@ -0,0 +1,126 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: import-project.service.coffee +### + +class ImportProjectService extends taiga.Service + @.$inject = [ + 'tgCurrentUserService', + '$tgAuth', + 'tgLightboxFactory', + '$translate', + '$tgConfirm', + '$location', + '$tgNavUrls' + ] + + constructor: (@currentUserService, @tgAuth, @lightboxFactory, @translate, @confirm, @location, @tgNavUrls) -> + + importPromise: (promise) -> + return promise.then(@.importSuccess.bind(this), @.importError.bind(this)) + + importSuccess: (result) -> + promise = @currentUserService.loadProjects() + promise.then () => + if result.status == 202 # Async mode + title = @translate.instant('PROJECT.IMPORT.ASYNC_IN_PROGRESS_TITLE') + message = @translate.instant('PROJECT.IMPORT.ASYNC_IN_PROGRESS_MESSAGE') + @location.path(@tgNavUrls.resolve('home')) + @confirm.success(title, message) + else # result.status == 201 # Sync mode + ctx = {project: result.data.slug} + @location.path(@tgNavUrls.resolve('project-admin-project-profile-details', ctx)) + msg = @translate.instant('PROJECT.IMPORT.SYNC_SUCCESS') + @confirm.notify('success', msg) + return promise + + importError: (result) -> + promise = @tgAuth.refresh() + promise.then () => + restrictionError = @.getRestrictionError(result) + + if restrictionError + @lightboxFactory.create('tg-lb-import-error', { + class: 'lightbox lightbox-import-error' + }, restrictionError) + + else + errorMsg = @translate.instant("PROJECT.IMPORT.ERROR") + + if result.status == 429 # TOO MANY REQUESTS + errorMsg = @translate.instant("PROJECT.IMPORT.ERROR_TOO_MANY_REQUEST") + else if result.data?._error_message + errorMsg = @translate.instant("PROJECT.IMPORT.ERROR_MESSAGE", {error_message: result.data._error_message}) + + @confirm.notify("error", errorMsg) + return promise + + getRestrictionError: (result) -> + if result.headers + errorKey = '' + + user = @currentUserService.getUser() + maxMemberships = null + + if result.headers.isPrivate + privateError = !@currentUserService.canCreatePrivateProjects().valid + + if user.get('max_memberships_private_projects') != null && result.headers.memberships >= user.get('max_memberships_private_projects') + membersError = true + else + membersError = false + + if privateError && membersError + errorKey = 'private-space-members' + maxMemberships = user.get('max_memberships_private_projects') + else if privateError + errorKey = 'private-space' + else if membersError + errorKey = 'private-members' + maxMemberships = user.get('max_memberships_private_projects') + + else + publicError = !@currentUserService.canCreatePublicProjects().valid + + if user.get('max_memberships_public_projects') != null && result.headers.memberships >= user.get('max_memberships_public_projects') + membersError = true + else + membersError = false + + if publicError && membersError + errorKey = 'public-space-members' + maxMemberships = user.get('max_memberships_public_projects') + else if publicError + errorKey = 'public-space' + else if membersError + errorKey = 'public-members' + maxMemberships = user.get('max_memberships_public_projects') + + if !errorKey + return false + + return { + key: errorKey, + values: { + max_memberships: maxMemberships, + members: result.headers.memberships + } + } + else + return false + +angular.module("taigaProjects").service("tgImportProjectService", ImportProjectService) diff --git a/app/modules/projects/create/import/import-project.service.spec.coffee b/app/modules/projects/create/import/import-project.service.spec.coffee new file mode 100644 index 00000000..78417d7d --- /dev/null +++ b/app/modules/projects/create/import/import-project.service.spec.coffee @@ -0,0 +1,294 @@ +### +# Copyright (C) 2014-2015 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: import-project.service.spec.coffee +### + +describe "tgImportProjectService", -> + $provide = null + importProjectService = null + mocks = {} + + _mockCurrentUserService = -> + mocks.currentUserService = { + loadProjects: sinon.stub(), + getUser: sinon.stub(), + canCreatePrivateProjects: sinon.stub(), + canCreatePublicProjects: sinon.stub() + } + + $provide.value("tgCurrentUserService", mocks.currentUserService) + + _mockAuth = -> + mocks.auth = { + refresh: sinon.stub() + } + + $provide.value("$tgAuth", mocks.auth) + + _mockLightboxFactory = -> + mocks.lightboxFactory = { + create: sinon.stub() + } + + $provide.value("tgLightboxFactory", mocks.lightboxFactory) + + _mockTranslate = -> + mocks.translate = { + instant: sinon.stub() + } + + $provide.value("$translate", mocks.translate) + + _mockConfirm = -> + mocks.confirm = { + success: sinon.stub(), + notify: sinon.stub() + } + + $provide.value("$tgConfirm", mocks.confirm) + + _mockLocation = -> + mocks.location = { + path: sinon.stub() + } + + $provide.value("$location", mocks.location) + + _mockNavUrls = -> + mocks.navUrls = { + resolve: sinon.stub() + } + + $provide.value("$tgNavUrls", mocks.navUrls) + + _mocks = -> + module (_$provide_) -> + $provide = _$provide_ + + _mockCurrentUserService() + _mockAuth() + _mockLightboxFactory() + _mockTranslate() + _mockConfirm() + _mockLocation() + _mockNavUrls() + + return null + + _inject = -> + inject (_tgImportProjectService_) -> + importProjectService = _tgImportProjectService_ + + _setup = -> + _mocks() + _inject() + + beforeEach -> + module "taigaProjects" + + _setup() + + it "import success async mode", (done) -> + result = { + status: 202, + data: { + slug: 'project-slug' + } + } + + mocks.translate.instant.returns('xxx') + + mocks.currentUserService.loadProjects.promise().resolve() + + importProjectService.importSuccess(result).then () -> + expect(mocks.confirm.success).have.been.calledOnce + done() + + it "import success sync mode", (done) -> + result = { + status: 201, + data: { + slug: 'project-slug' + } + } + + mocks.translate.instant.returns('msg') + + mocks.navUrls.resolve.withArgs('project-admin-project-profile-details', {project: 'project-slug'}).returns('url') + + mocks.currentUserService.loadProjects.promise().resolve() + + importProjectService.importSuccess(result).then () -> + expect(mocks.location.path).have.been.calledWith('url') + expect(mocks.confirm.notify).have.been.calledWith('success', 'msg') + done() + + it "private get restriction errors, private & member error", () -> + result = { + headers: { + isPrivate: true, + memberships: 10 + } + } + + mocks.currentUserService.getUser.returns(Immutable.fromJS({ + max_memberships_private_projects: 1 + })) + + mocks.currentUserService.canCreatePrivateProjects.returns({ + valid: false + }) + + error = importProjectService.getRestrictionError(result) + + expect(error).to.be.eql({ + key: 'private-space-members', + values: { + max_memberships: 1, + members: 10 + } + }) + + it "private get restriction errors, private limit error", () -> + result = { + headers: { + isPrivate: true, + memberships: 10 + } + } + + mocks.currentUserService.getUser.returns(Immutable.fromJS({ + max_memberships_private_projects: 20 + })) + + mocks.currentUserService.canCreatePrivateProjects.returns({ + valid: false + }) + + error = importProjectService.getRestrictionError(result) + + expect(error).to.be.eql({ + key: 'private-space', + values: { + max_memberships: null, + members: 10 + } + }) + + it "private get restriction errors, members error", () -> + result = { + headers: { + isPrivate: true, + memberships: 10 + } + } + + mocks.currentUserService.getUser.returns(Immutable.fromJS({ + max_memberships_private_projects: 1 + })) + + mocks.currentUserService.canCreatePrivateProjects.returns({ + valid: true + }) + + error = importProjectService.getRestrictionError(result) + + expect(error).to.be.eql({ + key: 'private-members', + values: { + max_memberships: 1, + members: 10 + } + }) + + it "public get restriction errors, public & member error", () -> + result = { + headers: { + isPrivate: false, + memberships: 10 + } + } + + mocks.currentUserService.getUser.returns(Immutable.fromJS({ + max_memberships_public_projects: 1 + })) + + mocks.currentUserService.canCreatePublicProjects.returns({ + valid: false + }) + + error = importProjectService.getRestrictionError(result) + + expect(error).to.be.eql({ + key: 'public-space-members', + values: { + max_memberships: 1, + members: 10 + } + }) + + it "public get restriction errors, public limit error", () -> + result = { + headers: { + isPrivate: false, + memberships: 10 + } + } + + mocks.currentUserService.getUser.returns(Immutable.fromJS({ + max_memberships_public_projects: 20 + })) + + mocks.currentUserService.canCreatePublicProjects.returns({ + valid: false + }) + + error = importProjectService.getRestrictionError(result) + + expect(error).to.be.eql({ + key: 'public-space', + values: { + max_memberships: null, + members: 10 + } + }) + + it "public get restriction errors, members error", () -> + result = { + headers: { + isPrivate: false, + memberships: 10 + } + } + + mocks.currentUserService.getUser.returns(Immutable.fromJS({ + max_memberships_public_projects: 1 + })) + + mocks.currentUserService.canCreatePublicProjects.returns({ + valid: true + }) + + error = importProjectService.getRestrictionError(result) + + expect(error).to.be.eql({ + key: 'public-members', + values: { + max_memberships: 1, + members: 10 + } + }) diff --git a/app/modules/projects/create/invite-members/invite-members.controller.coffee b/app/modules/projects/create/invite-members/invite-members.controller.coffee new file mode 100644 index 00000000..180cf5ff --- /dev/null +++ b/app/modules/projects/create/invite-members/invite-members.controller.coffee @@ -0,0 +1,26 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: invite-members.controller.coffee +### + +class InviteMembersController + @.$inject = [] + + isDisabled: (id) -> + return @.invitedMembers.indexOf(id) == -1 + +angular.module("taigaProjects").controller("InviteMembersCtrl", InviteMembersController) diff --git a/app/modules/projects/create/invite-members/invite-members.directive.coffee b/app/modules/projects/create/invite-members/invite-members.directive.coffee new file mode 100644 index 00000000..36a8e901 --- /dev/null +++ b/app/modules/projects/create/invite-members/invite-members.directive.coffee @@ -0,0 +1,38 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: invite-members.directive.coffee +### + +InviteMembersDirective = () -> + link = (scope, el, attr, ctrl) -> + + return { + link: link, + templateUrl:"projects/create/invite-members/invite-members.html", + controller: "InviteMembersCtrl", + controllerAs: "vm", + bindToController: true, + scope: { + invitedMembers: '<', + members: '<', + onToggleInvitedMember: '&' + } + } + +InviteMembersDirective.$inject = [] + +angular.module("taigaProjects").directive("tgInviteMembers", InviteMembersDirective) diff --git a/app/modules/projects/create/invite-members/invite-members.jade b/app/modules/projects/create/invite-members/invite-members.jade new file mode 100644 index 00000000..eb5ec521 --- /dev/null +++ b/app/modules/projects/create/invite-members/invite-members.jade @@ -0,0 +1,8 @@ +fieldset.create-project-invite + .create-project-invite-avatars + tg-single-member( + tg-repeat="member in vm.members track by member.get('id')" + disabled="vm.isDisabled(member.get('id'))" + avatar="member" + ng-click="vm.onToggleInvitedMember({member: member.get('id')})" + ) diff --git a/app/modules/projects/create/invite-members/invite-members.scss b/app/modules/projects/create/invite-members/invite-members.scss new file mode 100644 index 00000000..567b51af --- /dev/null +++ b/app/modules/projects/create/invite-members/invite-members.scss @@ -0,0 +1,7 @@ +.create-project-invite { + &-avatars { + display: flex; + flex-wrap: wrap; + } +} + diff --git a/app/modules/projects/create/invite-members/single-member/single-member.directive.coffee b/app/modules/projects/create/invite-members/single-member/single-member.directive.coffee new file mode 100644 index 00000000..dbf63670 --- /dev/null +++ b/app/modules/projects/create/invite-members/single-member/single-member.directive.coffee @@ -0,0 +1,31 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: single-member.directive.coffee +### + +SingleMemberDirective = () -> + return { + templateUrl:"projects/create/invite-members/single-member/single-member.html", + scope: { + disabled: "<", + avatar: "=" + } + } + +SingleMemberDirective.$inject = [] + +angular.module("taigaProjects").directive("tgSingleMember", SingleMemberDirective) diff --git a/app/modules/projects/create/invite-members/single-member/single-member.jade b/app/modules/projects/create/invite-members/single-member/single-member.jade new file mode 100644 index 00000000..1974e4c1 --- /dev/null +++ b/app/modules/projects/create/invite-members/single-member/single-member.jade @@ -0,0 +1,6 @@ +label.create-project-invite-avatar(ng-class="{'disabled': disabled}") + img( + tg-avatar="avatar" + alt="{{avatar.get('full_name_display')}}" + title="{{avatar.get('full_name_display')}}" + ) diff --git a/app/modules/projects/create/invite-members/single-member/single-member.scss b/app/modules/projects/create/invite-members/single-member/single-member.scss new file mode 100644 index 00000000..d0d0c7ec --- /dev/null +++ b/app/modules/projects/create/invite-members/single-member/single-member.scss @@ -0,0 +1,40 @@ +.create-project-invite-avatar { + cursor: pointer; + display: block; + margin-right: .25rem; + &:hover { + @include empty-color(47); + border: 0; + opacity: .9; + transition: all .2s; + transition-delay: .2s; + } + &.disabled { + opacity: .3; + transition: opacity .2s; + &:hover { + @include empty-color(23); + border: 0; + opacity: .6; + transition: all .2s ease-in; + &::after { + background: $grayer; + left: 24px; + top: 8px; + transform: rotate(0); + transform-origin: center; + } + &::before { + background: $grayer; + right: 22px; + top: 8px; + transform: rotate(90deg); + transform-origin: center; + } + } + } + img { + cursor: pointer; + width: 3rem; + } +} diff --git a/app/modules/projects/create/jira-import/jira-import-project-form/jira-import-project-form.controller.coffee b/app/modules/projects/create/jira-import/jira-import-project-form/jira-import-project-form.controller.coffee new file mode 100644 index 00000000..97d2cd6c --- /dev/null +++ b/app/modules/projects/create/jira-import/jira-import-project-form/jira-import-project-form.controller.coffee @@ -0,0 +1,58 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: jira-import-project-form.controller.coffee +### + +class JiraImportProjectFormController + @.$inject = [ + "tgCurrentUserService" + ] + + constructor: (@currentUserService) -> + @.canCreatePublicProjects = @currentUserService.canCreatePublicProjects() + @.canCreatePrivateProjects = @currentUserService.canCreatePrivateProjects() + + @.projectForm = @.project.toJS() + + @.projectForm.is_private = false + @.projectForm.keepExternalReference = false + if @.projectForm.importer_type == "agile" + @.projectForm.project_type = null + else + @.projectForm.project_type = "scrum" + @.projectForm.create_subissues = true + + if !@.canCreatePublicProjects.valid && @.canCreatePrivateProjects.valid + @.projectForm.is_private = true + + checkUsersLimit: () -> + @.limitMembersPrivateProject = @currentUserService.canAddMembersPrivateProject(@.members.size) + @.limitMembersPublicProject = @currentUserService.canAddMembersPublicProject(@.members.size) + + saveForm: () -> + @.onSaveProjectDetails({project: Immutable.fromJS(@.projectForm)}) + + canCreateProject: () -> + if @.projectForm.is_private + return @.canCreatePrivateProjects.valid + else + return @.canCreatePublicProjects.valid + + isDisabled: () -> + return !@.canCreateProject() + +angular.module('taigaProjects').controller('JiraImportProjectFormCtrl', JiraImportProjectFormController) diff --git a/app/modules/projects/create/jira-import/jira-import-project-form/jira-import-project-form.directive.coffee b/app/modules/projects/create/jira-import/jira-import-project-form/jira-import-project-form.directive.coffee new file mode 100644 index 00000000..601d015b --- /dev/null +++ b/app/modules/projects/create/jira-import/jira-import-project-form/jira-import-project-form.directive.coffee @@ -0,0 +1,40 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: jira-import-project-form.directive.coffee +### + +JiraImportProjectFormDirective = () -> + return { + link: (scope, elm, attr, ctrl) -> + scope.$watch('vm.members', ctrl.checkUsersLimit.bind(ctrl)) + + templateUrl:"projects/create/jira-import/jira-import-project-form/jira-import-project-form.html", + controller: "JiraImportProjectFormCtrl", + controllerAs: "vm", + bindToController: true, + scope: { + members: '<', + project: '<', + onSaveProjectDetails: '&', + onCancelForm: '&', + fetchingUsers: '<' + } + } + +JiraImportProjectFormDirective.$inject = [] + +angular.module("taigaProjects").directive("tgJiraImportProjectForm", JiraImportProjectFormDirective) diff --git a/app/modules/projects/create/jira-import/jira-import-project-form/jira-import-project-form.jade b/app/modules/projects/create/jira-import/jira-import-project-form/jira-import-project-form.jade new file mode 100644 index 00000000..864ba248 --- /dev/null +++ b/app/modules/projects/create/jira-import/jira-import-project-form/jira-import-project-form.jade @@ -0,0 +1,126 @@ +.import-project-jira-form + div(ng-include="'projects/create/import/import-header.html'") + + .spin(tg-loading="vm.fetchingUsers") + + form( + ng-if="!vm.fetchingUsers", + name="projectForm", + ng-submit="vm.saveForm()" + ) + div(ng-include="'projects/create/import-project-form-common/name.html'") + div(ng-include="'projects/create/import-project-form-common/description.html'") + + .create-project-import-type(role="group", ng-if="vm.projectForm.importer_type !== 'agile'") + fieldset + input( + type="radio" + name="project_type" + id="template-scrum" + data-required="true" + aria-hidden="true" + ng-value="'scrum'" + ng-model="vm.projectForm.project_type" + required + ) + label(for="template-scrum") + tg-svg(svg-icon="icon-scrum") + span(translate="PROJECT.IMPORT.JIRA.SCRUM_PROJECT") + fieldset + input( + type="radio" + name="project_type" + id="template-kanban" + data-required="true" + aria-hidden="true" + ng-value="'kanban'" + ng-model="vm.projectForm.project_type" + required + ) + label(for="template-kanban") + tg-svg(svg-icon="icon-kanban") + span(translate="PROJECT.IMPORT.JIRA.KANBAN_PROJECT") + fieldset + input( + type="radio" + name="project_type" + id="template-issues" + data-required="true" + aria-hidden="true" + ng-value="'issues'" + ng-model="vm.projectForm.project_type" + required + ) + label(for="template-issues") + tg-svg(svg-icon="icon-issues") + span(translate="PROJECT.IMPORT.JIRA.ISSUES_PROJECT") + + p.create-project-import-type-info( + ng-if="vm.projectForm.project_type == 'scrum'" + translate='PROJECT.IMPORT.JIRA.CREATE_AS_SCRUM_DESCRIPTION' + ) + p.create-project-import-type-info( + ng-if="vm.projectForm.project_type == 'kanban'" + translate='PROJECT.IMPORT.JIRA.CREATE_AS_KANBAN_DESCRIPTION' + ) + .create-project-type-issues-subform(ng-if="vm.projectForm.project_type == 'issues'") + p.create-project-type-issues-subform-title( + translate='PROJECT.IMPORT.JIRA.CREATE_AS_ISSUES_DESCRIPTION' + ) + fieldset.create-project-type-issues-subform-radiogr + label + input( + type="radio" + name="create_subissues" + id="template-issues-create" + data-required="true" + aria-hidden="true" + ng-value="true" + ng-model="vm.projectForm.create_subissues" + required + ) + svg( + viewBox="0 0 16 16" + xmlns="http://www.w3.org/2000/svg" + ) + circle( + cx="7" + cy="7" + r="6" + ) + span.control-indicator(translate="PROJECT.IMPORT.JIRA.CREATE_NEW_ISSUES") + label + input( + type="radio" + name="create_subissues" + id="template-issues-ignore" + data-required="true" + aria-hidden="true" + ng-value="false" + ng-model="vm.projectForm.create_subissues" + required + ) + svg( + viewBox="0 0 16 16" + xmlns="http://www.w3.org/2000/svg" + ) + circle( + cx="7" + cy="7" + r="6" + ) + span.control-indicator(translate="PROJECT.IMPORT.JIRA.NOT_CREATE_NEW_ISSUES") + + div(ng-include="'projects/create/import-project-form-common/project-privacy.html'") + tg-create-project-restrictions( + is-private="vm.projectForm.is_private" + can-create-public-projects="vm.canCreatePublicProjects" + can-create-private-projects="vm.canCreatePrivateProjects" + ) + tg-create-project-members-restrictions( + is-private="vm.projectForm.is_private" + limit-members-private-project="vm.limitMembersPrivateProject" + limit-members-public-project="vm.limitMembersPublicProject" + ) + div(ng-include="'projects/create/import-project-form-common/links.html'") + div(ng-include="'projects/create/import-project-form-common/actions.html'") diff --git a/app/modules/projects/create/jira-import/jira-import-project-form/jira-import-project-form.scss b/app/modules/projects/create/jira-import/jira-import-project-form/jira-import-project-form.scss new file mode 100644 index 00000000..639b5deb --- /dev/null +++ b/app/modules/projects/create/jira-import/jira-import-project-form/jira-import-project-form.scss @@ -0,0 +1,30 @@ +.import-project-jira-form { + @include create-project; +} + +.create-project-import-type-info { + @include font-size(small); + @include font-type(light); + margin-bottom: 1rem; +} + +.create-project-type-issues-subform { + margin: 1rem 0 2rem; + + &-title { + @include font-size(small); + @include font-type(bold); + } + + &-radiogr { + @include radio-group; + } +} + +.create-project-import-type { + margin-bottom: .25rem; + + fieldset { + margin: 0; + } +} diff --git a/app/modules/projects/create/jira-import/jira-import.controller.coffee b/app/modules/projects/create/jira-import/jira-import.controller.coffee new file mode 100644 index 00000000..95238043 --- /dev/null +++ b/app/modules/projects/create/jira-import/jira-import.controller.coffee @@ -0,0 +1,78 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: jira-import.controller.coffee +### + +class JiraImportController + @.$inject = [ + 'tgJiraImportService', + '$tgConfirm', + '$translate', + 'tgImportProjectService', + ] + + constructor: (@jiraImportService, @confirm, @translate, @importProjectService) -> + @.step = 'autorization-jira' + @.project = null + taiga.defineImmutableProperty @, 'projects', () => return @jiraImportService.projects + taiga.defineImmutableProperty @, 'members', () => return @jiraImportService.projectUsers + + startProjectSelector: () -> + @.step = 'project-select-jira' + @jiraImportService.fetchProjects() + + onSelectProject: (project) -> + @.step = 'project-form-jira' + @.project = project + @.fetchingUsers = true + + @jiraImportService.fetchUsers(@.project.get('id')).then () => @.fetchingUsers = false + + onSaveProjectDetails: (project) -> + @.project = project + @.step = 'project-members-jira' + + onCancelMemberSelection: () -> + @.step = 'project-form-jira' + + startImport: (users) -> + loader = @confirm.loader(@translate.instant('PROJECT.IMPORT.IN_PROGRESS.TITLE'), @translate.instant('PROJECT.IMPORT.IN_PROGRESS.DESCRIPTION'), true) + + loader.start() + + projectType = @.project.get('project_type') + if projectType == "issues" and @.project.get('create_subissues') + projectType = "issues-with-subissues" + + promise = @jiraImportService.importProject( + @.project.get('name'), + @.project.get('description'), + @.project.get('id'), + users, + @.project.get('keepExternalReference'), + @.project.get('is_private'), + projectType, + @.project.get('importer_type'), + ) + + @importProjectService.importPromise(promise).then () => loader.stop() + + submitUserSelection: (users) -> + @.startImport(users) + return null + +angular.module('taigaProjects').controller('JiraImportCtrl', JiraImportController) diff --git a/app/modules/projects/create/jira-import/jira-import.controller.spec.coffee b/app/modules/projects/create/jira-import/jira-import.controller.spec.coffee new file mode 100644 index 00000000..f4542dd8 --- /dev/null +++ b/app/modules/projects/create/jira-import/jira-import.controller.spec.coffee @@ -0,0 +1,171 @@ +### +# Copyright (C) 2014-2015 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: jira-import.controller.spec.coffee +### + +describe "JiraImportCtrl", -> + $provide = null + $controller = null + mocks = {} + + _mockCurrentUserService = -> + mocks.currentUserService = { + canAddMembersPrivateProject: sinon.stub() + canAddMembersPublicProject: sinon.stub() + } + + $provide.value("tgCurrentUserService", mocks.currentUserService) + + _mockJiraImportService = -> + mocks.jiraService = { + fetchProjects: sinon.stub(), + fetchUsers: sinon.stub(), + importProject: sinon.stub() + } + + $provide.value("tgJiraImportService", mocks.jiraService) + + _mockImportProjectService = -> + mocks.importProjectService = { + importPromise: sinon.stub() + } + + $provide.value("tgImportProjectService", mocks.importProjectService) + + _mockConfirm = -> + mocks.confirm = { + loader: sinon.stub() + } + + $provide.value("$tgConfirm", mocks.confirm) + + _mockTranslate = -> + mocks.translate = { + instant: sinon.stub() + } + + $provide.value("$translate", mocks.translate) + _mocks = -> + module (_$provide_) -> + $provide = _$provide_ + + _mockJiraImportService() + _mockConfirm() + _mockTranslate() + _mockImportProjectService() + _mockCurrentUserService() + + return null + + _inject = -> + inject (_$controller_) -> + $controller = _$controller_ + + _setup = -> + _mocks() + _inject() + + beforeEach -> + module "taigaProjects" + + _setup() + + it "start project selector", () -> + ctrl = $controller("JiraImportCtrl") + ctrl.startProjectSelector() + + expect(ctrl.step).to.be.equal('project-select-jira') + expect(mocks.jiraService.fetchProjects).have.been.called + + it "on select project reload projects", (done) -> + project = Immutable.fromJS({ + id: 1, + name: "project-name" + }) + + mocks.jiraService.fetchUsers.promise().resolve() + + ctrl = $controller("JiraImportCtrl") + + promise = ctrl.onSelectProject(project) + + expect(ctrl.fetchingUsers).to.be.true + + promise.then () -> + expect(ctrl.fetchingUsers).to.be.false + expect(ctrl.step).to.be.equal('project-form-jira') + expect(ctrl.project).to.be.equal(project) + done() + + it "on save project details reload users", () -> + project = Immutable.fromJS({ + id: 1, + name: "project-name" + }) + + ctrl = $controller("JiraImportCtrl") + ctrl.onSaveProjectDetails(project) + + expect(ctrl.step).to.be.equal('project-members-jira') + expect(ctrl.project).to.be.equal(project) + + it "on select user init import", (done) -> + users = Immutable.fromJS([ + { + id: 0 + }, + { + id: 1 + }, + { + id: 2 + } + ]) + + loaderObj = { + start: sinon.spy(), + update: sinon.stub(), + stop: sinon.spy() + } + + projectResult = { + id: 3, + name: "name" + } + + mocks.confirm.loader.returns(loaderObj) + + mocks.importProjectService.importPromise.promise().resolve() + + ctrl = $controller("JiraImportCtrl") + ctrl.project = Immutable.fromJS({ + id: 1, + name: 'project-name', + description: 'project-description', + keepExternalReference: false, + is_private: true + }) + + + mocks.jiraService.importProject.promise().resolve(projectResult) + + ctrl.startImport(users).then () -> + expect(loaderObj.start).have.been.called + expect(loaderObj.stop).have.been.called + expect(mocks.jiraService.importProject).have.been.calledWith('project-name', 'project-description', 1, users, false, true) + + done() diff --git a/app/modules/projects/create/jira-import/jira-import.directive.coffee b/app/modules/projects/create/jira-import/jira-import.directive.coffee new file mode 100644 index 00000000..33132680 --- /dev/null +++ b/app/modules/projects/create/jira-import/jira-import.directive.coffee @@ -0,0 +1,35 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: jira-import.directive.coffee +### + +JiraImportDirective = () -> + return { + link: (scope, elm, attrs, ctrl) -> + ctrl.startProjectSelector() + templateUrl:"projects/create/jira-import/jira-import.html", + controller: "JiraImportCtrl", + controllerAs: "vm", + bindToController: true, + scope: { + onCancel: '&' + } + } + +JiraImportDirective.$inject = [] + +angular.module("taigaProjects").directive("tgJiraImport", JiraImportDirective) diff --git a/app/modules/projects/create/jira-import/jira-import.jade b/app/modules/projects/create/jira-import/jira-import.jade new file mode 100644 index 00000000..3090dea1 --- /dev/null +++ b/app/modules/projects/create/jira-import/jira-import.jade @@ -0,0 +1,31 @@ +.create-project.import-project(ng-if="vm.step == 'autorization-jira'") + p autorization... + +tg-import-project-selector( + logo="/#{v}/images/import-logos/jira.png" + search="{{ 'PROJECT.IMPORT.JIRA.CHOOSE_PROJECT' | translate }}" + no-projects-msg="{{ 'PROJECT.IMPORT.JIRA.NO_PROJECTS' | translate }}" + projects="vm.projects" + on-cancel="vm.onCancel()" + on-select-project="vm.onSelectProject(project)" + ng-if="vm.step == 'project-select-jira'" +) + +tg-jira-import-project-form( + ng-if="vm.step == 'project-form-jira'" + project="vm.project" + members="vm.members" + fetching-users="vm.fetchingUsers" + on-save-project-details="vm.onSaveProjectDetails(project)" + on-cancel-form="vm.step = 'project-select-jira'" +) + +tg-import-project-members( + ng-if="vm.step == 'project-members-jira'" + platform="Jira" + logo="/#{v}/images/import-logos/jira.png" + project="vm.project" + members="vm.members" + on-submit="vm.submitUserSelection(users)" + on-cancel="vm.onCancelMemberSelection()" +) diff --git a/app/modules/projects/create/jira-import/jira-import.service.coffee b/app/modules/projects/create/jira-import/jira-import.service.coffee new file mode 100644 index 00000000..f9fcbe2e --- /dev/null +++ b/app/modules/projects/create/jira-import/jira-import.service.coffee @@ -0,0 +1,58 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: jira-import.service.coffee +### + +class JiraImportService extends taiga.Service + @.$inject = [ + 'tgResources', + '$location' + ] + + constructor: (@resources, @location) -> + @.projects = Immutable.List() + @.projectUsers = Immutable.List() + + setToken: (token, url) -> + @.token = token + @.url = url + + fetchProjects: () -> + @resources.jiraImporter.listProjects(@.url, @.token).then (projects) => @.projects = projects + + fetchUsers: (projectId) -> + @resources.jiraImporter.listUsers(@.url, @.token, projectId).then (users) => @.projectUsers = users + + importProject: (name, description, projectId, userBindings, keepExternalReference, isPrivate, projectType, importerType) -> + @resources.jiraImporter.importProject(@.url, @.token, name, description, projectId, userBindings, keepExternalReference, isPrivate, projectType, importerType) + + getAuthUrl: (url) -> + return new Promise (resolve) => + @resources.jiraImporter.getAuthUrl(url).then (response) => + @.authUrl = response.data.url + resolve(@.authUrl) + + authorize: () -> + return new Promise (resolve, reject) => + @resources.jiraImporter.authorize().then ((response) => + @.token = response.data.token + @.url = response.data.url + resolve(response.data) + ), (error) -> + reject(new Error(error.status)) + +angular.module("taigaProjects").service("tgJiraImportService", JiraImportService) diff --git a/app/modules/projects/create/jira-import/jira-import.service.spec.coffee b/app/modules/projects/create/jira-import/jira-import.service.spec.coffee new file mode 100644 index 00000000..3b5650d0 --- /dev/null +++ b/app/modules/projects/create/jira-import/jira-import.service.spec.coffee @@ -0,0 +1,129 @@ +### +# Copyright (C) 2014-2015 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: jira-import.controller.spec.coffee +### + +describe "tgJiraImportService", -> + $provide = null + service = null + mocks = {} + + _mockResources = -> + mocks.resources = { + jiraImporter: { + listProjects: sinon.stub(), + listUsers: sinon.stub(), + importProject: sinon.stub(), + getAuthUrl: sinon.stub(), + authorize: sinon.stub() + } + } + + $provide.value("tgResources", mocks.resources) + + _mockLocation = -> + mocks.location = { + search: sinon.stub() + } + + mocks.location.search.returns({ + url: "http://test", + token: 123 + }) + + $provide.value("$location", mocks.location) + + _mocks = -> + module (_$provide_) -> + $provide = _$provide_ + + _mockResources() + _mockLocation() + + return null + + _inject = -> + inject (_tgJiraImportService_) -> + service = _tgJiraImportService_ + + _setup = -> + _mocks() + _inject() + + beforeEach -> + module "taigaProjects" + + _setup() + + it "fetch projects", (done) -> + service.setToken(123, 'http://test') + mocks.resources.jiraImporter.listProjects.withArgs("http://test", 123).promise().resolve('projects') + + service.fetchProjects().then () -> + service.projects = "projects" + done() + + it "fetch user", (done) -> + service.setToken(123, 'http://test') + projectId = 3 + mocks.resources.jiraImporter.listUsers.withArgs("http://test", 123, projectId).promise().resolve('users') + + service.fetchUsers(projectId).then () -> + service.projectUsers = 'users' + done() + + it "import project", () -> + service.setToken(123, 'http://test') + service.url = 'url' + projectId = 2 + + service.importProject(projectId, true, true ,true) + + expect(mocks.resources.jiraImporter.importProject).to.have.been.calledWith('url', 123, projectId, true, true, true) + + it "get auth url", (done) -> + service.setToken(123, 'http://test') + projectId = 3 + + response = { + data: { + url: "url123" + } + } + + mocks.resources.jiraImporter.getAuthUrl.promise("http://test").resolve(response) + + service.getAuthUrl().then (url) -> + expect(url).to.be.equal("url123") + done() + + it "authorize", (done) -> + service.setToken(123, 'http://test') + projectId = 3 + + response = { + data: { + url: "http://test", + token: "token123" + } + } + + mocks.resources.jiraImporter.authorize.withArgs().promise().resolve(response) + + service.authorize().then (token) -> + expect(token).to.be.deep.equal({url: "http://test", token: "token123"}) + done() diff --git a/app/modules/projects/create/select-import-user-lightbox/select-import-user-lightbox.controller.coffee b/app/modules/projects/create/select-import-user-lightbox/select-import-user-lightbox.controller.coffee new file mode 100644 index 00000000..25eba43f --- /dev/null +++ b/app/modules/projects/create/select-import-user-lightbox/select-import-user-lightbox.controller.coffee @@ -0,0 +1,35 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: trello-import-project-members.controller.coffee +### + +class SelectImportUserLightboxCtrl + @.$inject = [] + + constructor: () -> + + start: () -> + @.mode = 'search' + @.invalid = false + + assignUser: () -> + @.onSelectUser({user: @.user, taigaUser: @.userEmail}) + + selectUser: (taigaUser) -> + @.onSelectUser({user: @.user, taigaUser: Immutable.fromJS(taigaUser)}) + +angular.module('taigaProjects').controller('SelectImportUserLightboxCtrl', SelectImportUserLightboxCtrl) diff --git a/app/modules/projects/create/select-import-user-lightbox/select-import-user-lightbox.directive.coffee b/app/modules/projects/create/select-import-user-lightbox/select-import-user-lightbox.directive.coffee new file mode 100644 index 00000000..baf481f5 --- /dev/null +++ b/app/modules/projects/create/select-import-user-lightbox/select-import-user-lightbox.directive.coffee @@ -0,0 +1,54 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: select-import-user-lightbox.directive.coffee +### + +SelectImportUserLightboxDirective = (lightboxService, lightboxKeyboardNavigationService) -> + link = (scope, el, attrs, ctrl) -> + scope.$watch 'vm.visible', (visible) -> + if visible && !el.hasClass('open') + ctrl.start() + lightboxService.open(el, null, scope.vm.onClose).then -> + el.find('input').focus() + lightboxKeyboardNavigationService.init(el) + else if !visible && el.hasClass('open') + lightboxService.close(el).then () -> + ctrl.userEmail = '' + ctrl.usersSearch = '' + + return { + controller: "SelectImportUserLightboxCtrl", + controllerAs: "vm", + bindToController: true, + scope: { + user: '<', + visible: '<', + onClose: '&', + onSelectUser: '&', + selectableUsers: '<', + isPrivate: '<', + limitMembersPrivateProject: '<', + limitMembersPublicProject: '<', + displayEmailSelector: '<' + }, + templateUrl: 'projects/create/select-import-user-lightbox/select-import-user-lightbox.html' + link: link + } + +SelectImportUserLightboxDirective.$inject = ['lightboxService', 'lightboxKeyboardNavigationService'] + +angular.module("taigaProjects").directive("tgSelectImportUserLightbox", SelectImportUserLightboxDirective) diff --git a/app/modules/projects/create/select-import-user-lightbox/select-import-user-lightbox.jade b/app/modules/projects/create/select-import-user-lightbox/select-import-user-lightbox.jade new file mode 100644 index 00000000..cccdfabe --- /dev/null +++ b/app/modules/projects/create/select-import-user-lightbox/select-import-user-lightbox.jade @@ -0,0 +1,88 @@ +tg-lightbox-close(on-close="vm.onClose()") + +.form(ng-if="vm.visible") + .candidate-user + .avatar.empty(ng-if="!vm.user.get('avatar')") {{vm.user.get('full_name')[0].toUpperCase() || vm.user.get('username')[0].toUpperCase()}} + .avatar(ng-if="vm.user.get('avatar')") + img(ng-src="{{vm.user.get('avatar')}}") + span.candidate-user-name {{vm.user.get('full_name') || vm.user.get('username')}} + + h2.title(translate="PROJECT.IMPORT.WHO_IS") + + div.create-project-warning(ng-if="!vm.limitMembersPublicProject.valid && !vm.isPrivate") + tg-svg(svg-icon="icon-exclamation") + span( + translate="PROJECT.IMPORT.PROJECT_RESTRICTIONS.ACCOUNT_ALLOW_MEMBERS", + translate-values="{'members': vm.limitMembersPublicProject.max}" + ) + + div.create-project-warning(ng-if="!vm.limitMembersPrivateProject.valid && vm.isPrivate") + tg-svg(svg-icon="icon-exclamation") + span( + translate="PROJECT.IMPORT.PROJECT_RESTRICTIONS.ACCOUNT_ALLOW_MEMBERS", + translate-values="{'members': vm.limitMembersPrivateProject.max}" + ) + + form( + ng-if="vm.mode == 'mail'" + ng-submit="vm.assignUser()" + ) + div.create-project-warning + tg-svg(svg-icon="icon-exclamation") + span(translate="PROJECT.IMPORT.WARNING_MAIL_USER") + + fieldset + label( + translate="PROJECT.IMPORT.WRITE_EMAIL_LABEL" + for="user-name" + ) + + .group + input( + name="user-name" + type="text", + data-maxlength="500", + ng-model="vm.userEmail" + ) + button.button-green.submit-button( + type="submit", + title="{{'PROJECT.IMPORT.ASSIGN' | translate}}", + translate="PROJECT.IMPORT.ASSIGN" + ) + + button.search-user-mode( + ng-click="vm.mode = 'search'" + ) {{'PROJECT.IMPORT.SEARCH_CONTACT' | translate}} + + div(ng-if="vm.mode == 'search'") + fieldset + input( + type="text", + data-maxlength="500", + placeholder="{{'LIGHTBOX.ASSIGNED_TO.SEARCH' | translate}}", + ng-model="vm.usersSearch" + ) + + .assigned-to-list + .user-list-single( + ng-repeat="user in vm.selectableUsers | toMutable | filter: vm.usersSearch | orderBy:'full_name_display' | limitTo: 5 as filteredCollection", + ng-click="vm.selectUser(user)" + ) + .user-list-avatar + a( + href="#" + title="{{'COMMON.ASSIGNED_TO.TITLE' | translate}}" + ) + img(tg-avatar="user") + a.user-list-name( + href="" + title="{{user.full_name_display || user.full_name || user}}" + ) {{user.full_name_display || user.full_name || user}} + + .more-users(ng-if="filteredCollection.length > 5") + span(translate="COMMON.ASSIGNED_TO.TOO_MANY") + + button.search-user-mode( + ng-click="vm.mode = 'mail'" + ng-if="vm.displayEmailSelector" + ) {{'PROJECT.IMPORT.WRITE_EMAIL' | translate}} diff --git a/app/modules/projects/create/select-import-user-lightbox/select-import-user-lightbox.scss b/app/modules/projects/create/select-import-user-lightbox/select-import-user-lightbox.scss new file mode 100644 index 00000000..6062b314 --- /dev/null +++ b/app/modules/projects/create/select-import-user-lightbox/select-import-user-lightbox.scss @@ -0,0 +1,59 @@ +tg-select-import-user-lightbox { + .form { + flex-basis: 600px; + flex-grow: 0; + width: 600px; + } + .candidate-user { + align-items: center; + display: flex; + justify-content: center; + padding-bottom: 1.5rem; + .candidate-user-name { + margin-left: .5rem; + } + .user-list-avatar { + background-color: $red; + height: 32px; + margin-right: .5rem; + width: 32px; + } + } + .error { + color: $red-light; + text-align: center; + } + .more-users { + @include font-type(light); + @include font-size(small); + padding: 1rem; + text-align: center; + } + .group { + display: flex; + input { + flex-grow: 2; + margin-right: .5rem; + } + .submit-button { + flex-grow: 0; + width: auto; + } + } + .search-user-mode { + @include font-size(small); + background: none; + margin-top: 2rem; + padding: .5rem; + text-align: left; + transition: .2s; + width: 100%; + &:hover { + color: $primary; + } + } + label { + display: block; + padding-bottom: .5rem; + } +} diff --git a/app/modules/projects/create/trello-import/trello-import-project-form/trello-import-project-form.controller.coffee b/app/modules/projects/create/trello-import/trello-import-project-form/trello-import-project-form.controller.coffee new file mode 100644 index 00000000..c4fb6b98 --- /dev/null +++ b/app/modules/projects/create/trello-import/trello-import-project-form/trello-import-project-form.controller.coffee @@ -0,0 +1,54 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: trello-import-project-form.controller.coffee +### + +class TrelloImportProjectFormController + @.$inject = [ + "tgCurrentUserService" + ] + + constructor: (@currentUserService) -> + @.canCreatePublicProjects = @currentUserService.canCreatePublicProjects() + @.canCreatePrivateProjects = @currentUserService.canCreatePrivateProjects() + + @.projectForm = @.project.toJS() + + @.platformName = "Trello" + @.projectForm.is_private = false + @.projectForm.keepExternalReference = false + + if !@.canCreatePublicProjects.valid && @.canCreatePrivateProjects.valid + @.projectForm.is_private = true + + checkUsersLimit: () -> + @.limitMembersPrivateProject = @currentUserService.canAddMembersPrivateProject(@.members.size) + @.limitMembersPublicProject = @currentUserService.canAddMembersPublicProject(@.members.size) + + saveForm: () -> + @.onSaveProjectDetails({project: Immutable.fromJS(@.projectForm)}) + + canCreateProject: () -> + if @.projectForm.is_private + return @.canCreatePrivateProjects.valid + else + return @.canCreatePublicProjects.valid + + isDisabled: () -> + return !@.canCreateProject() + +angular.module('taigaProjects').controller('TrelloImportProjectFormCtrl', TrelloImportProjectFormController) diff --git a/app/modules/projects/create/trello-import/trello-import-project-form/trello-import-project-form.directive.coffee b/app/modules/projects/create/trello-import/trello-import-project-form/trello-import-project-form.directive.coffee new file mode 100644 index 00000000..91cfbfb1 --- /dev/null +++ b/app/modules/projects/create/trello-import/trello-import-project-form/trello-import-project-form.directive.coffee @@ -0,0 +1,40 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: trello-import-project-form.directive.coffee +### + +TrelloImportProjectFormDirective = () -> + return { + link: (scope, elm, attr, ctrl) -> + scope.$watch('vm.members', ctrl.checkUsersLimit.bind(ctrl)) + + templateUrl:"projects/create/trello-import/trello-import-project-form/trello-import-project-form.html", + controller: "TrelloImportProjectFormCtrl", + controllerAs: "vm", + bindToController: true, + scope: { + members: '<', + project: '<', + onSaveProjectDetails: '&', + onCancelForm: '&', + fetchingUsers: '<' + } + } + +TrelloImportProjectFormDirective.$inject = [] + +angular.module("taigaProjects").directive("tgTrelloImportProjectForm", TrelloImportProjectFormDirective) diff --git a/app/modules/projects/create/trello-import/trello-import-project-form/trello-import-project-form.jade b/app/modules/projects/create/trello-import/trello-import-project-form/trello-import-project-form.jade new file mode 100644 index 00000000..576cf489 --- /dev/null +++ b/app/modules/projects/create/trello-import/trello-import-project-form/trello-import-project-form.jade @@ -0,0 +1,25 @@ +.import-project-trello-form.create-project + div(ng-include="'projects/create/import/import-header.html'") + + .spin(tg-loading="vm.fetchingUsers") + + form( + ng-if="!vm.fetchingUsers", + name="projectForm", + ng-submit="vm.saveForm()" + ) + div(ng-include="'projects/create/import-project-form-common/name.html'") + div(ng-include="'projects/create/import-project-form-common/description.html'") + div(ng-include="'projects/create/import-project-form-common/project-privacy.html'") + tg-create-project-restrictions( + is-private="vm.projectForm.is_private" + can-create-public-projects="vm.canCreatePublicProjects" + can-create-private-projects="vm.canCreatePrivateProjects" + ) + tg-create-project-members-restrictions( + is-private="vm.projectForm.is_private" + limit-members-private-project="vm.limitMembersPrivateProject" + limit-members-public-project="vm.limitMembersPublicProject" + ) + div(ng-include="'projects/create/import-project-form-common/links.html'") + div(ng-include="'projects/create/import-project-form-common/actions.html'") diff --git a/app/modules/projects/create/trello-import/trello-import-project-form/trello-import-project-form.scss b/app/modules/projects/create/trello-import/trello-import-project-form/trello-import-project-form.scss new file mode 100644 index 00000000..02491eb7 --- /dev/null +++ b/app/modules/projects/create/trello-import/trello-import-project-form/trello-import-project-form.scss @@ -0,0 +1,3 @@ +.import-project-trello-form { + @include create-project; +} diff --git a/app/modules/projects/create/trello-import/trello-import.controller.coffee b/app/modules/projects/create/trello-import/trello-import.controller.coffee new file mode 100644 index 00000000..b061d77b --- /dev/null +++ b/app/modules/projects/create/trello-import/trello-import.controller.coffee @@ -0,0 +1,71 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: trello-import.controller.coffee +### + +class TrelloImportController + @.$inject = [ + 'tgTrelloImportService', + '$tgConfirm', + '$translate', + 'tgImportProjectService', + ] + + constructor: (@trelloImportService, @confirm, @translate, @importProjectService) -> + @.project = null + taiga.defineImmutableProperty @, 'projects', () => return @trelloImportService.projects + taiga.defineImmutableProperty @, 'members', () => return @trelloImportService.projectUsers + + startProjectSelector: () -> + @trelloImportService.fetchProjects().then () => @.step = 'project-select-trello' + + onSelectProject: (project) -> + @.step = 'project-form-trello' + @.project = project + @.fetchingUsers = true + + @trelloImportService.fetchUsers(@.project.get('id')).then () => @.fetchingUsers = false + + onSaveProjectDetails: (project) -> + @.project = project + @.step = 'project-members-trello' + + onCancelMemberSelection: () -> + @.step = 'project-form-trello' + + startImport: (users) -> + loader = @confirm.loader(@translate.instant('PROJECT.IMPORT.IN_PROGRESS.TITLE'), @translate.instant('PROJECT.IMPORT.IN_PROGRESS.DESCRIPTION'), true) + + loader.start() + + promise = @trelloImportService.importProject( + @.project.get('name'), + @.project.get('description'), + @.project.get('id'), + users, + @.project.get('keepExternalReference'), + @.project.get('is_private') + ) + + @importProjectService.importPromise(promise).then () => loader.stop() + + submitUserSelection: (users) -> + @.startImport(users) + + return null + +angular.module('taigaProjects').controller('TrelloImportCtrl', TrelloImportController) diff --git a/app/modules/projects/create/trello-import/trello-import.controller.spec.coffee b/app/modules/projects/create/trello-import/trello-import.controller.spec.coffee new file mode 100644 index 00000000..c93a3274 --- /dev/null +++ b/app/modules/projects/create/trello-import/trello-import.controller.spec.coffee @@ -0,0 +1,176 @@ +### +# Copyright (C) 2014-2015 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: trello-import.controller.spec.coffee +### + +describe "TrelloImportCtrl", -> + $provide = null + $controller = null + mocks = {} + + _mockCurrentUserService = -> + mocks.currentUserService = { + canAddMembersPrivateProject: sinon.stub() + canAddMembersPublicProject: sinon.stub() + } + + $provide.value("tgCurrentUserService", mocks.currentUserService) + + + _mockImportProjectService = -> + mocks.importProjectService = { + importPromise: sinon.stub() + } + + $provide.value("tgImportProjectService", mocks.importProjectService) + + _mockTrelloImportService = -> + mocks.trelloService = { + fetchProjects: sinon.stub(), + fetchUsers: sinon.stub(), + importProject: sinon.stub() + } + + $provide.value("tgTrelloImportService", mocks.trelloService) + + _mockConfirm = -> + mocks.confirm = { + loader: sinon.stub() + } + + $provide.value("$tgConfirm", mocks.confirm) + + _mockTranslate = -> + mocks.translate = { + instant: sinon.stub() + } + + $provide.value("$translate", mocks.translate) + + _mocks = -> + module (_$provide_) -> + $provide = _$provide_ + + _mockTrelloImportService() + _mockConfirm() + _mockTranslate() + _mockImportProjectService() + _mockCurrentUserService() + + return null + + _inject = -> + inject (_$controller_) -> + $controller = _$controller_ + + _setup = -> + _mocks() + _inject() + + beforeEach -> + module "taigaProjects" + + _setup() + + it "start project selector", () -> + ctrl = $controller("TrelloImportCtrl") + + mocks.trelloService.fetchProjects.promise().resolve() + + ctrl.startProjectSelector().then () -> + expect(ctrl.step).to.be.equal('project-select-trello') + expect(mocks.trelloService.fetchProjects).have.been.called + + it "on select project reload projects", (done) -> + project = Immutable.fromJS({ + id: 1, + name: "project-name" + }) + + mocks.trelloService.fetchUsers.promise().resolve() + + ctrl = $controller("TrelloImportCtrl") + + promise = ctrl.onSelectProject(project) + + expect(ctrl.fetchingUsers).to.be.true + + promise.then () -> + expect(ctrl.fetchingUsers).to.be.false + expect(ctrl.step).to.be.equal('project-form-trello') + expect(ctrl.project).to.be.equal(project) + done() + + it "on save project details reload users", () -> + project = Immutable.fromJS({ + id: 1, + name: "project-name" + }) + + ctrl = $controller("TrelloImportCtrl") + ctrl.onSaveProjectDetails(project) + + expect(ctrl.step).to.be.equal('project-members-trello') + expect(ctrl.project).to.be.equal(project) + + + it "on select user init import", (done) -> + users = Immutable.fromJS([ + { + id: 0 + }, + { + id: 1 + }, + { + id: 2 + } + ]) + + loaderObj = { + start: sinon.spy(), + update: sinon.stub(), + stop: sinon.spy() + } + + projectResult = { + id: 3, + name: "name" + } + + mocks.confirm.loader.returns(loaderObj) + + mocks.importProjectService.importPromise.promise().resolve() + + ctrl = $controller("TrelloImportCtrl") + ctrl.project = Immutable.fromJS({ + id: 1, + name: 'project-name', + description: 'project-description', + keepExternalReference: false, + is_private: true + }) + + + mocks.trelloService.importProject.promise().resolve(projectResult) + + ctrl.startImport(users).then () -> + expect(loaderObj.start).have.been.called + expect(loaderObj.stop).have.been.called + expect(mocks.trelloService.importProject).have.been.calledWith('project-name', 'project-description', 1, users, false, true) + + done() diff --git a/app/modules/projects/create/trello-import/trello-import.directive.coffee b/app/modules/projects/create/trello-import/trello-import.directive.coffee new file mode 100644 index 00000000..63414e3f --- /dev/null +++ b/app/modules/projects/create/trello-import/trello-import.directive.coffee @@ -0,0 +1,35 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: trello-import.directive.coffee +### + +TrelloImportDirective = () -> + return { + link: (scope, elm, attrs, ctrl) -> + ctrl.startProjectSelector() + templateUrl:"projects/create/trello-import/trello-import.html", + controller: "TrelloImportCtrl", + controllerAs: "vm", + bindToController: true, + scope: { + onCancel: '&' + } + } + +TrelloImportDirective.$inject = [] + +angular.module("taigaProjects").directive("tgTrelloImport", TrelloImportDirective) diff --git a/app/modules/projects/create/trello-import/trello-import.jade b/app/modules/projects/create/trello-import/trello-import.jade new file mode 100644 index 00000000..47fb2ba7 --- /dev/null +++ b/app/modules/projects/create/trello-import/trello-import.jade @@ -0,0 +1,28 @@ +tg-import-project-selector( + logo="/#{v}/images/import-logos/trello.png" + search="{{ 'PROJECT.IMPORT.TRELLO.CHOOSE_PROJECT' | translate }}" + no-projects-msg="{{ 'PROJECT.IMPORT.TRELLO.NO_PROJECTS' | translate }}" + projects="vm.projects" + on-cancel="vm.onCancel()" + on-select-project="vm.onSelectProject(project)" + ng-if="vm.step == 'project-select-trello'" +) + +tg-trello-import-project-form( + ng-if="vm.step == 'project-form-trello'" + project="vm.project" + members="vm.members" + fetching-users="vm.fetchingUsers" + on-save-project-details="vm.onSaveProjectDetails(project)" + on-cancel-form="vm.step = 'project-select-trello'" +) + +tg-import-project-members( + ng-if="vm.step == 'project-members-trello'" + platform="Trello" + logo="/#{v}/images/import-logos/trello.png" + project="vm.project" + members="vm.members" + on-submit="vm.submitUserSelection(users)" + on-cancel="vm.onCancelMemberSelection()" +) diff --git a/app/modules/projects/create/trello-import/trello-import.service.coffee b/app/modules/projects/create/trello-import/trello-import.service.coffee new file mode 100644 index 00000000..6792540b --- /dev/null +++ b/app/modules/projects/create/trello-import/trello-import.service.coffee @@ -0,0 +1,56 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: trello-import.service.coffee +### + +class TrelloImportService extends taiga.Service + @.$inject = [ + 'tgResources' + ] + + constructor: (@resources) -> + @.projects = Immutable.List() + @.projectUsers = Immutable.List() + @.token = null + + setToken: (token) -> + @.token = token + + fetchProjects: () -> + @resources.trelloImporter.listProjects(@.token).then (projects) => @.projects = projects + + fetchUsers: (projectId) -> + @resources.trelloImporter.listUsers(@.token, projectId).then (users) => @.projectUsers = users + + importProject: (name, description, projectId, userBindings, keepExternalReference, isPrivate) -> + return @resources.trelloImporter.importProject(@.token, name, description, projectId, userBindings, keepExternalReference, isPrivate) + + getAuthUrl: () -> + return new Promise (resolve) => + @resources.trelloImporter.getAuthUrl().then (response) => + @.authUrl = response.data.url + resolve(@.authUrl) + + authorize: (verifyCode) -> + return new Promise (resolve, reject) => + @resources.trelloImporter.authorize(verifyCode).then ((response) => + @.token = response.data.token + resolve(@.token) + ), (error) -> + reject(new Error(error.status)) + +angular.module("taigaProjects").service("tgTrelloImportService", TrelloImportService) diff --git a/app/modules/projects/create/trello-import/trello-import.service.spec.coffee b/app/modules/projects/create/trello-import/trello-import.service.spec.coffee new file mode 100644 index 00000000..91bd4c78 --- /dev/null +++ b/app/modules/projects/create/trello-import/trello-import.service.spec.coffee @@ -0,0 +1,115 @@ +### +# Copyright (C) 2014-2015 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: trello-import.controller.spec.coffee +### + +describe "tgTrelloImportService", -> + $provide = null + service = null + mocks = {} + + _mockResources = -> + mocks.resources = { + trelloImporter: { + listProjects: sinon.stub(), + listUsers: sinon.stub(), + importProject: sinon.stub(), + getAuthUrl: sinon.stub(), + authorize: sinon.stub() + } + } + + $provide.value("tgResources", mocks.resources) + + _mocks = -> + module (_$provide_) -> + $provide = _$provide_ + + _mockResources() + + return null + + _inject = -> + inject (_tgTrelloImportService_) -> + service = _tgTrelloImportService_ + + _setup = -> + _mocks() + _inject() + + beforeEach -> + module "taigaProjects" + + _setup() + + it "fetch projects", (done) -> + service.setToken(123) + mocks.resources.trelloImporter.listProjects.withArgs(123).promise().resolve('projects') + + service.fetchProjects().then () -> + service.projects = "projects" + done() + + it "fetch user", (done) -> + service.setToken(123) + projectId = 3 + mocks.resources.trelloImporter.listUsers.withArgs(123, projectId).promise().resolve('users') + + service.fetchUsers(projectId).then () -> + service.projectUsers = 'users' + done() + + it "import project", () -> + service.setToken(123) + projectId = 2 + + service.importProject(projectId, true, true ,true) + + expect(mocks.resources.trelloImporter.importProject).to.have.been.calledWith(123, projectId, true, true, true) + + it "get auth url", (done) -> + service.setToken(123) + projectId = 3 + + response = { + data: { + url: "url123" + } + } + + mocks.resources.trelloImporter.getAuthUrl.promise().resolve(response) + + service.getAuthUrl().then (url) -> + expect(url).to.be.equal("url123") + done() + + it "authorize", (done) -> + service.setToken(123) + projectId = 3 + verifyCode = 12345 + + response = { + data: { + token: "token123" + } + } + + mocks.resources.trelloImporter.authorize.withArgs(verifyCode).promise().resolve(response) + + service.authorize(verifyCode).then (token) -> + expect(token).to.be.equal("token123") + done() diff --git a/app/modules/projects/create/warning-user-import-lightbox/warning-user-import-lightbox.directive.coffee b/app/modules/projects/create/warning-user-import-lightbox/warning-user-import-lightbox.directive.coffee new file mode 100644 index 00000000..16781dda --- /dev/null +++ b/app/modules/projects/create/warning-user-import-lightbox/warning-user-import-lightbox.directive.coffee @@ -0,0 +1,41 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: warning-user-import.directive.coffee +### + +WarningUserImportDirective = (lightboxService, lightboxKeyboardNavigationService) -> + return { + link: (scope, el, attr) -> + scope.$watch 'visible', (visible) -> + if visible && !el.hasClass('open') + lightboxService.open(el, scope.onClose).then -> + el.find('input').focus() + lightboxKeyboardNavigationService.init(el) + else if !visible && el.hasClass('open') + lightboxService.close(el) + + templateUrl:"projects/create/warning-user-import-lightbox/warning-user-import-lightbox.html", + scope: { + visible: '<', + onClose: '&', + onConfirm: '&' + } + } + +WarningUserImportDirective.$inject = ['lightboxService', 'lightboxKeyboardNavigationService'] + +angular.module("taigaProjects").directive("tgWarningUserImportLightbox", WarningUserImportDirective) diff --git a/app/modules/projects/create/warning-user-import-lightbox/warning-user-import-lightbox.jade b/app/modules/projects/create/warning-user-import-lightbox/warning-user-import-lightbox.jade new file mode 100644 index 00000000..76b1f400 --- /dev/null +++ b/app/modules/projects/create/warning-user-import-lightbox/warning-user-import-lightbox.jade @@ -0,0 +1,8 @@ +tg-lightbox-close(on-close="onClose()") + +.warning-users-import-lightbox + h1.warning-users-import-title(translate="PROJECT.IMPORT.WARNING.TITLE") + p(translate="PROJECT.IMPORT.WARNING.DESCRIPTION") + .actions + button.button.button-trans(translate="PROJECT.IMPORT.WARNING.CHECK", ng-click="onClose()") + button.button.button-green(type="submit", translate="PROJECT.IMPORT.IMPORT", ng-click="onConfirm()") diff --git a/app/modules/projects/create/warning-user-import-lightbox/warning-user-import-lightbox.scss b/app/modules/projects/create/warning-user-import-lightbox/warning-user-import-lightbox.scss new file mode 100644 index 00000000..b6893a3f --- /dev/null +++ b/app/modules/projects/create/warning-user-import-lightbox/warning-user-import-lightbox.scss @@ -0,0 +1,21 @@ +.warning-users-import-lightbox { + max-width: 600px; + .warning-users-import-title { + text-align: center; + } + .actions { + display: flex; + margin: 2rem; + button { + flex: 1; + &:first-child { + flex: 0; + flex-basis: 40%; + margin-right: .5rem; + } + } + .button-trans { + color: $grayer; + } + } +} diff --git a/app/modules/projects/listing/projects-listing.controller.coffee b/app/modules/projects/listing/projects-listing.controller.coffee index d7a60304..64e3a36f 100644 --- a/app/modules/projects/listing/projects-listing.controller.coffee +++ b/app/modules/projects/listing/projects-listing.controller.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -19,14 +19,10 @@ class ProjectsListingController @.$inject = [ - "tgCurrentUserService", - "tgProjectsService", + "tgCurrentUserService" ] - constructor: (@currentUserService, @projectsService) -> + constructor: (@currentUserService) -> taiga.defineImmutableProperty(@, "projects", () => @currentUserService.projects.get("all")) - newProject: -> - @projectsService.newProject() - angular.module("taigaProjects").controller("ProjectsListing", ProjectsListingController) diff --git a/app/modules/projects/listing/projects-listing.controller.spec.coffee b/app/modules/projects/listing/projects-listing.controller.spec.coffee index d7a3f00d..6742e193 100644 --- a/app/modules/projects/listing/projects-listing.controller.spec.coffee +++ b/app/modules/projects/listing/projects-listing.controller.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -43,16 +43,11 @@ describe "ProjectsListingController", -> _mockProjectsService = () -> stub = sinon.stub() - mocks.projectsService = { - newProject: sinon.stub() - } - provide.value "tgProjectsService", mocks.projectsService _mocks = () -> module ($provide) -> provide = $provide - _mockProjectsService() _mockCurrentUserService() return null @@ -70,11 +65,3 @@ describe "ProjectsListingController", -> $scope: {} expect(pageCtrl.projects).to.be.equal(projects.get('all')) - - it "new project", () -> - pageCtrl = controller "ProjectsListing", - $scope: {} - - pageCtrl.newProject() - - expect(mocks.projectsService.newProject).to.be.calledOnce diff --git a/app/modules/projects/listing/projects-listing.jade b/app/modules/projects/listing/projects-listing.jade index 096af8b6..9c72475b 100644 --- a/app/modules/projects/listing/projects-listing.jade +++ b/app/modules/projects/listing/projects-listing.jade @@ -4,17 +4,10 @@ .create-options a.create-project-btn.button-green( href="#" - ng-click="vm.newProject()" + tg-nav="create-project" title="{{'PROJECT.NAVIGATION.ACTION_CREATE_PROJECT' | translate}}" translate="PROJECT.NAVIGATION.ACTION_CREATE_PROJECT" ) - span(tg-import-project-button) - a.button-blackish.import-project-button( - href="" - title="{{'PROJECT.NAVIGATION.TITLE_IMPORT_PROJECT' | translate}}" - ) - tg-svg(svg-icon="icon-upload") - input.import-file.hidden(type="file") section.project-list-section .project-list diff --git a/app/modules/projects/project/project.controller.coffee b/app/modules/projects/project/project.controller.coffee index 18820098..355787e7 100644 --- a/app/modules/projects/project/project.controller.coffee +++ b/app/modules/projects/project/project.controller.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/projects/project/project.controller.spec.coffee b/app/modules/projects/project/project.controller.spec.coffee index dfcf812b..11258ca9 100644 --- a/app/modules/projects/project/project.controller.spec.coffee +++ b/app/modules/projects/project/project.controller.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/projects/project/project.jade b/app/modules/projects/project/project.jade index 01feadbc..fd5949e1 100644 --- a/app/modules/projects/project/project.jade +++ b/app/modules/projects/project/project.jade @@ -25,6 +25,10 @@ div.wrapper div.track-buttons-container(ng-if="vm.user") tg-like-project-button(project="vm.project") tg-watch-project-button(project="vm.project") + tg-contact-project-button( + ng-if="vm.project.get('is_contact_activated')" + project="vm.project" + ) div.track-container(ng-if="!vm.user") .list-itemtype-track @@ -56,9 +60,13 @@ div.wrapper src="/#{v}/images/looking-for-people.png" title="{{'PROJECT.LOOKING_FOR_PEOPLE' | translate}}" ) - h3 {{'PROJECT.LOOKING_FOR_PEOPLE' | translate}} - p(ng-if="vm.project.get('looking_for_people_note')") - | {{::vm.project.get('looking_for_people_note')}} + h3(ng-class="{'is-empty': !vm.project.get('looking_for_people_note')}") {{'PROJECT.LOOKING_FOR_PEOPLE' | translate}} + p(ng-if="vm.project.get('looking_for_people_note')") {{::vm.project.get('looking_for_people_note')}} + tg-contact-project-button( + ng-if="vm.project.get('is_contact_activated')" + project="vm.project" + layout="large" + ) h2.title {{"PROJECT.SECTION.TEAM" | translate}} ul.involved-team diff --git a/app/modules/projects/projects.module.coffee b/app/modules/projects/projects.module.coffee index ab40dd05..f161970f 100644 --- a/app/modules/projects/projects.module.coffee +++ b/app/modules/projects/projects.module.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/projects/projects.service.coffee b/app/modules/projects/projects.service.coffee index 3c1415d5..d25a7e57 100644 --- a/app/modules/projects/projects.service.coffee +++ b/app/modules/projects/projects.service.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -22,9 +22,15 @@ groupBy = @.taiga.groupBy class ProjectsService extends taiga.Service - @.$inject = ["tgResources", "$projectUrl", "tgLightboxFactory"] + @.$inject = ["tgResources", "$projectUrl"] - constructor: (@rs, @projectUrl, @lightboxFactory) -> + constructor: (@rs, @projectUrl) -> + + create: (data) -> + return @rs.projects.create(data) + + duplicate: (projectId, data) -> + return @rs.projects.duplicate(projectId, data) getProjectBySlug: (projectSlug) -> return @rs.projects.getProjectBySlug(projectSlug) @@ -46,11 +52,6 @@ class ProjectsService extends taiga.Service return project - newProject: -> - @lightboxFactory.create("tg-lb-create-project", { - "class": "wizard-create-project lightbox" - }) - bulkUpdateProjectsOrder: (sortData) -> return @rs.projects.bulkUpdateOrder(sortData) diff --git a/app/modules/projects/projects.service.spec.coffee b/app/modules/projects/projects.service.spec.coffee index 80a98389..f6dcf71c 100644 --- a/app/modules/projects/projects.service.spec.coffee +++ b/app/modules/projects/projects.service.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -46,12 +46,6 @@ describe "tgProjectsService", -> provide.value "$projectUrl", mocks.projectUrl - _mockLightboxFactory = () -> - mocks.lightboxFactory = { - create: sinon.stub() - } - - provide.value "tgLightboxFactory", mocks.lightboxFactory _inject = (callback) -> inject (_$q_, _$rootScope_, _tgProjectsService_) -> @@ -65,7 +59,6 @@ describe "tgProjectsService", -> provide = $provide _mockResources() _mockProjectUrl() - _mockLightboxFactory() _mockAuthService() return null @@ -75,13 +68,6 @@ describe "tgProjectsService", -> _mocks() _inject() - it "newProject, create the wizard lightbox", () -> - projectsService.newProject() - - expect(mocks.lightboxFactory.create).to.have.been.calledWith("tg-lb-create-project", { - "class": "wizard-create-project lightbox" - }) - it "bulkUpdateProjectsOrder and then fetch projects again", () -> projects_order = [ {"id": 8}, diff --git a/app/modules/projects/transfer/cant-own-project-explanation.directive.coffee b/app/modules/projects/transfer/cant-own-project-explanation.directive.coffee index a6ea655c..4d5b7330 100644 --- a/app/modules/projects/transfer/cant-own-project-explanation.directive.coffee +++ b/app/modules/projects/transfer/cant-own-project-explanation.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/projects/transfer/transfer-project.controller.coffee b/app/modules/projects/transfer/transfer-project.controller.coffee index b7bed191..b61b5bcd 100644 --- a/app/modules/projects/transfer/transfer-project.controller.coffee +++ b/app/modules/projects/transfer/transfer-project.controller.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/projects/transfer/transfer-project.controller.spec.coffee b/app/modules/projects/transfer/transfer-project.controller.spec.coffee index 3a854312..442e64b8 100644 --- a/app/modules/projects/transfer/transfer-project.controller.spec.coffee +++ b/app/modules/projects/transfer/transfer-project.controller.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/projects/transfer/transfer-project.directive.coffee b/app/modules/projects/transfer/transfer-project.directive.coffee index 5a117d27..9dbbb4a2 100644 --- a/app/modules/projects/transfer/transfer-project.directive.coffee +++ b/app/modules/projects/transfer/transfer-project.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/resources/attachments-resource.service.coffee b/app/modules/resources/attachments-resource.service.coffee index 94cb1bb2..3fba9af2 100644 --- a/app/modules/resources/attachments-resource.service.coffee +++ b/app/modules/resources/attachments-resource.service.coffee @@ -1,11 +1,11 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -58,7 +58,7 @@ Resource = (urlsService, http, config, $rootScope, $q, storage) -> return http.patch(url, patch) - service.create = (type, projectId, objectId, file) -> + service.create = (type, projectId, objectId, file, from_comment) -> urlname = "attachments/#{type}" url = urlsService.resolve(urlname) @@ -116,6 +116,7 @@ Resource = (urlsService, http, config, $rootScope, $q, storage) -> data.append("project", projectId) data.append("object_id", objectId) data.append("attached_file", file) + data.append("from_comment", from_comment) xhr = new XMLHttpRequest() xhr.upload.addEventListener("progress", uploadProgress, false) diff --git a/app/modules/resources/epics-resource.service.coffee b/app/modules/resources/epics-resource.service.coffee index 30d82791..06e3dd5d 100644 --- a/app/modules/resources/epics-resource.service.coffee +++ b/app/modules/resources/epics-resource.service.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/resources/external-apps-resource.service.coffee b/app/modules/resources/external-apps-resource.service.coffee index 7dd02d27..be42672b 100644 --- a/app/modules/resources/external-apps-resource.service.coffee +++ b/app/modules/resources/external-apps-resource.service.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/resources/importers-resource.service.coffee b/app/modules/resources/importers-resource.service.coffee new file mode 100644 index 00000000..82479bf2 --- /dev/null +++ b/app/modules/resources/importers-resource.service.coffee @@ -0,0 +1,193 @@ +### +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: modules/resources/importers.coffee +### + + +taiga = @.taiga + +TrelloResource = (urlsService, http) -> + service = {} + + service.getAuthUrl = (url) -> + url = urlsService.resolve("importers-trello-auth-url") + return http.get(url) + + service.authorize = (verifyCode) -> + url = urlsService.resolve("importers-trello-authorize") + return http.post(url, {code: verifyCode}) + + service.listProjects = (token) -> + url = urlsService.resolve("importers-trello-list-projects") + return http.post(url, {token: token}).then (response) -> Immutable.fromJS(response.data) + + service.listUsers = (token, projectId) -> + url = urlsService.resolve("importers-trello-list-users") + return http.post(url, {token: token, project: projectId}).then (response) -> Immutable.fromJS(response.data) + + service.importProject = (token, name, description, projectId, userBindings, keepExternalReference, isPrivate) -> + url = urlsService.resolve("importers-trello-import-project") + data = { + token: token, + name: name, + description: description, + project: projectId, + users_bindings: userBindings.toJS(), + keep_external_reference: keepExternalReference, + is_private: isPrivate, + template: "kanban", + } + return http.post(url, data) + + return () -> + return {"trelloImporter": service} + +TrelloResource.$inject = ["$tgUrls", "$tgHttp"] + +JiraResource = (urlsService, http) -> + service = {} + + service.getAuthUrl = (jira_url) -> + url = urlsService.resolve("importers-jira-auth-url") + "?url=" + jira_url + return http.get(url) + + service.authorize = () -> + url = urlsService.resolve("importers-jira-authorize") + return http.post(url) + + service.listProjects = (jira_url, token) -> + url = urlsService.resolve("importers-jira-list-projects") + return http.post(url, {url: jira_url, token: token}).then (response) -> Immutable.fromJS(response.data) + + service.listUsers = (jira_url, token, projectId) -> + url = urlsService.resolve("importers-jira-list-users") + return http.post(url, {url: jira_url, token: token, project: projectId}).then (response) -> Immutable.fromJS(response.data) + + service.importProject = (jira_url, token, name, description, projectId, userBindings, keepExternalReference, isPrivate, projectType, importerType) -> + url = urlsService.resolve("importers-jira-import-project") + projectTemplate = "kanban" + if projectType != "kanban" + projectTemplate = "scrum" + + data = { + url: jira_url, + token: token, + name: name, + description: description, + project: projectId, + users_bindings: userBindings.toJS(), + keep_external_reference: keepExternalReference, + is_private: isPrivate, + project_type: projectType, + importer_type: importerType, + template: projectTemplate, + } + return http.post(url, data) + + return () -> + return {"jiraImporter": service} + +JiraResource.$inject = ["$tgUrls", "$tgHttp"] + +GithubResource = (urlsService, http) -> + service = {} + + service.getAuthUrl = (callbackUri) -> + url = urlsService.resolve("importers-github-auth-url") + "?uri=" + callbackUri + return http.get(url) + + service.authorize = (code) -> + url = urlsService.resolve("importers-github-authorize") + return http.post(url, {code: code}) + + service.listProjects = (token) -> + url = urlsService.resolve("importers-github-list-projects") + return http.post(url, {token: token}).then (response) -> Immutable.fromJS(response.data) + + service.listUsers = (token, projectId) -> + url = urlsService.resolve("importers-github-list-users") + return http.post(url, {token: token, project: projectId}).then (response) -> Immutable.fromJS(response.data) + + service.importProject = (token, name, description, projectId, userBindings, keepExternalReference, isPrivate, projectType) -> + url = urlsService.resolve("importers-github-import-project") + + data = { + token: token, + name: name, + description: description, + project: projectId, + users_bindings: userBindings.toJS(), + keep_external_reference: keepExternalReference, + is_private: isPrivate, + template: projectType, + } + return http.post(url, data) + + return () -> + return {"githubImporter": service} + +GithubResource.$inject = ["$tgUrls", "$tgHttp"] + +AsanaResource = (urlsService, http) -> + service = {} + + service.getAuthUrl = () -> + url = urlsService.resolve("importers-asana-auth-url") + return http.get(url) + + service.authorize = (code) -> + url = urlsService.resolve("importers-asana-authorize") + return http.post(url, {code: code}) + + service.listProjects = (token) -> + url = urlsService.resolve("importers-asana-list-projects") + return http.post(url, {token: token}).then (response) -> Immutable.fromJS(response.data) + + service.listUsers = (token, projectId) -> + url = urlsService.resolve("importers-asana-list-users") + return http.post(url, {token: token, project: projectId}).then (response) -> Immutable.fromJS(response.data) + + service.importProject = (token, name, description, projectId, userBindings, keepExternalReference, isPrivate, projectType) -> + url = urlsService.resolve("importers-asana-import-project") + + data = { + token: token, + name: name, + description: description, + project: projectId, + users_bindings: userBindings.toJS(), + keep_external_reference: keepExternalReference, + is_private: isPrivate, + template: projectType, + } + return http.post(url, data) + + return () -> + return {"asanaImporter": service} + +AsanaResource.$inject = ["$tgUrls", "$tgHttp"] + +module = angular.module("taigaResources2") +module.factory("tgTrelloImportResource", TrelloResource) +module.factory("tgJiraImportResource", JiraResource) +module.factory("tgGithubImportResource", GithubResource) +module.factory("tgAsanaImportResource", AsanaResource) diff --git a/app/modules/resources/issues-resource.service.coffee b/app/modules/resources/issues-resource.service.coffee index 2af88e73..31f51822 100644 --- a/app/modules/resources/issues-resource.service.coffee +++ b/app/modules/resources/issues-resource.service.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/resources/projects-resource.service.coffee b/app/modules/resources/projects-resource.service.coffee index 9df02c3a..978593f4 100644 --- a/app/modules/resources/projects-resource.service.coffee +++ b/app/modules/resources/projects-resource.service.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -22,6 +22,28 @@ pagination = () -> Resource = (urlsService, http, paginateResponseService) -> service = {} + service.create = (data) -> + url = urlsService.resolve('projects') + + return http.post(url, JSON.stringify(data)) + .then (result) => return Immutable.fromJS(result.data) + + service.duplicate = (projectId, data) -> + + url = urlsService.resolve("projects") + url = "#{url}/#{projectId}/duplicate" + + members = data.users.map (member) => {"id": member} + + params = { + "name": data.name, + "description": data.description, + "is_private": data.is_private, + "users": members + } + + return http.post(url, params) + service.getProjects = (params = {}, pagination = true) -> url = urlsService.resolve("projects") @@ -108,6 +130,15 @@ Resource = (urlsService, http, paginateResponseService) -> url = urlsService.resolve("project-unwatch", projectId) return http.post(url) + service.contactProject = (projectId, message) -> + params = { + project: projectId, + comment: message + } + + url = urlsService.resolve("project-contact") + return http.post(url, params) + service.transferValidateToken = (projectId, token) -> data = { token: token diff --git a/app/modules/resources/resources.coffee b/app/modules/resources/resources.coffee index f55dd7cc..b108b77f 100644 --- a/app/modules/resources/resources.coffee +++ b/app/modules/resources/resources.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -28,7 +28,11 @@ services = [ "tgAttachmentsResource", "tgStatsResource", "tgWikiHistory", - "tgEpicsResource" + "tgEpicsResource", + "tgTrelloImportResource", + "tgJiraImportResource", + "tgGithubImportResource", + "tgAsanaImportResource" ] Resources = ($injector) -> @@ -39,7 +43,7 @@ Resources = ($injector) -> for serviceProperty in Object.keys(service) if @[serviceProperty] - console.warm("repeated resource " + serviceProperty) + console.warn("repeated resource " + serviceProperty) @[serviceProperty] = service[serviceProperty] diff --git a/app/modules/resources/resources.module.coffee b/app/modules/resources/resources.module.coffee index de2f52b5..206b7a73 100644 --- a/app/modules/resources/resources.module.coffee +++ b/app/modules/resources/resources.module.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/resources/tasks-resource.service.coffee b/app/modules/resources/tasks-resource.service.coffee index 1d056635..e4cc845f 100644 --- a/app/modules/resources/tasks-resource.service.coffee +++ b/app/modules/resources/tasks-resource.service.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/resources/user-resource.service.coffee b/app/modules/resources/user-resource.service.coffee index 3967c6d6..9850d9bc 100644 --- a/app/modules/resources/user-resource.service.coffee +++ b/app/modules/resources/user-resource.service.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/resources/users-resource.service.coffee b/app/modules/resources/users-resource.service.coffee index 1183fb09..6a6a053e 100644 --- a/app/modules/resources/users-resource.service.coffee +++ b/app/modules/resources/users-resource.service.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -50,16 +50,19 @@ Resource = (urlsService, http, paginateResponseService) -> .then (result) -> return Immutable.fromJS(result.data) - service.getContacts = (userId) -> + service.getContacts = (userId, excludeProjectId) -> url = urlsService.resolve("user-contacts", userId) + params = {} + params.exclude_project = excludeProjectId if excludeProjectId? + httpOptions = { headers: { "x-disable-pagination": "1" } } - return http.get(url, {}, httpOptions) + return http.get(url, params, httpOptions) .then (result) -> return Immutable.fromJS(result.data) diff --git a/app/modules/resources/userstories-resource.service.coffee b/app/modules/resources/userstories-resource.service.coffee index 23a9a297..20406e2a 100644 --- a/app/modules/resources/userstories-resource.service.coffee +++ b/app/modules/resources/userstories-resource.service.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/resources/wiki-resource.service.coffee b/app/modules/resources/wiki-resource.service.coffee index 6c3a67fe..01a03d6a 100644 --- a/app/modules/resources/wiki-resource.service.coffee +++ b/app/modules/resources/wiki-resource.service.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/services/app-meta.service.coffee b/app/modules/services/app-meta.service.coffee index e3382e7e..66d1125e 100644 --- a/app/modules/services/app-meta.service.coffee +++ b/app/modules/services/app-meta.service.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/services/app-meta.service.spec.coffee b/app/modules/services/app-meta.service.spec.coffee index 9fa8045f..d833a055 100644 --- a/app/modules/services/app-meta.service.spec.coffee +++ b/app/modules/services/app-meta.service.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/services/attachments.service.coffee b/app/modules/services/attachments.service.coffee index 5ebfa0ce..89069785 100644 --- a/app/modules/services/attachments.service.coffee +++ b/app/modules/services/attachments.service.coffee @@ -70,8 +70,8 @@ class AttachmentsService @confirm.notify("error", message) - upload: (file, objId, projectId, type) -> - promise = @rs.attachments.create(type, projectId, objId, file) + upload: (file, objId, projectId, type, from_comment = false) -> + promise = @rs.attachments.create(type, projectId, objId, file, from_comment) promise.then null, @.saveError.bind(this, file) diff --git a/app/modules/services/check-permissions.service.coffee b/app/modules/services/check-permissions.service.coffee index ad0cd7e9..90256425 100644 --- a/app/modules/services/check-permissions.service.coffee +++ b/app/modules/services/check-permissions.service.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/services/check-permissions.service.spec.coffee b/app/modules/services/check-permissions.service.spec.coffee index 48f727b6..0dc36367 100644 --- a/app/modules/services/check-permissions.service.spec.coffee +++ b/app/modules/services/check-permissions.service.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/services/current-user.service.coffee b/app/modules/services/current-user.service.coffee index 60985801..7a106c5e 100644 --- a/app/modules/services/current-user.service.coffee +++ b/app/modules/services/current-user.service.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -121,7 +121,13 @@ class CurrentUserService canCreatePrivateProjects: () -> user = @.getUser() if user.get('max_private_projects') != null && user.get('total_private_projects') >= user.get('max_private_projects') - return {valid: false, reason: 'max_private_projects', type: 'private_project'} + return { + valid: false, + reason: 'max_private_projects', + type: 'private_project', + current: user.get('total_private_projects'), + max: user.get('max_private_projects') + } return {valid: true} @@ -129,7 +135,41 @@ class CurrentUserService user = @.getUser() if user.get('max_public_projects') != null && user.get('total_public_projects') >= user.get('max_public_projects') - return {valid: false, reason: 'max_public_projects', type: 'public_project'} + return { + valid: false, + reason: 'max_public_projects', + type: 'public_project', + current: user.get('total_public_projects'), + max: user.get('max_public_projects') + } + + return {valid: true} + + canAddMembersPublicProject: (totalMembers) -> + user = @.getUser() + + if user.get('max_memberships_public_projects') != null && totalMembers > user.get('max_memberships_public_projects') + return { + valid: false, + reason: 'max_members_public_projects', + type: 'public_project', + current: totalMembers, + max: user.get('max_memberships_public_projects') + } + + return {valid: true} + + canAddMembersPrivateProject: (totalMembers) -> + user = @.getUser() + + if user.get('max_memberships_private_projects') != null && totalMembers > user.get('max_memberships_private_projects') + return { + valid: false, + reason: 'max_members_private_projects', + type: 'private_project', + current: totalMembers, + max: user.get('max_memberships_private_projects') + } return {valid: true} @@ -139,15 +179,14 @@ class CurrentUserService result = @.canCreatePrivateProjects() return result if !result.valid - if user.get('max_memberships_private_projects') != null && project.get('total_memberships') > user.get('max_memberships_private_projects') - return {valid: false, reason: 'max_members_private_projects', type: 'private_project'} - + membersResult = @.canAddMembersPrivateProject(project.get('total_memberships')) + return membersResult if !membersResult.valid else result = @.canCreatePublicProjects() return result if !result.valid - if user.get('max_memberships_public_projects') != null && project.get('total_memberships') > user.get('max_memberships_public_projects') - return {valid: false, reason: 'max_members_public_projects', type: 'public_project'} + membersResult = @.canAddMembersPublicProject(project.get('total_memberships')) + return membersResult if !membersResult.valid return {valid: true} diff --git a/app/modules/services/current-user.service.spec.coffee b/app/modules/services/current-user.service.spec.coffee index 96f4fff2..d08179d2 100644 --- a/app/modules/services/current-user.service.spec.coffee +++ b/app/modules/services/current-user.service.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -219,7 +219,9 @@ describe "tgCurrentUserService", -> expect(result).to.be.eql({ valid: false, reason: 'max_private_projects', - type: 'private_project' + type: 'private_project', + current: 1, + max: 1 }) it "the user can create private projects", () -> @@ -254,7 +256,9 @@ describe "tgCurrentUserService", -> expect(result).to.be.eql({ valid: false, reason: 'max_public_projects', - type: 'public_project' + type: 'public_project', + current: 1, + max: 1 }) it "the user can create public projects", () -> @@ -321,7 +325,9 @@ describe "tgCurrentUserService", -> expect(result).to.be.eql({ valid: false reason: 'max_public_projects' - type: 'public_project' + type: 'public_project', + current: 1, + max: 1 }) @@ -348,7 +354,9 @@ describe "tgCurrentUserService", -> expect(result).to.be.eql({ valid: false reason: 'max_members_public_projects' - type: 'public_project' + type: 'public_project', + current: 5, + max: 4 }) it "the user can own private project", () -> @@ -398,7 +406,9 @@ describe "tgCurrentUserService", -> expect(result).to.be.eql({ valid: false reason: 'max_private_projects' - type: 'private_project' + type: 'private_project', + current: 1, + max: 1 }) @@ -425,5 +435,7 @@ describe "tgCurrentUserService", -> expect(result).to.be.eql({ valid: false reason: 'max_members_private_projects' - type: 'private_project' + type: 'private_project', + current: 5, + max: 4 }) diff --git a/app/modules/services/error-handling.service.coffee b/app/modules/services/error-handling.service.coffee index 66576c39..c67fe2d9 100644 --- a/app/modules/services/error-handling.service.coffee +++ b/app/modules/services/error-handling.service.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/services/lightbox-factory.service.coffee b/app/modules/services/lightbox-factory.service.coffee index 04c9822f..ac7ed52d 100644 --- a/app/modules/services/lightbox-factory.service.coffee +++ b/app/modules/services/lightbox-factory.service.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/services/lightbox-factory.service.spec.coffee b/app/modules/services/lightbox-factory.service.spec.coffee index 96628e51..2a41ee4f 100644 --- a/app/modules/services/lightbox-factory.service.spec.coffee +++ b/app/modules/services/lightbox-factory.service.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/services/paginate-response.service.coffee b/app/modules/services/paginate-response.service.coffee index dce8b495..f55f1643 100644 --- a/app/modules/services/paginate-response.service.coffee +++ b/app/modules/services/paginate-response.service.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/services/paginate-response.service.spec.coffee b/app/modules/services/paginate-response.service.spec.coffee index e69e6906..2b48038b 100644 --- a/app/modules/services/paginate-response.service.spec.coffee +++ b/app/modules/services/paginate-response.service.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/services/project.service.coffee b/app/modules/services/project.service.coffee index 649147b4..2ba8f033 100644 --- a/app/modules/services/project.service.coffee +++ b/app/modules/services/project.service.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -22,10 +22,12 @@ taiga = @.taiga class ProjectService @.$inject = [ "tgProjectsService", - "tgXhrErrorService" + "tgXhrErrorService", + "tgUserActivityService", + "$interval" ] - constructor: (@projectsService, @xhrError) -> + constructor: (@projectsService, @xhrError, @userActivityService, @interval) -> @._project = null @._section = null @._sectionsBreadcrumb = Immutable.List() @@ -36,12 +38,24 @@ class ProjectService taiga.defineImmutableProperty @, "sectionsBreadcrumb", () => return @._sectionsBreadcrumb taiga.defineImmutableProperty @, "activeMembers", () => return @._activeMembers + @.autoRefresh() if !window.localStorage.e2e + cleanProject: () -> @._project = null @._activeMembers = Immutable.List() @._section = null @._sectionsBreadcrumb = Immutable.List() + autoRefresh: () -> + intervalId = @interval () => + @.fetchProject() + , 60 * 10 * 1000 + + @userActivityService.onInactive () => @interval.cancel(intervalId) + @userActivityService.onActive () => + @.fetchProject() + @.autoRefresh() + setSection: (section) -> @._section = section @@ -68,6 +82,8 @@ class ProjectService else resolve() fetchProject: () -> + return if !@.project + pslug = @.project.get('slug') return @projectsService.getProjectBySlug(pslug).then (project) => @.setProject(project) diff --git a/app/modules/services/project.service.spec.coffee b/app/modules/services/project.service.spec.coffee index 20f529d1..567cac30 100644 --- a/app/modules/services/project.service.spec.coffee +++ b/app/modules/services/project.service.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -19,6 +19,7 @@ describe "tgProjectService", -> $provide = null + $interval = null mocks = {} projectService = null @@ -29,6 +30,14 @@ describe "tgProjectService", -> $provide.value "tgProjectsService", mocks.projectsService + _mockUserActivityService = () -> + mocks.userActivityService = { + onInactive: sinon.stub(), + onActive: sinon.stub() + } + + $provide.value "tgUserActivityService", mocks.userActivityService + _mockXhrErrorService = () -> mocks.xhrErrorService = { response: sinon.stub() @@ -42,6 +51,7 @@ describe "tgProjectService", -> _mockProjectsService() _mockXhrErrorService() + _mockUserActivityService() return null @@ -49,8 +59,9 @@ describe "tgProjectService", -> _mocks() _inject = () -> - inject (_tgProjectService_) -> + inject (_tgProjectService_, _$interval_) -> projectService = _tgProjectService_ + $interval = _$interval_ beforeEach -> module "taigaCommon" @@ -157,3 +168,35 @@ describe "tgProjectService", -> expect(perm1).to.be.true expect(perm2).to.be.false + + it "autorefresh project interval", () -> + projectService.fetchProject = sinon.spy() + + expect(projectService.fetchProject).not.to.have.been.called + + $interval.flush(60 * 11 * 1000) + + expect(projectService.fetchProject).to.have.been.called + + it "cancel interval on user inactivity", () -> + $interval.cancel = sinon.spy() + + projectService.fetchProject = sinon.spy() + + expect($interval.cancel).not.to.have.been.called + + mocks.userActivityService.onInactive.callArg(0) + + expect($interval.cancel).to.have.been.called + + it "fech project if the user restars the activity", () -> + projectService.fetchProject = sinon.spy() + projectService.autoRefresh = sinon.spy() + + expect(projectService.fetchProject).not.to.have.been.called + expect(projectService.autoRefresh).not.to.have.been.called + + mocks.userActivityService.onActive.callArg(0) + + expect(projectService.fetchProject).to.have.been.called + expect(projectService.autoRefresh).to.have.been.called diff --git a/app/modules/services/theme.service.coffee b/app/modules/services/theme.service.coffee index d3b096e5..cfe56256 100644 --- a/app/modules/services/theme.service.coffee +++ b/app/modules/services/theme.service.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/services/theme.service.spec.coffee b/app/modules/services/theme.service.spec.coffee index 4a7c3450..0cc4d091 100644 --- a/app/modules/services/theme.service.spec.coffee +++ b/app/modules/services/theme.service.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/services/user-activity.service.coffee b/app/modules/services/user-activity.service.coffee new file mode 100644 index 00000000..b26ed9dc --- /dev/null +++ b/app/modules/services/user-activity.service.coffee @@ -0,0 +1,79 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: user-activity.service.coffee +### + +taiga = @.taiga + +groupBy = @.taiga.groupBy + +class UserActivityService + @.$inject = ['$timeout'] + + idleTimeout: 60 * 5 * 1000 + + constructor: (@timeout) -> + return null if window.localStorage.e2e + + window.addEventListener('mousemove', @.resetTimer.bind(this), false) + window.addEventListener('mousedown', @.resetTimer.bind(this), false) + window.addEventListener('keypress', @.resetTimer.bind(this), false) + window.addEventListener('mousewheel', @.resetTimer.bind(this), false) + window.addEventListener('touchmove', @.resetTimer.bind(this), false) + + @.subscriptionsActive = [] + @.subscriptionsInactive = [] + @.isActive = true + + @.startTimer() + + startTimer: () -> + @.timerId = @timeout(@._fireInactive.bind(this), @.idleTimeout) + + resetTimer: () -> + if !@.isActive + @._fireActive() + + @timeout.cancel(@.timerId) + @.startTimer() + + @.isActive = true + + onActive: (cb) -> + @.subscriptionsActive.push(cb) + + return @._unSubscriptionsActive.bind(this, cb) + + onInactive: (cb) -> + @.subscriptionsInactive.push(cb) + + return @._unSubscriptionsInactive.bind(this, cb) + + _fireActive: () -> + @.subscriptionsActive.forEach (it) -> it() + + _fireInactive: () -> + @.isActive = false + @.subscriptionsInactive.forEach (it) -> it() + + _unSubscriptionsActive: (cb) -> + @.subscriptionsActive = @.subscriptionsActive.filter (fn) -> fn != cb + + _unSubscriptionsInactive: (cb) -> + @.subscriptionsInactive = @.subscriptionsInactive.filter (fn) -> fn != cb + +angular.module("taigaCommon").service("tgUserActivityService", UserActivityService) diff --git a/app/modules/services/user-activity.service.spec.coffee b/app/modules/services/user-activity.service.spec.coffee new file mode 100644 index 00000000..dd03548c --- /dev/null +++ b/app/modules/services/user-activity.service.spec.coffee @@ -0,0 +1,79 @@ +### +# Copyright (C) 2014-2017 Taiga Agile LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: app-meta.service.spec.coffee +### + +angular.module("taigaCommon").provider("$exceptionHandler", angular.mock.$ExceptionHandlerProvider) + +describe "UserActivityService", -> + userActivityService = null + $timeout = null + + _inject = () -> + inject (_tgUserActivityService_, _$timeout_) -> + userActivityService = _tgUserActivityService_ + $timeout = _$timeout_ + + beforeEach -> + module "taigaCommon" + _inject() + + it "inactive", (done) -> + active = sinon.spy() + userActivityService.onInactive () -> + expect(active).not.to.have.been.called; + done() + + userActivityService.onActive(active) + + $timeout.flush() + + it "unsubscribe inactive", (done) -> + unsubscribe = userActivityService.onInactive () -> + unsubscribe() + + expect(userActivityService.subscriptionsInactive).to.have.length(0) + + done() + + expect(userActivityService.subscriptionsInactive).to.have.length(1) + + $timeout.flush() + + it "active", (done) -> + inactive = sinon.spy() + userActivityService.onInactive(inactive) + + userActivityService.onActive () -> + expect(inactive).to.have.been.called; + done() + + $timeout.flush() + userActivityService.resetTimer() + + it "unsubscribe active", (done) -> + unsubscribe = userActivityService.onActive () -> + unsubscribe() + + expect(userActivityService.subscriptionsActive).to.have.length(0) + + done() + + expect(userActivityService.subscriptionsActive).to.have.length(1) + + $timeout.flush() + userActivityService.resetTimer() diff --git a/app/modules/services/user.service.coffee b/app/modules/services/user.service.coffee index b986c1f4..fce6357a 100644 --- a/app/modules/services/user.service.coffee +++ b/app/modules/services/user.service.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -30,8 +30,8 @@ class UserService extends taiga.Service getUserByUserName: (username) -> return @rs.users.getUserByUsername(username) - getContacts: (userId) -> - return @rs.users.getContacts(userId) + getContacts: (userId, excludeProjectId) -> + return @rs.users.getContacts(userId, excludeProjectId) getLiked: (userId, pageNumber, objectType, textQuery) -> return @rs.users.getLiked(userId, pageNumber, objectType, textQuery) diff --git a/app/modules/services/user.service.spec.coffee b/app/modules/services/user.service.spec.coffee index f721d19b..744f2ec2 100644 --- a/app/modules/services/user.service.spec.coffee +++ b/app/modules/services/user.service.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/services/xhrError.service.coffee b/app/modules/services/xhrError.service.coffee index 42de3515..f24ec0b1 100644 --- a/app/modules/services/xhrError.service.coffee +++ b/app/modules/services/xhrError.service.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/services/xhrError.service.spec.coffee b/app/modules/services/xhrError.service.spec.coffee index 2efc12ef..d6bea130 100644 --- a/app/modules/services/xhrError.service.spec.coffee +++ b/app/modules/services/xhrError.service.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/user-timeline/user-timeline-attachment/user-timeline-attachment.directive.coffee b/app/modules/user-timeline/user-timeline-attachment/user-timeline-attachment.directive.coffee index ced341ac..7ec57ed2 100644 --- a/app/modules/user-timeline/user-timeline-attachment/user-timeline-attachment.directive.coffee +++ b/app/modules/user-timeline/user-timeline-attachment/user-timeline-attachment.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/user-timeline/user-timeline-attachment/user-timeline-attachment.directive.spec.coffee b/app/modules/user-timeline/user-timeline-attachment/user-timeline-attachment.directive.spec.coffee index e9c1d39b..68ca30b9 100644 --- a/app/modules/user-timeline/user-timeline-attachment/user-timeline-attachment.directive.spec.coffee +++ b/app/modules/user-timeline/user-timeline-attachment/user-timeline-attachment.directive.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/user-timeline/user-timeline-item/user-timeline-item-title.service.coffee b/app/modules/user-timeline/user-timeline-item/user-timeline-item-title.service.coffee index 84a189c3..92622694 100644 --- a/app/modules/user-timeline/user-timeline-item/user-timeline-item-title.service.coffee +++ b/app/modules/user-timeline/user-timeline-item/user-timeline-item-title.service.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/user-timeline/user-timeline-item/user-timeline-item-title.service.spec.coffee b/app/modules/user-timeline/user-timeline-item/user-timeline-item-title.service.spec.coffee index 64f306f4..d0fc3313 100644 --- a/app/modules/user-timeline/user-timeline-item/user-timeline-item-title.service.spec.coffee +++ b/app/modules/user-timeline/user-timeline-item/user-timeline-item-title.service.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/user-timeline/user-timeline-item/user-timeline-item-type.service.coffee b/app/modules/user-timeline/user-timeline-item/user-timeline-item-type.service.coffee index 9e33dcd0..045682cc 100644 --- a/app/modules/user-timeline/user-timeline-item/user-timeline-item-type.service.coffee +++ b/app/modules/user-timeline/user-timeline-item/user-timeline-item-type.service.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/user-timeline/user-timeline-item/user-timeline-item-type.service.spec.coffee b/app/modules/user-timeline/user-timeline-item/user-timeline-item-type.service.spec.coffee index 9ac0339e..096ce795 100644 --- a/app/modules/user-timeline/user-timeline-item/user-timeline-item-type.service.spec.coffee +++ b/app/modules/user-timeline/user-timeline-item/user-timeline-item-type.service.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/user-timeline/user-timeline-item/user-timeline-item.directive.coffee b/app/modules/user-timeline/user-timeline-item/user-timeline-item.directive.coffee index 9fff02c3..97e6ec2a 100644 --- a/app/modules/user-timeline/user-timeline-item/user-timeline-item.directive.coffee +++ b/app/modules/user-timeline/user-timeline-item/user-timeline-item.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/user-timeline/user-timeline-pagination-sequence/user-timeline-pagination-sequence.service.coffee b/app/modules/user-timeline/user-timeline-pagination-sequence/user-timeline-pagination-sequence.service.coffee index 616caf7e..5cdb7286 100644 --- a/app/modules/user-timeline/user-timeline-pagination-sequence/user-timeline-pagination-sequence.service.coffee +++ b/app/modules/user-timeline/user-timeline-pagination-sequence/user-timeline-pagination-sequence.service.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/user-timeline/user-timeline-pagination-sequence/user-timeline-pagination-sequence.service.spec.coffee b/app/modules/user-timeline/user-timeline-pagination-sequence/user-timeline-pagination-sequence.service.spec.coffee index 7baebf6e..14696adb 100644 --- a/app/modules/user-timeline/user-timeline-pagination-sequence/user-timeline-pagination-sequence.service.spec.coffee +++ b/app/modules/user-timeline/user-timeline-pagination-sequence/user-timeline-pagination-sequence.service.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/user-timeline/user-timeline.module.coffee b/app/modules/user-timeline/user-timeline.module.coffee index 3bdab1fe..f1ccf67c 100644 --- a/app/modules/user-timeline/user-timeline.module.coffee +++ b/app/modules/user-timeline/user-timeline.module.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/user-timeline/user-timeline/user-timeline.controller.coffee b/app/modules/user-timeline/user-timeline/user-timeline.controller.coffee index b426672c..d8c062a3 100644 --- a/app/modules/user-timeline/user-timeline/user-timeline.controller.coffee +++ b/app/modules/user-timeline/user-timeline/user-timeline.controller.coffee @@ -1,10 +1,10 @@ ### -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino Garcia -# Copyright (C) 2014-2016 David Barragán Merino -# Copyright (C) 2014-2016 Alejandro Alonso -# Copyright (C) 2014-2016 Juan Francisco Alcántara -# Copyright (C) 2014-2016 Xavi Julian +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino Garcia +# Copyright (C) 2014-2017 David Barragán Merino +# Copyright (C) 2014-2017 Alejandro Alonso +# Copyright (C) 2014-2017 Juan Francisco Alcántara +# Copyright (C) 2014-2017 Xavi Julian # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/user-timeline/user-timeline/user-timeline.controller.spec.coffee b/app/modules/user-timeline/user-timeline/user-timeline.controller.spec.coffee index 519f79be..68e7a6ba 100644 --- a/app/modules/user-timeline/user-timeline/user-timeline.controller.spec.coffee +++ b/app/modules/user-timeline/user-timeline/user-timeline.controller.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/user-timeline/user-timeline/user-timeline.directive.coffee b/app/modules/user-timeline/user-timeline/user-timeline.directive.coffee index fda9bb7b..698ae76b 100644 --- a/app/modules/user-timeline/user-timeline/user-timeline.directive.coffee +++ b/app/modules/user-timeline/user-timeline/user-timeline.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/user-timeline/user-timeline/user-timeline.service.coffee b/app/modules/user-timeline/user-timeline/user-timeline.service.coffee index aecf5724..6737f3c5 100644 --- a/app/modules/user-timeline/user-timeline/user-timeline.service.coffee +++ b/app/modules/user-timeline/user-timeline/user-timeline.service.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/user-timeline/user-timeline/user-timeline.service.spec.coffee b/app/modules/user-timeline/user-timeline/user-timeline.service.spec.coffee index 60912d62..b9836d10 100644 --- a/app/modules/user-timeline/user-timeline/user-timeline.service.spec.coffee +++ b/app/modules/user-timeline/user-timeline/user-timeline.service.spec.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/utils/isolate-click.directive.coffee b/app/modules/utils/isolate-click.directive.coffee index df262794..73d3abea 100644 --- a/app/modules/utils/isolate-click.directive.coffee +++ b/app/modules/utils/isolate-click.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/utils/utils.module.coffee b/app/modules/utils/utils.module.coffee index d39c4e08..1d69b870 100644 --- a/app/modules/utils/utils.module.coffee +++ b/app/modules/utils/utils.module.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/wiki/history/wiki-history-diff.directive.coffee b/app/modules/wiki/history/wiki-history-diff.directive.coffee index 3388d969..fb1b03ec 100644 --- a/app/modules/wiki/history/wiki-history-diff.directive.coffee +++ b/app/modules/wiki/history/wiki-history-diff.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/wiki/history/wiki-history-entry.directive.coffee b/app/modules/wiki/history/wiki-history-entry.directive.coffee index 7f0905ab..1f24956a 100644 --- a/app/modules/wiki/history/wiki-history-entry.directive.coffee +++ b/app/modules/wiki/history/wiki-history-entry.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/wiki/history/wiki-history.directive.coffee b/app/modules/wiki/history/wiki-history.directive.coffee index 34d96c31..fd179590 100644 --- a/app/modules/wiki/history/wiki-history.directive.coffee +++ b/app/modules/wiki/history/wiki-history.directive.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/wiki/history/wiki-history.module.coffee b/app/modules/wiki/history/wiki-history.module.coffee index 4ed5d8d0..6664daa7 100644 --- a/app/modules/wiki/history/wiki-history.module.coffee +++ b/app/modules/wiki/history/wiki-history.module.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/modules/wiki/history/wiki-history.service.coffee b/app/modules/wiki/history/wiki-history.service.coffee index 6b3107ad..3953d71f 100644 --- a/app/modules/wiki/history/wiki-history.service.coffee +++ b/app/modules/wiki/history/wiki-history.service.coffee @@ -1,5 +1,5 @@ ### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/app/partials/admin/admin-project-profile.jade b/app/partials/admin/admin-project-profile.jade index 50a41dc9..bd37c9cb 100644 --- a/app/partials/admin/admin-project-profile.jade +++ b/app/partials/admin/admin-project-profile.jade @@ -119,6 +119,18 @@ div.wrapper( ng-model="project.looking_for_people_note" placeholder="{{ 'ADMIN.PROJECT_PROFILE.RECRUITING_PLACEHOLDER' | translate }}" ) + + fieldset.get-feedback + .get-feedback-inner + span {{ 'ADMIN.PROJECT_PROFILE.FEEDBACK' | translate }} + div.check + input( + type="checkbox", + ng-model="project.is_contact_activated" + ) + div + span.check-text.check-yes(translate="COMMON.YES") + span.check-text.check-no(translate="COMMON.NO") tg-admin-project-restrictions(project="project") diff --git a/app/partials/admin/admin-project-values-custom-fields.jade b/app/partials/admin/admin-project-values-custom-fields.jade index 19cb292b..4ef46a11 100644 --- a/app/partials/admin/admin-project-values-custom-fields.jade +++ b/app/partials/admin/admin-project-values-custom-fields.jade @@ -20,27 +20,27 @@ div.wrapper( div.admin-attributes-section( tg-project-custom-attributes, ng-controller="ProjectCustomAttributesController as ctrl", - ng-init="type='epic'; customFieldSectionTitle='ADMIN.CUSTOM_FIELDS.EPIC_DESCRIPTION'; customFieldButtonTitle='ADMIN.CUSTOM_FIELDS.EPIC_ADD'" + ng-init="init('epic'); customFieldSectionTitle='ADMIN.CUSTOM_FIELDS.EPIC_DESCRIPTION'; customFieldButtonTitle='ADMIN.CUSTOM_FIELDS.EPIC_ADD'" ) include ../includes/modules/admin/admin-custom-attributes div.admin-attributes-section( tg-project-custom-attributes, ng-controller="ProjectCustomAttributesController as ctrl", - ng-init="type='userstory'; customFieldSectionTitle='ADMIN.CUSTOM_FIELDS.US_DESCRIPTION'; customFieldButtonTitle='ADMIN.CUSTOM_FIELDS.US_ADD'" + ng-init="init('userstory'); customFieldSectionTitle='ADMIN.CUSTOM_FIELDS.US_DESCRIPTION'; customFieldButtonTitle='ADMIN.CUSTOM_FIELDS.US_ADD'" ) include ../includes/modules/admin/admin-custom-attributes div.admin-attributes-section( tg-project-custom-attributes, ng-controller="ProjectCustomAttributesController as ctrl", - ng-init="type='task'; customFieldSectionTitle='ADMIN.CUSTOM_FIELDS.TASK_DESCRIPTION'; customFieldButtonTitle='ADMIN.CUSTOM_FIELDS.TASK_ADD'" + ng-init="init('task'); customFieldSectionTitle='ADMIN.CUSTOM_FIELDS.TASK_DESCRIPTION'; customFieldButtonTitle='ADMIN.CUSTOM_FIELDS.TASK_ADD'" ) include ../includes/modules/admin/admin-custom-attributes div.admin-attributes-section( tg-project-custom-attributes, ng-controller="ProjectCustomAttributesController as ctrl", - ng-init="type='issue'; customFieldSectionTitle='ADMIN.CUSTOM_FIELDS.ISSUE_DESCRIPTION'; customFieldButtonTitle='ADMIN.CUSTOM_FIELDS.ISSUE_ADD'" + ng-init="init('issue'); customFieldSectionTitle='ADMIN.CUSTOM_FIELDS.ISSUE_DESCRIPTION'; customFieldButtonTitle='ADMIN.CUSTOM_FIELDS.ISSUE_ADD'" ) include ../includes/modules/admin/admin-custom-attributes diff --git a/app/partials/admin/memberships-row-avatar.jade b/app/partials/admin/memberships-row-avatar.jade index 89411cb6..53c66556 100644 --- a/app/partials/admin/memberships-row-avatar.jade +++ b/app/partials/admin/memberships-row-avatar.jade @@ -1,10 +1,11 @@ -figure.avatar +.avatar img( + src!="<%- imgurl %>" + alt!="<%- full_name %>" style!="background-color: <%- bg %>" - src!="<%- imgurl %>", alt!="<%- full_name %>" ) - figcaption - div.name + .user-data + .name span(ng-non-bindable) <%- full_name %> <% if (isOwner) { %> tg-svg.owner-badge( @@ -12,6 +13,8 @@ figure.avatar svg-title-translate="COMMON.OWNER" ) <% } %> - div - span.pending <%- pending %> + .data span.email <%- email %> + <% if (pending) { %> + span.pending <%- pending %> + <% } %> diff --git a/app/partials/admin/memberships-warning-message.jade b/app/partials/admin/memberships-warning-message.jade index 304e5f09..6f46ef10 100644 --- a/app/partials/admin/memberships-warning-message.jade +++ b/app/partials/admin/memberships-warning-message.jade @@ -1,11 +1,11 @@ p.member-limit-warning( - ng-if="project.i_am_owner == true" + ng-if="project.get('i_am_owner') == true" translate="LIGHTBOX.CREATE_MEMBER.LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER" - translate-values="{maxMembers: project.max_memberships}" + translate-values="{maxMembers: project.get('max_memberships')}" ) p.member-limit-warning( - ng-if="project.i_am_owner == false" + ng-if="project.get('i_am_owner') == false" translate="LIGHTBOX.CREATE_MEMBER.LIMIT_USERS_WARNING_MESSAGE" - translate-values="{maxMembers: project.max_memberships}" + translate-values="{maxMembers: project.get('max_memberships')}" ) diff --git a/app/partials/backlog/backlog.jade b/app/partials/backlog/backlog.jade index be444cc8..941f3ce4 100644 --- a/app/partials/backlog/backlog.jade +++ b/app/partials/backlog/backlog.jade @@ -36,7 +36,7 @@ div.wrapper(tg-backlog, ng-controller="BacklogController as ctrl", div.backlog-menu div.backlog-table-options - a.trans-button.menu-button.move-to-current-sprint.move-to-sprint.e2e-move-to-sprint( + a.menu-button.move-to-current-sprint.move-to-sprint.e2e-move-to-sprint( ng-if="currentSprint" href="" title="{{'BACKLOG.MOVE_US_TO_CURRENT_SPRINT' | translate}}" @@ -44,7 +44,7 @@ div.wrapper(tg-backlog, ng-controller="BacklogController as ctrl", ) tg-svg(svg-icon="icon-move") span.text(translate="BACKLOG.MOVE_US_TO_CURRENT_SPRINT") - a.trans-button.menu-button.move-to-latest-sprint.move-to-sprint.e2e-move-to-sprint( + a.menu-button.move-to-latest-sprint.move-to-sprint.e2e-move-to-sprint( ng-if="!currentSprint" href="" title="{{'BACKLOG.MOVE_US_TO_LATEST_SPRINT' | translate}}" @@ -52,33 +52,61 @@ div.wrapper(tg-backlog, ng-controller="BacklogController as ctrl", ) tg-svg(svg-icon="icon-move") span.text(translate="BACKLOG.MOVE_US_TO_LATEST_SPRINT") - a.trans-button.menu-button.e2e-open-filter.ng-animate-disabled( + a.menu-button.e2e-open-filter.ng-animate-disabled( ng-if="!ctrl.activeFilters" href="" title="{{'BACKLOG.FILTERS.TOGGLE' | translate}}" id="show-filters-button" translate="BACKLOG.FILTERS.SHOW" ) - a.trans-button.menu-button.active.e2e-open-filter.ng-animate-disabled( + a.menu-button.active.e2e-open-filter.ng-animate-disabled( ng-if="ctrl.activeFilters" href="" title="{{'BACKLOG.FILTERS.HIDE' | translate}}" id="show-filters-button" translate="BACKLOG.FILTERS.HIDE" ) - a.trans-button.menu-button( + a.menu-button( ng-if="userstories.length" href="" title="{{'BACKLOG.TAGS.TOGGLE' | translate}}" id="show-tags" translate="BACKLOG.TAGS.SHOW" ) + a.menu-button.velocity-forecasting-btn.ng-animate-disabled.e2e-velocity-forecasting( + ng-if="userstories.length && ctrl.displayVelocity " + href="" + title="{{'BACKLOG.FORECASTING.TITLE' | translate}}" + translate="BACKLOG.FORECASTING.BACKLOG" + ng-click="ctrl.toggleVelocityForecasting()" + tg-check-permission="add_milestone" + ) + a.menu-button.velocity-forecasting-btn.ng-animate-disabled.e2e-velocity-forecasting( + ng-if="userstories.length && !ctrl.displayVelocity && stats.speed > 0" + href="" + title="{{'BACKLOG.FORECASTING.BACKLOG' | translate}}" + translate="BACKLOG.FORECASTING.TITLE" + ng-click="ctrl.toggleVelocityForecasting()" + tg-check-permission="add_milestone" + ) include ../includes/components/addnewus + section.backlog-table(ng-class="{'hidden': !userstories.length}") include ../includes/modules/backlog-table - - div.empty-large.js-empty-backlog(ng-class="{'hidden': userstories === undefined || userstories.length}") + + .forecasting-add-sprint.e2e-velocity-forecasting-add(ng-if="ctrl.displayVelocity") + tg-svg(svg-icon="icon-add") + span( + ng-if="!currentSprint" + translate="BACKLOG.FORECASTING.NEW_SPRINT" + ) + span( + ng-if="currentSprint" + translate="BACKLOG.FORECASTING.CURRENT_SPRINT" + ) + + .empty-large.js-empty-backlog(ng-class="{'hidden': userstories === undefined || userstories.length}") img( src="/#{v}/images/empty/empty_mex.png" alt="{{'BACKLOG.EMPTY' | translate}}" diff --git a/app/partials/common/components/editable-description.jade b/app/partials/common/components/editable-description.jade deleted file mode 100644 index f5b9f095..00000000 --- a/app/partials/common/components/editable-description.jade +++ /dev/null @@ -1,15 +0,0 @@ -include wysiwyg.jade - -.view-description - section.us-content.wysiwyg(tg-bind-html="item.description_html || noDescriptionMsg") - tg-svg.edit(svg-icon="icon-edit") - -.edit-description - textarea(ng-attr-placeholder="{{'COMMON.DESCRIPTION.EMPTY' | translate}}", ng-model="item.description", tg-markitup="tg-markitup") - +wysihelp - div.save-container - span.save - tg-svg( - svg-icon="icon-save", - svg-title-translate="COMMON.SAVE" - ) diff --git a/app/partials/common/components/wysiwyg-toolbar.jade b/app/partials/common/components/wysiwyg-toolbar.jade new file mode 100644 index 00000000..502839d5 --- /dev/null +++ b/app/partials/common/components/wysiwyg-toolbar.jade @@ -0,0 +1,67 @@ +.editor(ng-class="{'edit-mode': editMode, 'read-mode': !editMode}") + div(ng-if="outdated") + p.outdated {{'COMMON.WYSIWYG.OUTDATED' | translate}} + + .medium.wysiwyg( + type="text", + ng-show="mode == 'html'" + ) + + textarea.markdown.e2e-markdown-textarea( + ng-attr-placeholder="{{placeholder}}" + ng-change="changeMarkdown(markdown)" + ng-model="markdown" + ng-show="mode == 'markdown' && editMode" + ) + + .markdown( + ng-class="{empty: !markdown.length}" + ng-click="editMode = true" + ng-show="mode == 'markdown' && !editMode" + ) + p(ng-if="markdown.length") {{markdown}} + p.markdown-editor-placeholder.wysiwyg(ng-if="!markdown.length") {{placeholder}} + + .mode-editor(ng-if="editMode") + span.e2e-markdown-mode( + ng-if="mode=='html'" + ng-click="setMode('markdown')" + ) Markdown Mode + + span.e2e-html-mode( + ng-if="mode=='markdown'" + ng-click="setMode('html')" + ) HTML Mode + + a.help-markdown( + ng-if="mode=='markdown'" + href="https://tree.taiga.io/support/misc/taiga-markdown-syntax/" + target="_blank" + title="{{'COMMON.WYSIWYG.MARKDOWN_HELP' | translate}}" + ) + tg-svg(svg-icon="icon-question") + span(translate="COMMON.WYSIWYG.MARKDOWN_HELP") + +.tools(ng-if="editMode") + a.e2e-save-editor( + ng-class="{disabled: required && !markdown.length}" + tg-loading="saving" + href="#", + ng-click="save($event)" + ) + tg-svg(svg-icon="icon-save") + a.e2e-cancel-editor( + href="#", + ng-click="cancel($event)" + title="{{ 'COMMON.CANCEL' | translate }}" + ) + tg-svg(svg-icon="icon-close") + +tg-wysiwyg-code-lightbox.lightbox.lightbox-generic-form( + languages="codeLans" + code-language="currentCodeLanguage" + code="code" + visible="codeEditorVisible" + on-close="codeEditorVisible = false" + on-save="saveSnippet(lan, code)" +) \ No newline at end of file diff --git a/app/partials/common/components/wysiwyg.jade b/app/partials/common/components/wysiwyg.jade deleted file mode 100644 index f68d4467..00000000 --- a/app/partials/common/components/wysiwyg.jade +++ /dev/null @@ -1,11 +0,0 @@ -mixin wysihelp - .wysiwyg-help - span.drag-drop-help(ng-if="wiki.id", translate="COMMON.WYSIWYG.ATTACH_FILE_HELP") - span.drag-drop-help(ng-if="!wiki.id", translate="COMMON.WYSIWYG.ATTACH_FILE_HELP_SAVE_FIRST") - a.help-markdown( - href="https://tree.taiga.io/support/misc/taiga-markdown-syntax/" - target="_blank" - title="{{'COMMON.WYSIWYG.MARKDOWN_HELP' | translate}}" - ) - tg-svg(svg-icon="icon-question") - span(translate="COMMON.WYSIWYG.MARKDOWN_HELP") diff --git a/app/partials/custom-attributes/custom-attribute-value-edit.jade b/app/partials/custom-attributes/custom-attribute-value-edit.jade index e00fc04f..3e2a1a60 100644 --- a/app/partials/custom-attributes/custom-attribute-value-edit.jade +++ b/app/partials/custom-attributes/custom-attribute-value-edit.jade @@ -13,6 +13,8 @@ form.custom-field-single.editable input#custom-field-value(name="value", type="text", value!="<%- value %>") <% } else if (type=="multiline") { %> textarea#custom-field-value(name="value") <%- value %> + <% } else if (type=="richtext") { %> + tg-custom-field-edit-wysiwyg() <% } else if (type=="date") { %> input#custom-field-value(name="value", type="text", data-pikaday, value!="<%- value %>") <% } else if (type=="url") { %> @@ -21,6 +23,8 @@ form.custom-field-single.editable input#custom-field-value(name="value", type="text", value!="<%- value %>") <% } %> + <% if (type != "richtext") { %> div.custom-field-options a.js-save-description(href="", title="{{'COMMON.CUSTOM_ATTRIBUTES.SAVE' | translate}}") tg-svg(svg-icon="icon-save") + <% } %> diff --git a/app/partials/custom-attributes/custom-attribute-value.jade b/app/partials/custom-attributes/custom-attribute-value.jade index 0350a24d..0bd427e5 100644 --- a/app/partials/custom-attributes/custom-attribute-value.jade +++ b/app/partials/custom-attributes/custom-attribute-value.jade @@ -7,14 +7,19 @@ <%- description %> <% } %> + <% if (type=="url") { %> .custom-field-value.js-value-view-mode span - <% if (type=="url") { %> a(href!="<%- value %>") <%- value %> - <% } else { %> + <% } else if (type=="richtext") { %> + .custom-field-value.js-value-view-mode.wysiwyg + div(ng-bind-html!="\'<%- value %>\'|markdownToHTML") + <% } else { %> + .custom-field-value.js-value-view-mode + span <%- value %> - <% } %> + <% } %> <% if (isEditable) { %> .custom-field-options diff --git a/app/partials/custom-attributes/custom-attributes-values.jade b/app/partials/custom-attributes/custom-attributes-values.jade index 2a5ec5eb..ba45e4f3 100644 --- a/app/partials/custom-attributes/custom-attributes-values.jade +++ b/app/partials/custom-attributes/custom-attributes-values.jade @@ -7,8 +7,10 @@ section.duty-custom-fields(ng-show="ctrl.customAttributes.length") ng-click="toggleCollapse()" ) tg-svg(svg-icon="icon-arrow-down") + .custom-fields-body( ng-show="!collapsed" + ng-class="{'collapse-fields': ctrl.customAttributes.length > 6}" ) .custom-attribute( ng-repeat="attr in ctrl.customAttributes" diff --git a/app/partials/epic/epic-detail.jade b/app/partials/epic/epic-detail.jade index 52bb688c..6f422b05 100644 --- a/app/partials/epic/epic-detail.jade +++ b/app/partials/epic/epic-detail.jade @@ -41,12 +41,12 @@ div.wrapper( ) tg-created-by-display.ticket-created-by(ng-model="epic") - section.duty-content( - tg-editable-description - tg-editable-wysiwyg - ng-model="epic" - required-perm="modify_epic" - ) + section.duty-content + tg-item-wysiwyg( + type="epic", + model="epic", + required-perm="modify_epic" + ) // Custom Fields tg-custom-attributes-values( diff --git a/app/partials/includes/components/backlog-row.jade b/app/partials/includes/components/backlog-row.jade index 0c772ee1..e3fafd2d 100644 --- a/app/partials/includes/components/backlog-row.jade +++ b/app/partials/includes/components/backlog-row.jade @@ -1,9 +1,10 @@ .row.us-item-row( - ng-repeat="us in userstories track by us.id" + ng-repeat="us in userstories | inArray:visibleUserStories:'ref'" tg-bind-scope ng-class="{blocked: us.is_blocked}" tg-class-permission="{'readonly': '!modify_us'}" ) + .input(tg-check-permission="modify_us") input( type="checkbox" diff --git a/app/partials/includes/modules/admin/admin-custom-attributes.jade b/app/partials/includes/modules/admin/admin-custom-attributes.jade index 847a4133..b2e97952 100644 --- a/app/partials/includes/modules/admin/admin-custom-attributes.jade +++ b/app/partials/includes/modules/admin/admin-custom-attributes.jade @@ -30,6 +30,10 @@ section.custom-fields-table.basic-table ng-switch-default translate="ADMIN.CUSTOM_FIELDS.FIELD_TYPE_TEXT" ) + span( + ng-switch-when="richtext" + translate="ADMIN.CUSTOM_FIELDS.FIELD_TYPE_RICHTEXT" + ) span( ng-switch-when="multiline" translate="ADMIN.CUSTOM_FIELDS.FIELD_TYPE_MULTI" diff --git a/app/partials/includes/modules/admin/admin-membership-table.jade b/app/partials/includes/modules/admin/admin-membership-table.jade index 8ddb19f5..c88d8abc 100644 --- a/app/partials/includes/modules/admin/admin-membership-table.jade +++ b/app/partials/includes/modules/admin/admin-membership-table.jade @@ -1,11 +1,11 @@ section.admin-membership-table.basic-table - div.row.title + .row.title div.header-member(translate="ADMIN.MEMBERSHIP.COLUMN_MEMBER") div.header-admin(translate="ADMIN.MEMBERSHIP.COLUMN_ADMIN") div.header-role(translate="ADMIN.MEMBERSHIP.COLUMN_ROLE") div.header-status(translate="ADMIN.MEMBERSHIP.COLUMN_STATUS") - div.row(ng-repeat="member in memberships") + .row(ng-repeat="member in memberships") div.row-member(tg-memberships-row-avatar="member") div.row-admin(tg-memberships-row-admin-checkbox="member") div.row-role(tg-memberships-row-role-selector="member") diff --git a/app/partials/includes/modules/admin/project-us-status.jade b/app/partials/includes/modules/admin/project-us-status.jade index 684e817d..62445f7a 100644 --- a/app/partials/includes/modules/admin/project-us-status.jade +++ b/app/partials/includes/modules/admin/project-us-status.jade @@ -11,7 +11,7 @@ section.project-us-status div.color-column(translate="COMMON.FIELDS.COLOR") div.status-name(translate="COMMON.FIELDS.NAME") div.status-slug(translate="COMMON.FIELDS.SLUG") - div.is-closed-column(translate="COMMON.FIELDS.IS_CLOSED") + div.is-closed-column(translate="ADMIN.US_STATUS.IS_CLOSED_COLUMN") div.is-archived-column(translate="ADMIN.US_STATUS.IS_ARCHIVED_COLUMN") div.status-wip-limit(translate="ADMIN.US_STATUS.WIP_LIMIT_COLUMN") div.options-column diff --git a/app/partials/includes/modules/backlog-table.jade b/app/partials/includes/modules/backlog-table.jade index 8ee5707b..c37e329f 100644 --- a/app/partials/includes/modules/backlog-table.jade +++ b/app/partials/includes/modules/backlog-table.jade @@ -10,7 +10,7 @@ div.backlog-table-header div.backlog-table-body( tg-backlog-sortable, - ng-class="{'show-tags': ctrl.showTags, 'active-filters': ctrl.activeFilters}" + ng-class="{'show-tags': ctrl.showTags, 'active-filters': ctrl.activeFilters, 'forecasted-stories': ctrl.displayVelocity}" infinite-scroll="ctrl.loadUserstories()" infinite-scroll-disabled="ctrl.disablePagination || !ctrl.firstLoadComplete" infinite-scroll-immediate-check='false' diff --git a/app/partials/includes/modules/invitation-login-form.jade b/app/partials/includes/modules/invitation-login-form.jade index 816854c2..f9effc25 100644 --- a/app/partials/includes/modules/invitation-login-form.jade +++ b/app/partials/includes/modules/invitation-login-form.jade @@ -30,10 +30,15 @@ form.login-form ) fieldset - a.button-login.button-blackish.submit-button( + button.button-green.submit-button( type="submit" - title="{{'LOGIN_COMMON.ACTION_ENTER' | translate}}" translate="LOGIN_COMMON.ACTION_ENTER" ) + + .contrib-plugins-wrapper(ng-if="contribPlugins.length") + label(translate="LOGIN_COMMON.ALT_LOGIN") - fieldset(ng-repeat="plugin in contribPlugins|filter:{type: 'auth'}", ng-include="plugin.template") + fieldset( + ng-repeat="plugin in contribPlugins|filter:{type: 'auth'}" + ng-include="plugin.template" + ) diff --git a/app/partials/includes/modules/invitation-register-form.jade b/app/partials/includes/modules/invitation-register-form.jade index 227f9c28..00b7611e 100644 --- a/app/partials/includes/modules/invitation-register-form.jade +++ b/app/partials/includes/modules/invitation-register-form.jade @@ -44,11 +44,11 @@ form.register-form ) fieldset - a.button-register.button-blackish.submit-button( + button.button-register.button-green.submit-button( type="submit" title="{{'REGISTER_FORM.ACTION_SIGN_UP' | translate}}" translate="REGISTER_FORM.ACTION_SIGN_UP" ) - + //- Only displays terms notice when terms plugin is loaded. tg-terms-of-service-and-privacy-policy-notice diff --git a/app/partials/includes/modules/lightbox-create-issue.jade b/app/partials/includes/modules/lightbox-create-issue.jade index ec245f0a..8cf35fa7 100644 --- a/app/partials/includes/modules/lightbox-create-issue.jade +++ b/app/partials/includes/modules/lightbox-create-issue.jade @@ -43,6 +43,7 @@ form tg-attachments-simple( attachments="attachments", on-add="addAttachment(attachment)" + on-delete="deleteAttachment(attachment)" ) fieldset diff --git a/app/partials/includes/modules/lightbox-sprint-add-edit.jade b/app/partials/includes/modules/lightbox-sprint-add-edit.jade index 254e3276..d2a2400a 100644 --- a/app/partials/includes/modules/lightbox-sprint-add-edit.jade +++ b/app/partials/includes/modules/lightbox-sprint-add-edit.jade @@ -3,7 +3,7 @@ tg-lightbox-close form h2.title(translate="LIGHTBOX.ADD_EDIT_SPRINT.TITLE") fieldset - input.sprint-name( + input.sprint-name.e2e-sprint-name( type="text" name="name" ng-model="newSprint.name" diff --git a/app/partials/includes/modules/login-form.jade b/app/partials/includes/modules/login-form.jade index 96927f3b..a1582f24 100644 --- a/app/partials/includes/modules/login-form.jade +++ b/app/partials/includes/modules/login-form.jade @@ -38,9 +38,12 @@ translate="LOGIN_COMMON.ACTION_SIGN_IN" ) - fieldset( - ng-repeat="plugin in contribPlugins|filter:{type: 'auth'}" - ng-include="plugin.template" - ) + .contrib-plugins-wrapper(ng-if="contribPlugins.length") + label(translate="LOGIN_COMMON.ALT_LOGIN") + + fieldset( + ng-repeat="plugin in contribPlugins|filter:{type: 'auth'}" + ng-include="plugin.template" + ) tg-public-register-message diff --git a/app/partials/includes/modules/register-form.jade b/app/partials/includes/modules/register-form.jade index e5aa9b6b..2c58fdff 100644 --- a/app/partials/includes/modules/register-form.jade +++ b/app/partials/includes/modules/register-form.jade @@ -51,11 +51,14 @@ div.register-form-container(tg-register) title="{{'REGISTER_FORM.ACTION_SIGN_UP' | translate}}" translate="REGISTER_FORM.ACTION_SIGN_UP" ) + + .contrib-plugins-wrapper(ng-if="contribPlugins.length") + label(translate="LOGIN_COMMON.ALT_LOGIN") - fieldset( - ng-repeat="plugin in contribPlugins|filter:{type: 'auth'}" - ng-include="plugin.template" - ) + fieldset( + ng-repeat="plugin in contribPlugins|filter:{type: 'auth'}" + ng-include="plugin.template" + ) //- Only displays terms notice when terms plugin is loaded. tg-terms-of-service-and-privacy-policy-notice diff --git a/app/partials/issue/issues-detail.jade b/app/partials/issue/issues-detail.jade index e85c9a3d..2b554160 100644 --- a/app/partials/issue/issues-detail.jade +++ b/app/partials/issue/issues-detail.jade @@ -34,12 +34,12 @@ div.wrapper( ) tg-created-by-display.ticket-created-by(ng-model="issue") - section.duty-content( - tg-editable-description - tg-editable-wysiwyg - ng-model="issue" - required-perm="modify_issue" - ) + section.duty-content + tg-item-wysiwyg( + type="issue", + model="issue", + required-perm="modify_issue" + ) // Custom Fields tg-custom-attributes-values( diff --git a/app/partials/kanban/kanban.jade b/app/partials/kanban/kanban.jade index 2e65ebe2..3a63c543 100644 --- a/app/partials/kanban/kanban.jade +++ b/app/partials/kanban/kanban.jade @@ -1,12 +1,15 @@ doctype html -div.wrapper(tg-kanban, ng-controller="KanbanController as ctrl" - ng-init="section='kanban'") +div.wrapper( + tg-kanban, + ng-controller="KanbanController as ctrl" + ng-init="section='kanban'" +) tg-project-menu section.main.kanban tg-filter( - ng-show="ctrl.openFilter" + open="{{ctrl.openFilter}}" q="ctrl.filterQ" filters="ctrl.filters" custom-filters="ctrl.customFilters" @@ -23,8 +26,8 @@ div.wrapper(tg-kanban, ng-controller="KanbanController as ctrl" .kanban-header include ../includes/components/mainTitle .taskboard-actions + .zoom-loading(tg-loading="ctrl.zoomLoading") tg-kanban-board-zoom( - ng-if="usByStatus.size", on-zoom-change="ctrl.setZoom(zoomLevel, zoom)" ) diff --git a/app/partials/project/wizard-create-project.jade b/app/partials/project/wizard-create-project.jade deleted file mode 100644 index 9015795a..00000000 --- a/app/partials/project/wizard-create-project.jade +++ /dev/null @@ -1,84 +0,0 @@ -tg-lightbox-close -form - header - h1.title(translate="WIZARD.SECTION_TITLE_CREATE_PROJECT") - .subtitle( - translate="WIZARD.CREATE_PROJECT_TEXT" - role="presentation" - ) - section.template-option - .template-selector-title - legend(translate="WIZARD.CHOOSE_TEMPLATE") - .template-selector - fieldset(ng-repeat="template in templates") - input( - type="radio" - name="template" - id="template-{{ template.id }}" - ng-value='template.id' - ng-model="data.creation_template" - data-required="true" - ) - label.template-label(for="template-{{ template.id }}") - tg-svg(svg-icon="{{'icon-'+template.slug}}") - span.template-name {{ template.name }} - .template-data - legend(translate="WIZARD.PROJECT_DETAILS") - fieldset - input( - type="text" - name="name" - ng-model="data.name" - data-required="true" - placeholder="{{'COMMON.FIELDS.NAME' | translate}}" - maxlength="45" - aria-hidden="true" - ) - fieldset - textarea( - name="description" - ng-model="data.description" - data-required="true" - ng-attr-placeholder="{{'COMMON.FIELDS.DESCRIPTION' | translate}}" - ) - .template-privacity - fieldset - input( - type="radio" - name="is_private" - id="template-public" - data-required="true" - aria-hidden="true" - ng-value="false" - ng-model="data.is_private" - required - ng-disabled="!canCreatePublicProjects.valid" - ng-checked="canCreatePublicProjects.valid" - ) - label.template-privacity(for="template-public") - tg-svg(svg-icon="icon-discover") - span(translate="WIZARD.PUBLIC_PROJECT") - fieldset - input( - type="radio" - name="is_private" - id="template-private" - data-required="true" - ng-value="true" - ng-model="data.is_private" - aria-hidden="true" - required - ng-disabled="!canCreatePrivateProjects.valid" - ng-checked="!canCreatePublicProjects.valid" - ) - label.template-privacity(for="template-private") - tg-svg(svg-icon="icon-lock") - span(translate="WIZARD.PRIVATE_PROJECT") - - tg-create-project-restriction - - button.button-green.submit-button( - translate="WIZARD.CREATE_PROJECT" - title="{{'WIZARD.CREATE_PROJECT' | translate}}" - ng-click="" - ) diff --git a/app/partials/project/wizard-restrictions.jade b/app/partials/project/wizard-restrictions.jade deleted file mode 100644 index fb80f608..00000000 --- a/app/partials/project/wizard-restrictions.jade +++ /dev/null @@ -1,7 +0,0 @@ -div.create-warning(ng-if="!canCreatePrivateProjects.valid && canCreatePrivateProjects.reason == 'max_private_projects'") - tg-svg(svg-icon="icon-exclamation") - span {{ 'WIZARD.MAX_PRIVATE_PROJECTS' | translate }} - -div.create-warning(ng-if="!canCreatePublicProjects.valid && canCreatePublicProjects.reason == 'max_public_projects'") - tg-svg(svg-icon="icon-exclamation") - span {{ 'WIZARD.MAX_PUBLIC_PROJECTS' | translate }} diff --git a/app/partials/task/task-detail.jade b/app/partials/task/task-detail.jade index 2a331a5b..3928cc08 100644 --- a/app/partials/task/task-detail.jade +++ b/app/partials/task/task-detail.jade @@ -43,7 +43,12 @@ div.wrapper( ) tg-created-by-display.ticket-created-by(ng-model="task") - section.duty-content(tg-editable-description, tg-editable-wysiwyg, ng-model="task", required-perm="modify_task") + section.duty-content + tg-item-wysiwyg( + type="task", + model="task", + required-perm="modify_task" + ) // Custom Fields tg-custom-attributes-values( diff --git a/app/partials/taskboard/taskboard.jade b/app/partials/taskboard/taskboard.jade index d9e85720..d9475033 100644 --- a/app/partials/taskboard/taskboard.jade +++ b/app/partials/taskboard/taskboard.jade @@ -1,11 +1,14 @@ doctype html -div.wrapper(tg-taskboard, ng-controller="TaskboardController as ctrl", - ng-init="section='backlog'") +div.wrapper( + tg-taskboard, + ng-controller="TaskboardController as ctrl", + ng-init="section='backlog'" +) tg-project-menu section.main.taskboard tg-filter( - ng-show="ctrl.openFilter" + open="{{ctrl.openFilter}}" q="ctrl.filterQ" filters="ctrl.filters" custom-filters="ctrl.customFilters" @@ -24,8 +27,8 @@ div.wrapper(tg-taskboard, ng-controller="TaskboardController as ctrl", span.green(tg-bo-bind="sprint.name") span.date(tg-date-range="sprint.estimated_start,sprint.estimated_finish") .taskboard-actions + .zoom-loading(tg-loading="ctrl.zoomLoading") tg-taskboard-zoom( - ng-if="usTasks.size", on-zoom-change="ctrl.setZoom(zoomLevel, zoom)" ) button.button-filter.e2e-open-filter( diff --git a/app/partials/us/us-detail.jade b/app/partials/us/us-detail.jade index 6c04fb9f..be89305b 100644 --- a/app/partials/us/us-detail.jade +++ b/app/partials/us/us-detail.jade @@ -43,7 +43,12 @@ div.wrapper( ) tg-created-by-display.ticket-created-by(ng-model="us") - section.duty-content(tg-editable-description, tg-editable-wysiwyg, ng-model="us", required-perm="modify_us") + section.duty-content + tg-item-wysiwyg( + type="us", + model="us", + required-perm="modify_us" + ) // Custom Fields tg-custom-attributes-values( diff --git a/app/partials/wiki/editable-wiki-content.jade b/app/partials/wiki/editable-wiki-content.jade deleted file mode 100644 index 4f27d874..00000000 --- a/app/partials/wiki/editable-wiki-content.jade +++ /dev/null @@ -1,29 +0,0 @@ -include ../common/components/wysiwyg.jade - -.view-wiki-content - section.wysiwyg(tg-bind-html='wiki.html') - a.edit( - href="" - title="{{'COMMON.EDIT' | translate}}" - ) - tg-svg(svg-icon="icon-edit") - -.edit-wiki-content(style='display: none;') - textarea( - ng-attr-placeholder="{{'WIKI.PLACEHOLDER_PAGE' | translate}}", - ng-model='wiki.content' - tg-markitup='tg-markitup' - ) - +wysihelp - - span.action-container - a.save( - title="{{'COMMON.SAVE' | translate}}" - href="" - ) - tg-svg(svg-icon="icon-save") - a.cancel( - title="{{'COMMON.CANCEL' | translate}}" - href="" - ) - tg-svg(svg-icon="icon-close") diff --git a/app/partials/wiki/wiki.jade b/app/partials/wiki/wiki.jade index cde221a6..50a37af7 100644 --- a/app/partials/wiki/wiki.jade +++ b/app/partials/wiki/wiki.jade @@ -17,11 +17,8 @@ div.wrapper( span.green(translate="PROJECT.SECTION.WIKI") h2.wiki-title(ng-bind='wikiTitle') - section.wiki-content( - tg-editable-wysiwyg, - tg-editable-wiki-content, - ng-model="wiki" - ) + + tg-wiki-wysiwyg(model="wiki") .summary.wiki-summary( tg-wiki-summary diff --git a/app/styles/components/buttons.scss b/app/styles/components/buttons.scss index 96dbb3b5..388bd258 100755 --- a/app/styles/components/buttons.scss +++ b/app/styles/components/buttons.scss @@ -8,7 +8,7 @@ color: $white; cursor: pointer; display: inline-block; - padding: .4rem 2rem; + padding: .6rem 2rem; text-align: center; text-transform: uppercase; transition: all .2s linear; @@ -59,6 +59,23 @@ color: $blackish; } } + +.menu-button { + @extend %button; + border-radius: 0; + color: $blackish; + &:hover { + background: $whitish; + color: $gray; + } + &:visited { + color: $blackish; + } + span { + color: $blackish; + } +} + .submit-button { width: 100%; } diff --git a/app/styles/components/empty.scss b/app/styles/components/empty.scss index 23fe77c7..381db7b7 100644 --- a/app/styles/components/empty.scss +++ b/app/styles/components/empty.scss @@ -32,3 +32,8 @@ max-width: 800px; } } + +.empty-filter { + @extend %empty; + margin-top: 1rem; +} diff --git a/app/styles/components/list-items.scss b/app/styles/components/list-items.scss index fb72b3a8..10483b4f 100644 --- a/app/styles/components/list-items.scss +++ b/app/styles/components/list-items.scss @@ -101,6 +101,10 @@ .ticket-project { margin-right: .3rem; } + .ticket-type { + margin-left: .3rem; + text-transform: uppercase; + } .ticket-project { color: $gray-light; } diff --git a/app/styles/components/markitup.scss b/app/styles/components/markitup.scss deleted file mode 100644 index 59dc99a2..00000000 --- a/app/styles/components/markitup.scss +++ /dev/null @@ -1,42 +0,0 @@ -.markItUpHeader { - ul { - background: $mass-white; - padding: .3rem; - li { - display: inline-block; - float: none; - a { - opacity: .8; - &:hover { - opacity: .3; - transition: opacity .2s linear; - } - } - } - .preview-icon { - position: absolute; - right: 4rem; - } - } -} - -.markItUpContainer { - padding: 0; -} - -.markdown { - position: relative; -} - -.preview { - .actions { - background: $mass-white; - margin-top: .5rem; - min-height: 2rem; - padding: .3rem; - } - .content { - background: $white; - margin-bottom: 0; - } -} diff --git a/app/styles/components/track-btn.scss b/app/styles/components/track-btn.scss index 221d893a..8fdab2bd 100644 --- a/app/styles/components/track-btn.scss +++ b/app/styles/components/track-btn.scss @@ -1,6 +1,3 @@ -////////////////////// -//Watch like buttons -////////////////////// .track-buttons-container { @include font-size(small); @@ -9,75 +6,80 @@ .track-button { align-items: stretch; - display: inline-flex; - position: relative; - .track-inner { - align-items: center; - background: $mass-white; - border-radius: 4px 0 0 4px; - display: flex; - flex: 1; - flex-basis: 140px; - justify-content: flex-start; - margin-right: .1rem; - min-width: 140px; - &:hover { - background: darken($mass-white, 5%); - transition: background .3s; + display: flex; + margin: 0; + padding: 0; + &.active { + .track-inner { + background: rgba($primary-light, .4); + } + .icon { + fill: $primary; + } + .track-button-counter { + background: rgba($primary-light, .6); + } + } + &.is-hover { + .track-inner { + background: lighten($red, 10%); + color: $whitish; + transition: background .2s; + } + .icon { + fill: $red-light; + } + .track-button-counter { + background: $red; + color: $whitish; + transition: background .2s; } } .watch-options-arrow { - margin: 0 .5rem 0 auto; - svg { - @include svg-size(.75rem); - } + margin-left: auto; } - &:hover { - color: $blackish; - } - &.active { - .track-inner { - background: rgba($primary-light, .2); - } - .track-icon { - svg { - fill: $primary; - } - } - } - &.watch-container { - margin-right: 1rem; - position: relative; - } - .track-icon { - padding: .3rem .6rem .3rem .75rem; - svg { - fill: $grayer; - position: relative; - top: 2px; - } - } - .track-button-counter { - align-items: center; - border: 1px solid $whitish; - display: flex; - justify-content: center; - min-width: 2rem; + .icon-arrow-down { + @include svg-size(.75rem); } } -.watch-button, -.like-button { - &.active { - &.is-hover { - .track-inner { - background: $red; - color: $whitish; - transition: background .3s; - } - svg { - fill: $red-light; - } - } + +.track-inner { + align-items: center; + background: $whitish; + border-radius: 4px 0 0 4px; + display: flex; + flex: 1; + flex-basis: 140px; + justify-content: flex-start; + min-width: 140px; + padding: .25rem 1rem; + &:hover { + background: darken($whitish, 5%); + transition: background .3s; + } +} + +.track-icon { + fill: $grayer; + margin-right: .5rem; + position: relative; + top: 2px; +} + +.track-button-counter { + align-items: center; + background: darken($whitish, 5%); + border-radius: 0 4px 4px 0; + padding: .25rem .75rem; +} + +.contact-team { + background: $whitish; + border-radius: 4px; + padding: .25rem .75rem; + &:hover { + background: darken($whitish, 5%); + transition: background .3s; } } diff --git a/app/styles/core/base.scss b/app/styles/core/base.scss index 7b4af1d2..e8761df4 100644 --- a/app/styles/core/base.scss +++ b/app/styles/core/base.scss @@ -47,6 +47,7 @@ body { .wrapper { display: flex; + height: 100%; min-height: $main-height; } diff --git a/app/styles/dependencies/mixins/btn-group.scss b/app/styles/dependencies/mixins/btn-group.scss new file mode 100644 index 00000000..af18c9e2 --- /dev/null +++ b/app/styles/dependencies/mixins/btn-group.scss @@ -0,0 +1,45 @@ +@mixin btn-group { + display: flex; + fieldset { + &:first-child { + label { + border-radius: .25rem 0 0 .25rem; + } + } + &:last-child { + label { + border-radius: 0 .25rem .25rem 0; + } + } + } + label { + align-items: center; + background: $mass-white; + cursor: pointer; + display: flex; + justify-content: center; + text-align: center; + padding: .75rem; + text-transform: uppercase; + &:hover { + background: darken($mass-white, 5%); + transition: background .2s linear; + } + .icon { + margin-right: .25rem; + } + } + input { + &:checked+label { + background: darken($mass-white, 10%); + @include font-type(bold); + } + &:disabled+label { + cursor: not-allowed; + color: lighten($gray-light, 15%); + .icon { + color: lighten($gray-light, 15%); + } + } + } +} diff --git a/app/styles/dependencies/mixins/create.scss b/app/styles/dependencies/mixins/create.scss new file mode 100644 index 00000000..f396854c --- /dev/null +++ b/app/styles/dependencies/mixins/create.scss @@ -0,0 +1,243 @@ +@mixin create-project { + @include centered; + max-width: 800px; + + fieldset { + margin-bottom: 1rem; + } + + label { + @include font-size(small); + display: block; + margin-bottom: .25rem; + + .mumble { + @include font-type(light); + margin-left: .25rem; + } + } + + &-check { + @include font-type(bold); + position: relative; + + span { + display: block; + } + + .description { + @include font-type(normal); + } + + .check { + position: absolute; + right: 0; + top: 0; + } + } + + &-title-wrapper { + align-items: center; + display: flex; + justify-content: center; + margin-bottom: 0; + + .create-project-title { + display: inline-block; + } + .icon { + @include svg-size(1.75rem); + margin-right: .5rem; + vertical-align: middle; + } + } + + &-title, + &-description { + margin: 0; + text-align: center; + } + + &-description { + color: $gray-light; + margin-bottom: 2rem; + } + + &-limit { + @include font-type(light); + @include font-size(small); + color: $gray; + } + + &-import-type { + @include btn-group; + + input { + display: none; + } + + label { + background: $mass-white; + } + } + + &-privacity { + @include btn-group; + + input { + display: none; + } + + label { + background: $mass-white; + } + } + + &-type { + @include font-type(bold); + align-items: center; + display: flex; + justify-content: center; + margin-bottom: 2rem; + text-transform: uppercase; + + span { + margin-left: .5rem; + } + } + + &-selector { + a { + align-items: center; + border-bottom: 1px solid $whitish; + color: $grayer; + cursor: pointer; + display: flex; + justify-content: center; + position: relative; + &:hover { + color: currentColor; + } + } + li { + &:hover { + background: rgba($primary, .1); + transition: background .3s ease-in; + } + + &:first-child { + border-top: 1px solid $whitish; + } + } + + &-icon { + align-self: flex-start; + padding: 1.5rem 1rem; + + .icon { + @include svg-size(2.25rem); + } + } + + &-template-wrapper { + flex: 1; + padding: 1.25rem; + } + + &-template { + @include font-type(bold); + text-transform: uppercase; + } + + &-description { + @include font-type(light); + } + + &-long-description { + margin-top: 1rem; + max-height: 120px; + overflow: hidden; + transition: all .3s .2s cubic-bezier(0, 0, .53, 1.32); + + &.ng-hide { + line-height: 0; + max-height: 0; + } + } + + &-question { + position: absolute; + right: 1.5rem; + top: 1.5rem; + + &:hover { + svg { + fill: $primary; + transition: fill .2s linear; + } + } + + svg { + @include svg-size(1.2rem); + fill: $grayer; + } + } + + p { + margin-bottom: 0; + } + } + + &-action { + display: flex; + margin: 3rem 0 0; + + button { + @include font-size(large); + padding: .75rem; + } + + &-submit { + flex: 4; + margin-left: 1rem; + } + + &-back, + &-cancel { + color: currentColor; + + &:hover { + color: $primary-light; + } + } + + &-cancel { + flex: 1; + } + + &-back { + width: 10%; + } + } + &-warning { + @include font-size(small); + border: 1px solid $red-light; + display: flex; + padding: 1rem; + margin-bottom: 1rem; + .icon-exclamation { + fill: $red-light; + margin-right: .5rem; + vertical-align: middle; + } + a { + color: $primary; + display: inline-block; + margin-left: .25rem; + } + } + .spin { + text-align: center; + width: 100%; + } +} diff --git a/app/styles/dependencies/mixins/import.scss b/app/styles/dependencies/mixins/import.scss new file mode 100644 index 00000000..877481ac --- /dev/null +++ b/app/styles/dependencies/mixins/import.scss @@ -0,0 +1,182 @@ +@mixin import-project-selector { + @include centered; + max-width: 800px; + .import-project-selector { + + &-service { + img { + display: block; + margin: 1rem auto; + width: 4rem; + } + } + + &-filter { + align-items: center; + background: $whitish; + display: flex; + padding: .5rem; + + input { + background: $mass-white; + border: 0; + flex: 1; + padding: .5rem; + } + + svg { + @include svg-size(1rem); + fill: $gray; + margin: 0 1rem; + } + } + + &-title { + border-bottom: 1px solid $whitish; + padding: 1rem; + + &:hover { + background: rgba($primary, .1); + cursor: pointer; + } + } + } +} +@mixin import-members { + @include centered; + max-width: 800px; + .avatar { + width: 48px; + } + &-title { + @include font-size(normal); + @include font-type(bold); + margin-bottom: 0; + } + + &-system { + display: flex; + justify-content: space-between; + margin: 1rem 0 0; + padding: .5rem 0; + + img { + width: 100%; + } + } + + &-logo { + max-height: 3rem; + max-width: 3rem; + } + + &-row { + align-items: center; + border-bottom: 1px solid $whitish; + border-top: 1px solid $whitish; + display: flex; + justify-content: space-between; + padding: .5rem 0; + + &:hover { + .import-project-members-delete { + opacity: 1; + transition: all .2s ease-in; + } + } + } + + &-single { + align-items: center; + display: flex; + } + + &-username { + margin-left: 1rem; + } + + .avatar { + &.empty { + background-color: $whitish; + line-height: 3rem; + text-align: center; + width: 3rem; + } + } + + &-actions { + align-items: center; + display: flex; + } + &-delete { + background: transparent; + opacity: 0; + padding: .25rem .5rem; + svg { + @include svg-size(.75rem); + fill: $red; + } + } + &-match { + color: $gray-light; + button { + background: $white; + border-radius: 50%; + padding: .25rem .5rem; + svg { + @include svg-size(.75rem); + } + } + &-true { + border: 1px solid $primary; + margin: 0 .1rem 0 .25rem; + transition: background .2s; + &:hover { + background: rgba($primary-light, .3); + } + svg { + fill: $primary; + } + } + &-false { + border: 1px solid $red; + margin: 0 .25rem 0 .1rem; + transition: background .2s; + &:hover { + background: rgba($red, .3); + } + svg { + fill: $red; + } + } + } + + &-choose { + color: $primary; + padding-right: 0; + text-transform: lowercase; + &:hover { + color: $primary-light; + } + } + + &-selected { + align-items: center; + display: flex; + + &-img { + margin-left: .5rem; + max-width: 3rem; + } + + img { + width: 100%; + } + } + + &-submit { + display: block; + margin: 2rem auto 0; + padding: .75rem 4rem; + } +} diff --git a/app/styles/dependencies/mixins/popover.scss b/app/styles/dependencies/mixins/popover.scss index 595896a7..175d1bb1 100644 --- a/app/styles/dependencies/mixins/popover.scss +++ b/app/styles/dependencies/mixins/popover.scss @@ -8,7 +8,8 @@ $arrow-top: '', $arrow-left: '', $arrow-bottom: '', - $arrow-height: 15px + $arrow-height: 15px, + $align: 'center' ) { @include font-type(light); @include font-size(small); @@ -25,7 +26,7 @@ top: #{$top}; width: $width; z-index: 99; - text-align: center; + text-align: $align; a { @include font-size(small); border-bottom: 1px solid $grayer; diff --git a/app/styles/dependencies/mixins/radio-group.scss b/app/styles/dependencies/mixins/radio-group.scss new file mode 100644 index 00000000..f04577da --- /dev/null +++ b/app/styles/dependencies/mixins/radio-group.scss @@ -0,0 +1,19 @@ +@mixin radio-group { + input { + opacity: 0; + &:checked+svg { + fill: rgba($primary, .6); + stroke: rgba($primary, .1); + } + } + svg { + fill: $whitish; + stroke: darken($whitish, 10%); + stroke-width: 1px; + vertical-align: middle; + } + .control-indicator { + padding-left: .25rem; + @include font-type(normal); + } +} diff --git a/app/styles/dependencies/responsive.scss b/app/styles/dependencies/responsive.scss index 3d4f8457..b88606cb 100644 --- a/app/styles/dependencies/responsive.scss +++ b/app/styles/dependencies/responsive.scss @@ -1,6 +1,6 @@ @mixin breakpoint($point) { @if $point == desktop { - @media (min-width: 1200px) { @content ; } + @media (min-width: 1400px) { @content ; } } @else if $point == laptop { @media (max-width: 1280px) { @content ; } diff --git a/app/styles/extras/dependencies.scss b/app/styles/extras/dependencies.scss index 2d94ceff..c6b29c92 100644 --- a/app/styles/extras/dependencies.scss +++ b/app/styles/extras/dependencies.scss @@ -1,5 +1,5 @@ // Bourbon -@import '../../../vendor/bourbon/app/assets/stylesheets/bourbon'; +@import '../../../node_modules/bourbon/core/bourbon'; //################################################# // dependencies @@ -14,6 +14,10 @@ @import '../dependencies/mixins/box-arrow'; @import '../dependencies/mixins/box-shadow'; @import '../dependencies/mixins/centered'; +@import '../dependencies/mixins/btn-group'; +@import '../dependencies/mixins/import'; +@import '../dependencies/mixins/create'; +@import '../dependencies/mixins/radio-group'; @import '../dependencies/mixins/lightbox'; @import '../dependencies/mixins/loading-spinner'; @import '../dependencies/mixins/popover'; @@ -22,3 +26,13 @@ @import '../dependencies/mixins/svg'; @import '../dependencies/mixins/track-buttons'; @import '../dependencies/mixins/empty-color'; + +//deprecated +@mixin placeholder { + $placeholders: ":-webkit-input" ":-moz" "-moz" "-ms-input"; + @each $placeholder in $placeholders { + &:#{$placeholder}-placeholder { + @content; + } + } +} diff --git a/app/styles/layout/auth.scss b/app/styles/layout/auth.scss index de95a0c5..aa2a972a 100644 --- a/app/styles/layout/auth.scss +++ b/app/styles/layout/auth.scss @@ -23,7 +23,7 @@ } .logo { @include font-size(xxlarge); - @include font-type(text); + @include font-type(light); color: $white; margin-bottom: 1rem; text-align: center; diff --git a/app/styles/layout/backlog.scss b/app/styles/layout/backlog.scss index f59fda27..e6feca25 100644 --- a/app/styles/layout/backlog.scss +++ b/app/styles/layout/backlog.scss @@ -25,24 +25,16 @@ display: flex; justify-content: space-between; margin-bottom: 1rem; + @include breakpoint(laptop) { + flex-direction: column; + } .menu-button { - border-radius: 0; - color: $blackish; - display: inline-block; - padding: .4rem 1.5rem; - &.active, - &:hover { - background: $whitish; - color: $gray; - } - &.active { - &:hover { - background: darken($whitish, 10%); - } - } &.move-to-sprint { display: none; } + .icon-move { + margin-right: .25rem; + } } .button-bulk { margin-left: .2rem; @@ -70,3 +62,23 @@ background: $white; } } + +.forecasting-add-sprint { + @include font-size(small); + background: $mass-white; + cursor: pointer; + padding: .5rem 0; + text-align: center; + &:hover { + background: darken($mass-white, 3%); + transition: background .2s; + } + .icon-add { + @include svg-size(1.75rem); + background: $primary-light; + fill: $white; + margin-right: 1rem; + padding: .25rem; + vertical-align: middle; + } +} diff --git a/app/styles/layout/invitation.scss b/app/styles/layout/invitation.scss index cbdf801c..f2d23cdb 100644 --- a/app/styles/layout/invitation.scss +++ b/app/styles/layout/invitation.scss @@ -5,6 +5,7 @@ background-size: cover; display: flex; flex: 1; + height: 100vh; justify-content: center; z-index: 999; .invitation-container { @@ -107,4 +108,10 @@ border-right: 0; } } + + .contrib-plugins-wrapper { + label { + color: $whitish; + } + } } diff --git a/app/styles/layout/issues.scss b/app/styles/layout/issues.scss index 52e9deff..4c9e48fb 100644 --- a/app/styles/layout/issues.scss +++ b/app/styles/layout/issues.scss @@ -3,4 +3,7 @@ position: relative; width: 260px; } + tg-filter { + transform: translateX(0); + } } diff --git a/app/styles/layout/kanban.scss b/app/styles/layout/kanban.scss index dca0852f..aad6c8c8 100644 --- a/app/styles/layout/kanban.scss +++ b/app/styles/layout/kanban.scss @@ -14,6 +14,10 @@ .burndown-container { display: none; } + .zoom-loading img { + display: block; + margin-right: 1rem; + } } .kanban-header { diff --git a/app/styles/layout/taskboard.scss b/app/styles/layout/taskboard.scss index e213b56f..45e34a89 100644 --- a/app/styles/layout/taskboard.scss +++ b/app/styles/layout/taskboard.scss @@ -10,6 +10,10 @@ .graphics-container { @include slide(300px, hidden); } + .zoom-loading img { + display: block; + margin-right: 1rem; + } } .taskboard-header { diff --git a/app/styles/layout/ticket-detail.scss b/app/styles/layout/ticket-detail.scss index 30af3d0a..8e0efc4f 100644 --- a/app/styles/layout/ticket-detail.scss +++ b/app/styles/layout/ticket-detail.scss @@ -59,7 +59,7 @@ .no-description { color: $gray-light; } - textarea { + .markdown { background: $white; height: 10rem; } diff --git a/app/styles/layout/wiki.scss b/app/styles/layout/wiki.scss index 3930ca41..e1b26a37 100644 --- a/app/styles/layout/wiki.scss +++ b/app/styles/layout/wiki.scss @@ -10,73 +10,3 @@ padding: 1rem; } } - -.wiki-content { - @include font-size(large); - position: relative; - &.editable { - &:hover { - .wysiwyg { - background: $mass-white; - cursor: pointer; - } - } - } - .view-wiki-content { - &:hover { - .edit { - opacity: 1; - top: -1.5rem; - transition: all .2s linear; - } - } - } - .edit { - @include svg-size(2rem); - background: $mass-white; - left: 0; - opacity: 0; - padding: .2rem .5rem; - position: absolute; - top: 0; - transition: all .2s linear; - &:hover { - cursor: pointer; - } - } - .preview { - padding-top: 1.8rem; - } -} - -.edit-wiki-content { - a { - display: inline-block; - margin-right: .5rem; - &:last-child { - margin: 0; - } - &:hover { - cursor: pointer; - .icon { - fill: $primary-dark; - opacity: .3; - transition: all .2s linear; - } - } - } - .preview-icon { - position: absolute; - right: 3.5rem; - } - .action-container { - position: absolute; - right: 1rem; - top: .3rem; - } - .edit { - position: absolute; - right: 3.5rem; - top: .4rem; - } -} diff --git a/app/styles/modules/admin/admin-membership-table.scss b/app/styles/modules/admin/admin-membership-table.scss index 0312b8f1..126f3a23 100644 --- a/app/styles/modules/admin/admin-membership-table.scss +++ b/app/styles/modules/admin/admin-membership-table.scss @@ -5,32 +5,23 @@ .avatar { align-items: center; display: flex; - justify-content: flex-start; - figcaption { - margin-left: 1rem; - width: 75%; - span { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - width: 100%; - } - } img { - flex-basis: 35px; - flex-grow: 1; - max-width: 35px; + border-radius: 4px; + flex-grow: 0; + margin: 0 .5rem 0 .3rem; + width: 50px; } - .name, - .email { - display: block; - width: 100%; + .data { + @include font-type(light); + @include font-size(small); + color: $gray; + margin-top: .2rem; } - .name { - @include font-type(bold); - } - .email { - color: $gray-light; + .pending { + @include font-type(normal); + color: $red-light; + display: inline-block; + padding-left: .3rem; } } .header-role, diff --git a/app/styles/modules/admin/admin-project-profile.scss b/app/styles/modules/admin/admin-project-profile.scss index 31060629..0984f6f6 100644 --- a/app/styles/modules/admin/admin-project-profile.scss +++ b/app/styles/modules/admin/admin-project-profile.scss @@ -1,13 +1,18 @@ @import '../dependencies/mixins/profile-form'; .project-details { @include profile-form; - .looking-for-people { + .looking-for-people, + .get-feedback { @include font-type(light); border-bottom: 1px solid $whitish; - border-top: 1px solid $whitish; padding: 1rem 0; } - .looking-for-people-selector { + .looking-for-people { + border-top: 1px solid $whitish; + margin-bottom: 0; + } + .looking-for-people-selector, + .get-feedback-inner { align-items: center; display: flex; svg { diff --git a/app/styles/modules/auth/login-form.scss b/app/styles/modules/auth/login-form.scss index 03e5e556..1fabdf05 100644 --- a/app/styles/modules/auth/login-form.scss +++ b/app/styles/modules/auth/login-form.scss @@ -10,6 +10,7 @@ } } } + .forgot-pass { @include font-size(small); color: $gray; diff --git a/app/styles/modules/backlog/backlog-table.scss b/app/styles/modules/backlog/backlog-table.scss index be8607f0..eba8eb0d 100644 --- a/app/styles/modules/backlog/backlog-table.scss +++ b/app/styles/modules/backlog/backlog-table.scss @@ -32,8 +32,7 @@ width: 100%; } .status { - flex-basis: 120px; - flex-grow: 0; + flex-grow: 1; flex-shrink: 0; } .points { @@ -145,6 +144,10 @@ } .backlog-table-body { + &.forecasted-stories { + border: .5rem solid $mass-white; + border-bottom: 0; + } .row { border-bottom: 1px solid darken($whitish, 4%); cursor: move; diff --git a/app/styles/modules/common/colors-table.scss b/app/styles/modules/common/colors-table.scss index fabf7df4..902fa371 100644 --- a/app/styles/modules/common/colors-table.scss +++ b/app/styles/modules/common/colors-table.scss @@ -79,9 +79,16 @@ flex-basis: 100px; } .status-slug { + display: none; flex-basis: 150px; flex-grow: 6; padding: 0 10px; + @include breakpoint(desktop) { + display: block; + } + span { + @include ellipsis(100%); + } } .options-column { max-width: 100px; @@ -94,13 +101,17 @@ text-align: center; } .is-closed-column { - max-width: 130px; + max-width: 100px; text-align: center; } .status-wip-limit { - max-width: 130px; + display: none; + max-width: 100px; padding: 0 0 0 10px; text-align: center; + @include breakpoint(desktop) { + display: block; + } } } @@ -163,4 +174,5 @@ visibility: hidden; } } + } diff --git a/app/styles/modules/common/contrib-plugins.scss b/app/styles/modules/common/contrib-plugins.scss new file mode 100644 index 00000000..26f0d09a --- /dev/null +++ b/app/styles/modules/common/contrib-plugins.scss @@ -0,0 +1,8 @@ +.contrib-plugins-wrapper { + margin: 1rem 0 2rem; + label { + @include font-size(small); + display: block; + margin-bottom: .5rem; + } +} diff --git a/app/styles/modules/common/custom-fields.scss b/app/styles/modules/common/custom-fields.scss index d2aed368..792550bb 100644 --- a/app/styles/modules/common/custom-fields.scss +++ b/app/styles/modules/common/custom-fields.scss @@ -24,7 +24,7 @@ border-bottom: 1px solid $whitish; display: flex; justify-content: flex-start; - padding: 1rem; + padding: .7rem; &:hover { .custom-field-options { opacity: 1; @@ -71,6 +71,9 @@ padding: 0 1rem 0 2rem; &.js-value-view-mode { white-space: pre-line; + &.wysiwyg { + white-space: normal; + } } } form { @@ -82,3 +85,40 @@ } } } + +.custom-fields-body { + display: flex; + flex-wrap: wrap; + &.collapse-fields { + .custom-attribute { + flex-basis: 50%; + @include breakpoint(laptop) { + flex-basis: 100%; + &:nth-child(even) { + padding: 0; + } + &:nth-child(odd) { + padding: 0; + } + } + &:nth-child(even) { + padding: 0 0 0 2rem; + } + &:nth-child(odd) { + padding: 0 2rem 0 0; + } + } + } + .custom-attribute { + flex-basis: 100%; + &:nth-child(even) { + padding: 0; + } + &:nth-child(odd) { + padding: 0; + } + } + .custom-field-single { + height: 100%; + } +} diff --git a/app/styles/modules/common/lightbox.scss b/app/styles/modules/common/lightbox.scss index 6df94cbc..255254d3 100644 --- a/app/styles/modules/common/lightbox.scss +++ b/app/styles/modules/common/lightbox.scss @@ -143,83 +143,6 @@ margin-bottom: 1rem; } } - -.lightbox-add-member { - .add-member-wrapper { - max-width: 600px; - width: 90%; - } - .add-single-member { - align-items: center; - display: flex; - justify-content: space-between; - margin-bottom: .5rem; - &:last-child { - margin-bottom: 0; - } - fieldset { - display: inline-block; - flex: 1; - margin: 0 .5rem 0 0; - &:last-child { - flex-basis: 30px; - flex-grow: 0; - flex-shrink: 0; - } - &:first-child { - flex-basis: 20%; - } - - } - } - .icon { - @include svg-size(1.25rem); - fill: $gray; - margin-left: .5rem; - } - .icon-add { - &:hover { - fill: $primary; - transition: fill .2s; - } - } - .icon-trash { - fill: $red-light; - &:hover { - fill: $red; - transition: fill .2s; - } - } - .member-limit-warning { - @include font-size(small); - background: $mass-white; - color: $grayer; - margin: 1rem 0; - padding: 1rem 2rem; - text-align: center; - a { - color: $primary; - &:hover { - color: $primary-light; - } - } - } - .help-text { - @include font-size(small); - @include font-type(light); - margin-top: 1rem; - } - .checksley-error-list { - right: .5rem; - li { - display: none; - &:first-child { - display: block; - } - } - } -} - .lightbox-sprint-add-edit { form { flex-basis: 600px; diff --git a/app/styles/modules/common/ticket-data.scss b/app/styles/modules/common/ticket-data.scss index edcdeea1..e1564075 100644 --- a/app/styles/modules/common/ticket-data.scss +++ b/app/styles/modules/common/ticket-data.scss @@ -84,7 +84,7 @@ position: relative; transition: background .2s ease-in; .pop-type { - @include popover(150px, '', 30px, '', ''); + @include popover(150px, 30px, 30px, '', '', 0, '', '', '', 15px, 'left'); } } .severity-data { @@ -95,7 +95,7 @@ position: relative; transition: background .2s ease-in; .pop-severity { - @include popover(150px, '', 30px, '', ''); + @include popover(150px, 30px, 30px, '', '', 0, '', '', '', 15px, 'left'); } } .priority-data { @@ -106,7 +106,7 @@ position: relative; transition: background .2s ease-in; .pop-priority { - @include popover(150px, '', 30px, '', ''); + @include popover(150px, 30px, 30px, '', '', 0, '', '', '', 15px, 'left'); } } } diff --git a/app/styles/modules/common/wizard.scss b/app/styles/modules/common/wizard.scss deleted file mode 100644 index 1ac0c065..00000000 --- a/app/styles/modules/common/wizard.scss +++ /dev/null @@ -1,143 +0,0 @@ -.wizard-create-project { - @include lightbox; - .close { - @include svg-size(2rem); - } - form { - width: 700px; - } - header { - margin-bottom: 3rem; - .title { - margin-bottom: 0; - } - .subtitle { - @include font-size(small); - color: $gray-light; - text-align: center; - } - } - .template-selector-title { - display: flex; - justify-content: space-between; - margin-bottom: 1rem; - } - .template-selector { - display: flex; - margin-bottom: 1rem; - input { - display: none; - } - fieldset { - &:first-child { - margin-right: .5rem; - } - } - } - input { - &:checked+label { - background: $primary-light; - color: $white; - transition: background .2s ease-in; - &:hover { - background: $primary-light; - } - } - +label { - background: rgba($whitish, .7); - cursor: pointer; - display: block; - padding: 2rem 1rem; - text-align: center; - transition: background .2s ease-in; - &:hover { - background: rgba($primary-light, .3); - transition: background .2s ease-in; - } - .icon { - @include svg-size(1.5rem); - fill: currentColor; - margin-right: .3rem; - vertical-align: text-top; - } - .template-name { - @include font-size(large); - text-transform: uppercase; - } - } - } - input[disabled]+label { - background: lighten($whitish, 5%); - box-shadow: none; - color: lighten($gray-light, 20%); - cursor: not-allowed; - opacity: .65; - &:hover { - background: lighten($whitish, 5%); - color: lighten($gray-light, 20%); - } - } - .template-data { - legend { - display: block; - margin-bottom: .5rem; - } - input, - textarea { - background: none; - border: 1px solid $whitish; - color: $gray-light; - @include placeholder { - color: darken($whitish, 20%); - } - } - textarea { - height: 7rem; - min-height: 7rem; - } - } - .template-privacity { - display: flex; - fieldset { - margin-bottom: 0; - &:first-child { - margin-right: .5rem; - } - } - input { - display: none; - } - label { - display: block; - text-align: center; - text-transform: uppercase; - - } - input+label { - padding: 1rem; - } - svg { - @include svg-size(.7rem); - } - } - .create-warning { - @include font-size(small); - padding: 1rem; - text-align: center; - .icon-exclamation { - fill: $red-light; - margin-right: .5rem; - vertical-align: middle; - } - a { - color: $primary; - display: inline-block; - margin-left: .25rem; - } - } - .button-green { - display: block; - margin: 1rem 5rem; - width: calc(100% - 10rem); - } -} diff --git a/app/styles/modules/home-project.scss b/app/styles/modules/home-project.scss index 3da70541..db929b69 100644 --- a/app/styles/modules/home-project.scss +++ b/app/styles/modules/home-project.scss @@ -79,9 +79,16 @@ h3 { @include font-size(small); } + .is-empty { + margin-bottom: .5rem; + } p { @include font-size(small); @include font-type(light); + margin-bottom: .5rem; + } + .contact-team { + margin-bottom: 1rem; } } .involved-data { diff --git a/app/styles/vendor/codehilite.github.css b/app/styles/vendor/codehilite.github.css deleted file mode 100644 index 6121071b..00000000 --- a/app/styles/vendor/codehilite.github.css +++ /dev/null @@ -1,64 +0,0 @@ -.codehilite .hll { background-color: #49483e } -.codehilite .c { color: #75715e } /* Comment */ -.codehilite .err { color: #960050; background-color: #1e0010 } /* Error */ -.codehilite .k { color: #66d9ef } /* Keyword */ -.codehilite .l { color: #ae81ff } /* Literal */ -.codehilite .n { color: #f8f8f2 } /* Name */ -.codehilite .o { color: #f92672 } /* Operator */ -.codehilite .p { color: #f8f8f2 } /* Punctuation */ -.codehilite .cm { color: #75715e } /* Comment.Multiline */ -.codehilite .cp { color: #75715e } /* Comment.Preproc */ -.codehilite .c1 { color: #75715e } /* Comment.Single */ -.codehilite .cs { color: #75715e } /* Comment.Special */ -.codehilite .ge { font-style: italic } /* Generic.Emph */ -.codehilite .gs { font-weight: bold } /* Generic.Strong */ -.codehilite .kc { color: #66d9ef } /* Keyword.Constant */ -.codehilite .kd { color: #66d9ef } /* Keyword.Declaration */ -.codehilite .kn { color: #f92672 } /* Keyword.Namespace */ -.codehilite .kp { color: #66d9ef } /* Keyword.Pseudo */ -.codehilite .kr { color: #66d9ef } /* Keyword.Reserved */ -.codehilite .kt { color: #66d9ef } /* Keyword.Type */ -.codehilite .ld { color: #e6db74 } /* Literal.Date */ -.codehilite .m { color: #ae81ff } /* Literal.Number */ -.codehilite .s { color: #e6db74 } /* Literal.String */ -.codehilite .na { color: #a6e22e } /* Name.Attribute */ -.codehilite .nb { color: #f8f8f2 } /* Name.Builtin */ -.codehilite .nc { color: #a6e22e } /* Name.Class */ -.codehilite .no { color: #66d9ef } /* Name.Constant */ -.codehilite .nd { color: #a6e22e } /* Name.Decorator */ -.codehilite .ni { color: #f8f8f2 } /* Name.Entity */ -.codehilite .ne { color: #a6e22e } /* Name.Exception */ -.codehilite .nf { color: #a6e22e } /* Name.Function */ -.codehilite .nl { color: #f8f8f2 } /* Name.Label */ -.codehilite .nn { color: #f8f8f2 } /* Name.Namespace */ -.codehilite .nx { color: #a6e22e } /* Name.Other */ -.codehilite .py { color: #f8f8f2 } /* Name.Property */ -.codehilite .nt { color: #f92672 } /* Name.Tag */ -.codehilite .nv { color: #f8f8f2 } /* Name.Variable */ -.codehilite .ow { color: #f92672 } /* Operator.Word */ -.codehilite .w { color: #f8f8f2 } /* Text.Whitespace */ -.codehilite .mf { color: #ae81ff } /* Literal.Number.Float */ -.codehilite .mh { color: #ae81ff } /* Literal.Number.Hex */ -.codehilite .mi { color: #ae81ff } /* Literal.Number.Integer */ -.codehilite .mo { color: #ae81ff } /* Literal.Number.Oct */ -.codehilite .sb { color: #e6db74 } /* Literal.String.Backtick */ -.codehilite .sc { color: #e6db74 } /* Literal.String.Char */ -.codehilite .sd { color: #e6db74 } /* Literal.String.Doc */ -.codehilite .s2 { color: #e6db74 } /* Literal.String.Double */ -.codehilite .se { color: #ae81ff } /* Literal.String.Escape */ -.codehilite .sh { color: #e6db74 } /* Literal.String.Heredoc */ -.codehilite .si { color: #e6db74 } /* Literal.String.Interpol */ -.codehilite .sx { color: #e6db74 } /* Literal.String.Other */ -.codehilite .sr { color: #e6db74 } /* Literal.String.Regex */ -.codehilite .s1 { color: #e6db74 } /* Literal.String.Single */ -.codehilite .ss { color: #e6db74 } /* Literal.String.Symbol */ -.codehilite .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */ -.codehilite .vc { color: #f8f8f2 } /* Name.Variable.Class */ -.codehilite .vg { color: #f8f8f2 } /* Name.Variable.Global */ -.codehilite .vi { color: #f8f8f2 } /* Name.Variable.Instance */ -.codehilite .il { color: #ae81ff } /* Literal.Number.Integer.Long */ - -.codehilite .gh { } /* Generic Heading & Diff Header */ -.codehilite .gu { color: #75715e; } /* Generic.Subheading & Diff Unified/Comment? */ -.codehilite .gd { color: #f92672; } /* Generic.Deleted & Diff Deleted */ -.codehilite .gi { color: #a6e22e; } /* Generic.Inserted & Diff Inserted */ diff --git a/app/styles/vendor/markitup.css b/app/styles/vendor/markitup.css deleted file mode 100644 index 93a8a345..00000000 --- a/app/styles/vendor/markitup.css +++ /dev/null @@ -1,175 +0,0 @@ -/* ------------------------------------------------------------------- -// markItUp! -// By Jay Salvat - http://markitup.jaysalvat.com/ -// ------------------------------------------------------------------*/ -.markItUp .markItUpButton1 a { - background-image:url("../images/markitup/h1.png"); -} - -.markItUp .markItUpButton2 a { - background-image:url("../images/markitup/h2.png"); -} - -.markItUp .markItUpButton3 a { - background-image:url("../images/markitup/h3.png"); -} - -.markItUp .markItUpButton4 a { - background-image:url("../images/markitup/bold.png"); -} -.markItUp .markItUpButton5 a { - background-image:url("../images/markitup/italic.png"); -} - -.markItUp .markItUpButton6 a { - background-image:url("../images/markitup/stroke.png"); -} - -.markdown .markItUpButton7 a { - background-image:url("../images/markitup/list-bullet.png"); -} -.markdown .markItUpButton8 a { - background-image:url("../images/markitup/list-numeric.png"); -} - -.markdown .markItUpButton9 a { - background-image:url("../images/markitup/picture.png"); -} -.markdown .markItUpButton10 a { - background-image:url("../images/markitup/link.png"); -} - -.markdown .markItUpButton11 a { - background-image:url("../images/markitup/quotes.png"); -} -.markdown .markItUpButton12 a { - background-image:url("../images/markitup/code.png"); -} - -.markdown .preview-icon a { - background-image:url("../images/markitup/preview.png"); -} - -.markdown .help a { - background-image:url("../images/markitup/help.png"); -} - - -/* ------------------------------------------------------------------- -// markItUp! Universal MarkUp Engine, JQuery plugin -// By Jay Salvat - http://markitup.jaysalvat.com/ -// ------------------------------------------------------------------*/ -.markItUp * { - margin:0px; padding:0px; - outline:none; -} -.markItUp a:link, -.markItUp a:visited { - color:#000; - text-decoration:none; -} -.markItUpContainer { - padding:5px 5px 2px 5px; - font:11px Verdana, Arial, Helvetica, sans-serif; -} -.markItUpEditor { - font:12px 'Courier New', Courier, monospace; - padding:5px; - height:320px; - clear:both; - line-height:18px; - overflow:auto; -} -.markItUpPreviewFrame { - overflow:auto; - background-color:#FFF; - width:99.9%; - height:300px; - margin:5px 0; -} -.markItUpFooter { - width:100%; -} -.markItUpResizeHandle { - overflow:hidden; - width:22px; height:5px; - margin-left:auto; - margin-right:auto; - background-image:url(../images/markitup/handle.png); - cursor:n-resize; -} -/***************************************************************************************/ -/* first row of buttons */ -.markItUp .markItUpHeader ul { - margin: 0; -} -.markItUpHeader ul li { - list-style:none; - float:left; - position:relative; - margin: 3px; -} -.markItUpHeader ul li:hover > ul{ - display:block; -} -.markItUpHeader ul .markItUpDropMenu { - background:transparent url(../images/markitup/menu.png) no-repeat 115% 50%; - margin-right:5px; -} -.markItUpHeader ul .markItUpDropMenu li { - margin-right:0px; -} -/* next rows of buttons */ -.markItUpHeader ul ul { - display:none; - position:absolute; - top:18px; left:0px; - background:#FFF; - border:1px solid #000; -} -.markItUpHeader ul ul li { - float:none; - border-bottom:1px solid #000; -} -.markItUpHeader ul ul .markItUpDropMenu { - background:#FFF url(../images/markitup/submenu.png) no-repeat 100% 50%; -} -.markItUpHeader ul .markItUpSeparator { - margin:2px 10px 0 10px; - width:1px; - height:16px; - overflow:hidden; - background-color:#CCC; -} -.markItUpHeader ul ul .markItUpSeparator { - width:auto; height:1px; - margin:0px; -} -/* next rows of buttons */ -.markItUpHeader ul ul ul { - position:absolute; - top:-1px; left:150px; -} -.markItUpHeader ul ul ul li { - float:none; -} -.markItUpHeader ul a { - display:block; - width:16px; height:16px; - text-indent:-10000px; - background-repeat:no-repeat; - padding:3px; - margin:0px; -} -.markItUpHeader ul ul a { - display:block; - padding-left:0px; - text-indent:0; - width:120px; - padding:5px 5px 5px 25px; - background-position:2px 50%; -} -.markItUpHeader ul ul a:hover { - color:#FFF; - background-color:#000; -} diff --git a/app/svg/editor.svg b/app/svg/editor.svg new file mode 100644 index 00000000..352ac011 --- /dev/null +++ b/app/svg/editor.svg @@ -0,0 +1,60 @@ + + + + editor-list-o + + + + editor-rtl + + + + editor-quote + + + + editor-list-n + + + + editor-no-format + + + + editor-link + + + + editor-italic + + + + editor-image + + + + editor-h3 + + + + editor-h1 + + + + editor-h2 + + + + editor-cross-out + + + + editor-code + + + + editor-bold + + + + diff --git a/app/svg/sprite.svg b/app/svg/sprite.svg index 869e7c00..bdca9a97 100644 --- a/app/svg/sprite.svg +++ b/app/svg/sprite.svg @@ -440,7 +440,7 @@ Merge - + Fill @@ -448,11 +448,20 @@ Epics - + Broken Link - + + + + + + + Duplicate + diff --git a/app/themes/high-contrast/custom.scss b/app/themes/high-contrast/custom.scss index f460705b..cf395204 100644 --- a/app/themes/high-contrast/custom.scss +++ b/app/themes/high-contrast/custom.scss @@ -443,6 +443,6 @@ tg-project-menu { // DASHBOARD .home-wrapper { .title-bar { - color: $white; + color: $black; } } diff --git a/app/themes/high-contrast/variables.scss b/app/themes/high-contrast/variables.scss index 1ecd40e2..e3a7a7e3 100755 --- a/app/themes/high-contrast/variables.scss +++ b/app/themes/high-contrast/variables.scss @@ -39,6 +39,7 @@ $tribe-secondary: darken($tribe-primary, 10%); $top-icon-color: $white; $dropdown-color: rgba(darken($primary-dark, 20%), 1); +$code-bg: #272822; /* Overwrite mixins */ diff --git a/app/themes/material-design/variables.scss b/app/themes/material-design/variables.scss index f975e2c3..b59deb2b 100755 --- a/app/themes/material-design/variables.scss +++ b/app/themes/material-design/variables.scss @@ -39,6 +39,7 @@ $tribe-secondary: darken($tribe-primary, 10%); $top-icon-color: $white; $dropdown-color: rgba(darken($primary-dark, 20%), 1); +$code-bg: #272822; /* Overwrite mixins */ diff --git a/app/themes/taiga/variables.scss b/app/themes/taiga/variables.scss index ebc23064..9f692c77 100755 --- a/app/themes/taiga/variables.scss +++ b/app/themes/taiga/variables.scss @@ -39,3 +39,4 @@ $tribe-secondary: darken($tribe-primary, 10%); $top-icon-color: #11241f; $dropdown-color: rgba(darken($grayer, 20%), 1); +$code-bg: #272822; \ No newline at end of file diff --git a/bower.json b/bower.json deleted file mode 100644 index 80144e0f..00000000 --- a/bower.json +++ /dev/null @@ -1,90 +0,0 @@ -{ - "name": "taiga-layout", - "version": "2.1.0", - "homepage": "https://github.com/taiga.io/taiga-layout", - "authors": [ - { - "name": "Andrey Antukh", - "email": "niwi@niwi.nz" - }, - { - "name": "Jesus Espino Garcia", - "email": "jespinog@gmail.com" - }, - { - "name": "David Barragán Merino", - "email": "dbarragan@dbarragan.com" - }, - { - "name": "Xavi Julian", - "email": "xavier.julian@kaleidos.net" - }, - { - "name": "Alejandro Alonso", - "email": "alejandro.alonso@kaleidos.net" - }, - { - "name": "Anler Hernández", - "email": "hello@anler.me" - }, - { - "name": "Juan Francisco Alcántara", - "email": "juanfran.alcantara@kaleidos.net" - } - ], - "description": "Taiga project management system (frontend)", - "license": "AGPL-3.0", - "repository": { - "type": "git", - "url": "git@github.com:taigaio/taiga-front.git" - }, - "ignore": [ - "**/.*", - "node_modules", - "bower_components", - "app/vendor", - "test", - "tests" - ], - "dependencies": { - "emoticons": "~0.1.7", - "jquery-flot": "~0.8.2", - "angular": "1.5.5", - "angular-route": "1.5.5", - "angular-animate": "1.5.5", - "angular-aria": "1.5.5", - "angular-sanitize": "1.5.5", - "checksley": "~0.6.0", - "jquery": "~2.2.3", - "markitup-1x": "~1.1.14", - "jquery-textcomplete": "yuku-t/jquery-textcomplete#~0.7", - "flot-axislabels": "markrcote/flot-axislabels", - "flot-orderBars": "emmerich/flot-orderBars", - "flot.tooltip": "~0.8.4", - "moment": "~2.13.0", - "pikaday": "~1.4.0", - "raven-js": "~3.0.0", - "l.js": "~0.1.0", - "angular-translate": "~2.10.0", - "angular-translate-loader-partial": "~2.10.0", - "angular-translate-loader-static-files": "~2.10.0", - "angular-translate-interpolation-messageformat": "~2.10.0", - "ng-infinite-scroll-npm-is-better-than-bower": "^1.3.0", - "immutable": "~3.8.1", - "bluebird": "~3.3.5", - "intro.js": "~2.1.0", - "lodash": "~4.11.2", - "messageformat": "^0.3.1", - "dragula.js": "dragula#^3.6.6", - "bourbon": "^4.2.7" - }, - "resolutions": { - "lodash": "~4.11.2", - "moment": "~2.10.6", - "jquery": "~2.2.3", - "angular": "1.5.5", - "messageformat": "0.3.1", - "angular-translate": "2.10.0" - }, - "private": true -} diff --git a/conf.e2e.js b/conf.e2e.js index d7ca0a01..28dab222 100644 --- a/conf.e2e.js +++ b/conf.e2e.js @@ -47,6 +47,7 @@ var config = { search: "e2e/suites/search.e2e.js", team: "e2e/suites/team.e2e.js", discover: "e2e/suites/discover/*.e2e.js", + createProject: "e2e/suites/create-project/*.e2e.js", transferProject: "e2e/suites/transfer-project.e2e.js", compileModules: "app/modules/compile-modules/**/*.e2e.js" }, @@ -111,6 +112,7 @@ var config = { browser.executeScript('window.sessionStorage.clear();'); browser.executeScript('window.localStorage.clear();'); + browser.executeScript('window.localStorage.e2e = true'); browser.driver.manage().window().maximize(); diff --git a/conf/conf.example.json b/conf/conf.example.json index 4f0d8cb6..2412774b 100644 --- a/conf/conf.example.json +++ b/conf/conf.example.json @@ -16,5 +16,6 @@ "maxUploadFileSize": null, "contribPlugins": [], "tribeHost": null, + "importers": [], "gravatar": true } diff --git a/csslintrc.json b/csslintrc.json index 3f615cc3..41704e31 100644 --- a/csslintrc.json +++ b/csslintrc.json @@ -21,5 +21,6 @@ "floats": false, "fallback-colors": false, "adjoining-classes": false, - "qualified-headings": false + "qualified-headings": false, + "outline-none": false } diff --git a/e2e/helpers/admin-memberships.js b/e2e/helpers/admin-memberships.js index e22bc3f5..e0e9759b 100644 --- a/e2e/helpers/admin-memberships.js +++ b/e2e/helpers/admin-memberships.js @@ -18,17 +18,28 @@ helper.getNewMemberLightbox = function() { return utils.lightbox.close(el); }, newEmail: function(email) { - el.$$('input').last().sendKeys(email); - el.$('.add-fieldset').click(); + el.$$('input').clear(); + el.$$('input').sendKeys(email); + el.$('.e2e-add-member-suggest-filter-addmail').click(); }, - getRows: function() { - return el.$$('.add-single-member'); + addSuggested: function(index) { + el.$$('.e2e-add-member-suggest-single').get(index).click(); }, - deleteRow: function(index) { - el.$$('.remove-fieldset').get(index).click(); + addNew: function() { + return el.$$('.e2e-invite-members-single-new').click(); + }, + setRole: function(index) { + let select = el.$$('.e2e-invite-members-single-role').get(index); + select.$('option:last-child').click(); + }, + getInviteds: function() { + return el.$$('.e2e-invite-members-single') + }, + deleteInvited: function(index) { + el.$$('.e2e-invite-members-single-remove').get(index).click(); }, submit: function() { - return el.$('.submit-button').click(); + return el.$('.e2e-invite-members-single-send').click(); } }; diff --git a/e2e/helpers/backlog-helper.js b/e2e/helpers/backlog-helper.js index 932e1c34..4c1f1f19 100644 --- a/e2e/helpers/backlog-helper.js +++ b/e2e/helpers/backlog-helper.js @@ -131,6 +131,22 @@ helper.openNewUs = function() { $$('.new-us a').get(0).click(); }; +helper.velocityForecasting = function() { + return $$('.e2e-velocity-forecasting'); +}; + +helper.openVelocityForecasting = function() { + $$('.e2e-velocity-forecasting').click(); +}; + +helper.createSprintFromForecasting = function() { + $$('.e2e-velocity-forecasting-add').click(); + let sprintName = 'sprintName' + new Date().getTime(); + $('.e2e-sprint-name') + .sendKeys(sprintName) + .sendKeys(protractor.Key.ENTER); +}; + helper.openUsBacklogEdit = function(item) { $$('.backlog-table-body .e2e-edit').get(item).click(); }; diff --git a/e2e/helpers/create-project-helper.js b/e2e/helpers/create-project-helper.js index 8323b73d..7f99f2bb 100644 --- a/e2e/helpers/create-project-helper.js +++ b/e2e/helpers/create-project-helper.js @@ -2,42 +2,35 @@ var utils = require('../utils'); var helper = module.exports; -helper.openWizard = function() { +helper.openCreateProjectPage = function() { $$('.create-project-btn').get(1).click(); }; -helper.createProjectLightbox = function() { +helper.newProjectScreen = function() { let obj = { - el: function() { - return $('div[tg-lb-create-project]'); + selectDuplicateOption: function() { + return utils.common.link($('.e2e-duplicate-project')); }, - waitOpen: function() { - return utils.lightbox.open(obj.el()); + selectScrumOption: function() { + return utils.common.link($('.e2e-create-project-scrum')); }, - waitClose: function() { - return utils.lightbox.close(obj.el()); + selectKanbanOption: function() { + return utils.common.link($('.e2e-create-project-kanban')); }, - next: async function() { - $('.wizard-step.active .button-green').click(); - - await browser.sleep(1000); + selectProjectToDuplicate: function() { + return $$('.e2e-duplicate-project-reference option').get(1).click(); }, - submit: function() { - return $('div[tg-lb-create-project] .button-green').click(); + fillNameAndDescription: async function(name, title){ + await $('.e2e-create-project-title').sendKeys(name); + await $('.e2e-create-project-description').sendKeys(title); }, - name: function() { - return $$('div[tg-lb-create-project] input[type="text"]').get(0); - }, - description: function() { - return $('div[tg-lb-create-project] textarea'); - }, - errors: function() { - return $$('.checksley-error-list li'); + createProject: function() { + return $('.e2e-create-project-action-submit').click(); } }; return obj; -}; +} helper.delete = async function() { $('.delete-project').click(); diff --git a/e2e/helpers/detail-helper.js b/e2e/helpers/detail-helper.js index a315edbb..1c180724 100644 --- a/e2e/helpers/detail-helper.js +++ b/e2e/helpers/detail-helper.js @@ -12,7 +12,12 @@ helper.title = function() { }, setTitle: function(title) { - el.$('.e2e-detail-edit').click(); + browser + .actions() + .mouseMove(el.$('.e2e-detail-edit')) + .click() + .perform(); + el.$('.e2e-title-input').clear().sendKeys(title); }, @@ -38,7 +43,7 @@ helper.description = function(){ }, getInnerHtml: async function(text){ - let html = await el.$(".wysiwyg.editable").getInnerHtml(); + let html = await el.$(".wysiwyg.editable").getAttribute("innerHTML"); return html; }, @@ -109,7 +114,7 @@ helper.statusSelector = function() { return this.getSelectedStatus(); }, getSelectedStatus: async function(){ - return el.$$('.detail-status-inner .e2e-status').first().getInnerHtml(); + return el.$$('.detail-status-inner .e2e-status').first().getAttribute("innerHTML"); } }; @@ -146,24 +151,6 @@ helper.assignedTo = function() { return obj; }; -helper.editComment = function() { - let el = $('.comment-editor'); - let obj = { - el:el, - - updateText: function (text) { - el.$('textarea').sendKeys(text); - }, - - saveComment: async function () { - el.$('.save-comment').click(); - await browser.waitForAngular(); - } - } - return obj; - -}; - helper.history = function() { let el = $('section.history'); let obj = { @@ -179,16 +166,6 @@ helper.history = function() { await browser.waitForAngular(); }, - addComment: async function(comment) { - obj.writeComment(comment); - el.$('.save-comment').click(); - await browser.waitForAngular(); - }, - - writeComment: function(comment) { - el.$('textarea[tg-markitup]').sendKeys(comment); - }, - countComments: async function() { let comments = await el.$$(".comment-wrapper"); return comments.length; @@ -227,6 +204,10 @@ helper.history = function() { await browser.waitForAngular(); }, + getComments: function() { + return $$('tg-comment'); + }, + showVersionsLastComment: async function() { el.$$(".comment-edited a").last().click(); await browser.waitForAngular(); @@ -252,11 +233,11 @@ helper.history = function() { el.$$(".deleted-comment-wrapper .restore-comment").last().click(); await browser.waitForAngular(); } - } + }; return obj; -} +}; helper.block = function() { let el = $('tg-block-button'); @@ -285,8 +266,9 @@ helper.blockLightbox = function() { waitClose: function() { return utils.notifications.success.close(); }, - fill: function(text) { + fill: async function(text) { el.$('textarea').sendKeys(text); + await browser.waitForAngular(); }, submit: async function() { el.$('a.button-green').click(); diff --git a/e2e/helpers/epics-dashboard-helper.js b/e2e/helpers/epics-dashboard-helper.js index 787acd1c..b09e923b 100644 --- a/e2e/helpers/epics-dashboard-helper.js +++ b/e2e/helpers/epics-dashboard-helper.js @@ -22,6 +22,7 @@ helper.epic = function() { $('.e2e-create-epic-blocked').click(); $('.e2e-create-epic-blocked-note').clear().sendKeys(date + description); $('.e2e-create-epic-button').click(); + await browser.waitForAngular(); }, displayUserStoriesinEpic: async function() { utils.common.takeScreenshot("epics", "epics-child-closed"); @@ -79,6 +80,7 @@ helper.epic = function() { $('.e2e-epics-column-button').click(); utils.common.takeScreenshot("epics", "epics-edit-columns"); $$('.e2e-epics-column-dropdown .check').first().click(); + await browser.waitForAngular(); } } diff --git a/e2e/helpers/project-detail-helper.js b/e2e/helpers/project-detail-helper.js index 88f2c81a..784612d2 100644 --- a/e2e/helpers/project-detail-helper.js +++ b/e2e/helpers/project-detail-helper.js @@ -14,6 +14,14 @@ helper.toggleIsLookingForPeople = function() { helper.lookingForPeople().click(); }; +helper.receiveFeedback = function() { + return $$('.get-feedback input').get(0); +}; + +helper.togglereceiveFeedback = function() { + helper.receiveFeedback().click(); +}; + helper.editLogo = function() { let inputFile = $('#logo-field'); diff --git a/e2e/helpers/us-detail-helper.js b/e2e/helpers/us-detail-helper.js index b419d433..7509831e 100644 --- a/e2e/helpers/us-detail-helper.js +++ b/e2e/helpers/us-detail-helper.js @@ -32,15 +32,17 @@ helper.createRelatedTasks = function(name, status, assigned_to) { let form = $('.related-task-create-form'); - return helper.relatedTaskForm(form, status, assigned_to); + return helper.relatedTaskForm(form, name, status, assigned_to); }; -helper.editRelatedTasks = function(taskIndex, name, status, assigned_to) { +helper.editRelatedTasks = async function(taskIndex, name, status, assigned_to) { let task = helper.relatedTasks().get(taskIndex); task.$('.edit-task').click(); - return helper.relatedTaskForm(task, status, assigned_to); + helper.relatedTaskForm(task, name, status, assigned_to); + + await browser.sleep(30000); }; helper.editRelatedTasksEnabled = function() { diff --git a/e2e/helpers/wiki-helper.js b/e2e/helpers/wiki-helper.js index c648d0c5..549b7a23 100644 --- a/e2e/helpers/wiki-helper.js +++ b/e2e/helpers/wiki-helper.js @@ -82,7 +82,7 @@ helper.editor = function(){ }, getInnerHtml: async function(text){ - let wikiText = await el.$(".view-wiki-content .wysiwyg").getInnerHtml(); + let wikiText = await el.$(".view-wiki-content .wysiwyg").getAttribute("innerHTML"); return wikiText; }, diff --git a/e2e/shared/detail.js b/e2e/shared/detail.js index 364813c5..a1240b1e 100644 --- a/e2e/shared/detail.js +++ b/e2e/shared/detail.js @@ -6,6 +6,7 @@ var customFieldsHelper = require('../helpers/custom-fields-helper'); var commonUtil = require('../utils/common'); var lightbox = require('../utils/lightbox'); var notifications = require('../utils/notifications'); +var sharedWysiwyg = require('./wysiwyg').wysiwygTesting; var chai = require('chai'); var chaiAsPromised = require('chai-as-promised'); @@ -48,49 +49,6 @@ shared.tagsTesting = async function() { expect(newtagsText).to.be.not.eql(tagsText); } -shared.descriptionTesting = function() { - it('confirm close with ESC', async function() { - let descriptionHelper = detailHelper.description(); - - descriptionHelper.enabledEditionMode(); - - browser.actions().sendKeys(protractor.Key.ESCAPE).perform(); - - await lightbox.confirm.cancel(); - - let descriptionVisibility = await $('.edit-description').isDisplayed(); - - expect(descriptionVisibility).to.be.true; - - descriptionHelper.focus(); - - browser.actions().sendKeys(protractor.Key.ESCAPE).perform(); - - await lightbox.confirm.ok(); - - descriptionVisibility = await $('.edit-description').isDisplayed(); - - expect(descriptionVisibility).to.be.false; - }); - - it('edit', async function() { - let descriptionHelper = detailHelper.description(); - let description = await descriptionHelper.getInnerHtml(); - let date = Date.now(); - descriptionHelper.enabledEditionMode(); - descriptionHelper.setText("New description " + date); - descriptionHelper.save(); - - let newDescription = await descriptionHelper.getInnerHtml(); - let notificationOpen = await notifications.success.open(); - - expect(notificationOpen).to.be.equal.true; - expect(newDescription).to.be.not.equal(description); - - await notifications.success.close(); - }); -} - shared.statusTesting = async function(status1 , status2) { let statusHelper = detailHelper.statusSelector(); @@ -195,68 +153,9 @@ shared.assignedToTesting = function() { shared.historyTesting = async function(screenshotsFolder) { let historyHelper = detailHelper.history(); - - //Adding a comment - historyHelper.selectCommentsTab(); - await utils.common.takeScreenshot(screenshotsFolder, "show comments tab"); - - let commentsCounter = await historyHelper.countComments(); - let date = Date.now(); - - await historyHelper.addComment("New comment " + date); - await utils.common.takeScreenshot(screenshotsFolder, "new coment"); - - let newCommentsCounter = await historyHelper.countComments(); - expect(newCommentsCounter).to.be.equal(commentsCounter+1); - - //Edit last comment - historyHelper.editLastComment(); - let editComment = detailHelper.editComment(); - editComment.updateText("This is the new and updated text"); - editComment.saveComment(); - await utils.common.takeScreenshot(screenshotsFolder, "edit comment"); - - //Show versions from last comment edited - historyHelper.showVersionsLastComment(); - await utils.common.takeScreenshot(screenshotsFolder, "show comment versions"); - - historyHelper.closeVersionsLastComment(); - - //Deleting last comment - let deletedCommentsCounter = await historyHelper.countDeletedComments(); - await historyHelper.deleteLastComment(); - - let newDeletedCommentsCounter = await historyHelper.countDeletedComments(); - expect(newDeletedCommentsCounter).to.be.equal(deletedCommentsCounter+1); - await utils.common.takeScreenshot(screenshotsFolder, "deleted comment"); - - //Restore last comment - deletedCommentsCounter = await historyHelper.countDeletedComments(); - await historyHelper.restoreLastComment(); - newDeletedCommentsCounter = await historyHelper.countDeletedComments(); - expect(newDeletedCommentsCounter).to.be.equal(deletedCommentsCounter-1); - await utils.common.takeScreenshot(screenshotsFolder, "restored comment"); - - //Store comment with a modification - commentsCounter = await historyHelper.countComments(); - - historyHelper.writeComment("New comment " + date); - let title = detailHelper.title(); - title.setTitle('changed'); - await title.save(); - await utils.notifications.success.close(); - - newCommentsCounter = await historyHelper.countComments(); - - expect(newCommentsCounter).to.be.equal(commentsCounter+1); - //Check activity await historyHelper.selectActivityTab(); await utils.common.takeScreenshot(screenshotsFolder, "show activity tab"); - - let activitiesCounter = await historyHelper.countActivities(); - - expect(newCommentsCounter).to.be.least(1); } shared.blockTesting = async function() { diff --git a/e2e/shared/filters.js b/e2e/shared/filters.js index 3cc193ad..f8049df8 100644 --- a/e2e/shared/filters.js +++ b/e2e/shared/filters.js @@ -43,21 +43,16 @@ module.exports = function(name, counter) { }); it('save custom filters', async () => { - let len = await counter(); let customFiltersSize = await filterHelper.getCustomFilters().count(); await filterHelper.firterByCategoryWithContent(); await filterHelper.saveFilter("custom-filter"); await filterHelper.clearFilters(); - await filterHelper.firterByLastCustomFilter(); - let newLength = await counter(); let newCustomFiltersSize = await filterHelper.getCustomFilters().count(); - expect(newLength).to.be.below(len); expect(newCustomFiltersSize).to.be.equal(customFiltersSize + 1); - await filterHelper.clearFilters(); }); it('remove custom filters', async () => { diff --git a/e2e/shared/wysiwyg.js b/e2e/shared/wysiwyg.js new file mode 100644 index 00000000..1d1b8e2d --- /dev/null +++ b/e2e/shared/wysiwyg.js @@ -0,0 +1,548 @@ +var chai = require('chai'); +var chaiAsPromised = require('chai-as-promised'); + +var detailHelper = require('../helpers').detail; +var historyHelper = detailHelper.history(); + +var utils = require('../utils'); +var EC = protractor.ExpectedConditions; + +chai.use(chaiAsPromised); +var expect = chai.expect; + +var shared = module.exports; + +function selectEditorFirstChild(elm) { + browser.executeScript(function () { + var range = document.createRange(); + + range.setStart(arguments[0].firstChild.firstChild, 0); + range.setEnd(arguments[0].firstChild.firstChild, arguments[0].firstChild.innerText.length); + + var sel = window.getSelection(); + sel.removeAllRanges(); + sel.addRange(range); + }, elm.getWebElement()); + + browser.actions().mouseUp().perform(); //trigger medium events +} + +function resetSelection() { + browser.executeScript(function () { + var sel = window.getSelection(); + sel.removeAllRanges(); + }); + + browser.actions().mouseUp().perform(); //trigger medium events +} + +function getMarkdownText(elm) { + var markdownTextarea = getMarkdownTextarea(elm); + + return markdownTextarea.getAttribute("value"); +} + +function getMarkdownTextarea(elm) { + return elm.$('.e2e-markdown-textarea');} + + +function htmlMode(elm) { + elm.$('.e2e-html-mode').click(); + + return utils.common.waitElementPresent($('.e2e-markdown-mode')); +} + +function markdownMode(elm) { + elm.$('.e2e-markdown-mode').click(); + + return utils.common.waitElementPresent($('.e2e-html-mode')); +} + +function saveEdition(elm) { + return elm.$('.e2e-save-editor').click(); +} + +function cancelEdition(elm) { + elm.$('.e2e-cancel-editor').click(); + + return browser.wait(async () => { + return !!await elm.$$('.read-mode').count(); + }, 3000); +} + +function closeMention() { + return utils.common.waitElementNotPresent($('.medium-mention')); +} + +function preventThrottle() { + return browser.sleep(250); +} + +function getSnippeLightbox(parent) { + let el = parent.$('tg-wysiwyg-code-lightbox'); + + let obj = { + el: el, + waitOpen: function() { + return utils.lightbox.open(el); + }, + waitClose: function() { + return utils.lightbox.close(el); + }, + select: function(lan) { + return el.$('select').sendKeys('javascript'); + }, + save: function() { + return el.$('button').click(); + } + }; + + return obj; +}; + +async function edit(elm, elmWrapper, text = null) { + await browser.wait(EC.elementToBeClickable(elm), 10000); + + elm.click(); + + await browser.sleep(2000); + + if (text !== null) { + await cleanWysiwyg(elm, elmWrapper); + + return elm.sendKeys(text); + } +}; + +async function cleanWysiwyg(elm, elmWrapper) { + await browser.executeScript(function () { + if(arguments[0].firstChild) { + var range = document.createRange(); + range.setStart(arguments[0].firstChild, 0); + range.setEnd(arguments[0].lastChild, 0); + + var sel = window.getSelection(); + sel.removeAllRanges(); + sel.addRange(range); + } + }, elm.getWebElement()); + + return elm.sendKeys(protractor.Key.BACK_SPACE); +} + +shared.wysiwygTestingComments = function(parentSelector, section) { + var editor; + var editorWrapper; + + beforeEach(() => { + let parent = $(parentSelector); + editor = parent.$('.medium'); + editorWrapper = parent.$('tg-wysiwyg'); + }); + + it('bold, test normal behavior and check markdown', async () => { + let commentsCounter = await historyHelper.countComments(); + + await edit(editor, editorWrapper, "test"); + selectEditorFirstChild(editor); + + $('.medium-editor-toolbar-active .medium-editor-action-bold').click(); + + resetSelection(); + + markdownMode(editorWrapper); + + let markdown = await getMarkdownText(editorWrapper); + + expect(markdown).to.be.equal('**test**'); + + await htmlMode(editorWrapper); + + await saveEdition(editorWrapper); + + let newCommentsCounter = await historyHelper.countComments(); + expect(newCommentsCounter).to.be.equal(commentsCounter+1); + }); + + it('convert to html', async () => { + let commentsCounter = await historyHelper.countComments(); + + await edit(editor, editorWrapper, ''); + + markdownMode(editorWrapper); + + let markdownTextarea = getMarkdownTextarea(editorWrapper); + + await markdownTextarea.sendKeys('_test2_'); + + await htmlMode(editorWrapper); + + let html = await editor.getAttribute("innerHTML"); + + expect(html).to.be.eql('

    test2

    \n'); + + await saveEdition(editorWrapper); + + let newCommentsCounter = await historyHelper.countComments(); + expect(newCommentsCounter).to.be.equal(commentsCounter+1); + }); + + it('confirm exit when there is changes', async () => { + await edit(editor, editorWrapper, ''); + + editor.sendKeys('text text text'); + await preventThrottle(); + editor.sendKeys(protractor.Key.ESCAPE); + + await utils.lightbox.confirm.ok(); + + let isReadMode = !!await editorWrapper.$$('.read-mode').count(); + + expect(isReadMode).to.be.true; + + let html = await editor.getText(); + + expect(html).not.to.be.eql('text text text'); + }); + + it('keep changes on reload', async () => { + await edit(editor, editorWrapper, ''); + + editor.sendKeys('text text text'); + await preventThrottle(); + editor.sendKeys(protractor.Key.ESCAPE); + + browser.sleep(400); + browser.refresh(); + + let isReadMode = !!await editorWrapper.$$('.read-mode').count(); + + expect(isReadMode).to.be.false; + + let html = await editor.getText(); + + expect(html).to.be.eql('text text text'); + + await cancelEdition(editorWrapper); + }); + + it('mention user', async () => { + await edit(editor, editorWrapper, ''); + + editor.sendKeys('@user8'); + + $$('.medium-mention li').get(0).click(); + + let html = await editor.getAttribute("innerHTML"); + + expect(html).to.be.eql('

    @user8 

    '); + + markdownMode(editorWrapper); + + let markdown = await getMarkdownText(editorWrapper); + + expect(markdown).to.be.equal('[@user8](/profile/user8)'); + + await htmlMode(editorWrapper); + + await cancelEdition(editorWrapper); + }); + + it('emojis', async () => { + await edit(editor, editorWrapper, ''); + + editor.sendKeys(':smil'); + + $$('.medium-mention li').get(2).click(); + + let html = await editor.getAttribute("innerHTML"); + + expect(html).to.include('1f604.png'); + + markdownMode(editorWrapper); + + let markdown = await getMarkdownText(editorWrapper); + + expect(markdown).to.be.equal(':smile:'); + + await htmlMode(editorWrapper); + + await cancelEdition(editorWrapper); + }); + + it('cancel', async () => { + let prevHtml = await editor.getAttribute("innerHTML"); + + await edit(editor, editorWrapper, 'xxx yyy zzz'); + + await cancelEdition(editorWrapper); + + let html = await editor.getAttribute("innerHTML"); + + expect(html).to.be.equal(prevHtml); + }); + + it('edit comment', async () => { + historyHelper.editLastComment(); + + let editWrapperLast = historyHelper.getComments().last(); + let editLast = editWrapperLast.$('.medium'); + + await edit(editLast, editWrapperLast, "This is the new and updated text"); + await utils.common.takeScreenshot(section, "edit comment"); + + await saveEdition(editWrapperLast); + + //Show versions from last comment edited + historyHelper.showVersionsLastComment(); + await utils.common.takeScreenshot(section, "show comment versions"); + + historyHelper.closeVersionsLastComment(); + }); + + it('delete last comment', async () => { + let deletedCommentsCounter = await historyHelper.countDeletedComments(); + await historyHelper.deleteLastComment(); + + let newDeletedCommentsCounter = await historyHelper.countDeletedComments(); + + expect(newDeletedCommentsCounter).to.be.equal(deletedCommentsCounter+1); + + await utils.common.takeScreenshot(section, 'deleted comment'); + }); + + it('restore last comment', async () => { + let deletedCommentsCounter = await historyHelper.countDeletedComments(); + + await historyHelper.restoreLastComment(); + + let newDeletedCommentsCounter = await historyHelper.countDeletedComments(); + + expect(newDeletedCommentsCounter).to.be.equal(deletedCommentsCounter-1); + + await utils.common.takeScreenshot(section, 'restored comment'); + }); + + it('code block', async () => { + await edit(editor, editorWrapper, ''); + + editor.sendKeys("var test = 2;"); + + selectEditorFirstChild(editor); + + $('.medium-editor-toolbar-active .medium-editor-button-last').click(); + + browser.actions().doubleClick(editor.$('code')).perform(); + + let lb = getSnippeLightbox(editorWrapper); + + await lb.waitOpen(); + + await lb.select('javascript'); + await lb.save(); + await lb.waitClose(); + + let hasHightlighter = !!await editor.$$('.token').count(); + + expect(hasHightlighter).to.be.true; + + await saveEdition(editorWrapper); + }); +}; + +shared.wysiwygTesting = function(parentSelector) { + var editor; + var editorWrapper; + + beforeEach(async () => { + let isReadMode = !!await editorWrapper.$$('.read-mode').count(); + + if (isReadMode) { + editor.click(); + } + + let isHtmlMode = await editor.isDisplayed(); + if (!isHtmlMode) { + await htmlMode(editorWrapper); + } + + await cleanWysiwyg(editor, editorWrapper); + + markdownMode(editorWrapper); + + var markdownTextarea = getMarkdownTextarea(editorWrapper); + + browser.wait(EC.elementToBeClickable(markdownTextarea), 10000); + + await markdownTextarea.sendKeys('test'); + + await htmlMode(editorWrapper); + + await saveEdition(editorWrapper); + + await browser.wait(EC.elementToBeClickable(editor), 10000); + }); + + before(() => { + let parent = $(parentSelector); + editor = parent.$('.medium'); + editorWrapper = parent.$('tg-wysiwyg'); + }); + + it('bold, test normal behavior and check markdown', async () => { + await edit(editor, editorWrapper, "test"); + selectEditorFirstChild(editor); + + $('.medium-editor-toolbar-active .medium-editor-action-bold').click(); + + resetSelection(); + + let html = await editor.getAttribute("innerHTML"); + + expect(html).to.be.eql('

    test

    \n'); + + await saveEdition(editorWrapper); + + await edit(editor, editorWrapper); + + markdownMode(editorWrapper); + + let markdown = await getMarkdownText(editorWrapper); + + expect(markdown).to.be.equal('**test**'); + }); + + it('convert to html', async () => { + await edit(editor, editorWrapper, ''); + + markdownMode(editorWrapper); + + let markdownTextarea = getMarkdownTextarea(editorWrapper); + + await markdownTextarea.sendKeys('_test2_'); + + htmlMode(editorWrapper); + + let html = await editor.getAttribute("innerHTML"); + + expect(html).to.be.eql('

    test2

    \n'); + }); + + it('save with confirmconfirm exit when there is changes', async () => { + await edit(editor, editorWrapper, ''); + + editor.sendKeys('text text text'); + await preventThrottle(); + editor.sendKeys(protractor.Key.ESCAPE); + + await utils.lightbox.confirm.ok(); + + let isReadMode = !!await editorWrapper.$$('.read-mode').count(); + + expect(isReadMode).to.be.true; + + let html = await editor.getText(); + + expect(html).not.to.be.eql('text text text'); + }); + + it('keep changes on reload', async () => { + await edit(editor, editorWrapper, ''); + + editor.sendKeys('text text text'); + await preventThrottle(); + editor.sendKeys(protractor.Key.ESCAPE); + + browser.sleep(400); + browser.refresh(); + + let isReadMode = !!await editorWrapper.$$('.read-mode').count(); + + expect(isReadMode).to.be.false; + + let html = await editor.getText(); + + expect(html).to.be.eql('text text text'); + }); + + it('mention user', async () => { + await edit(editor, editorWrapper, ''); + + await editor.sendKeys('@user5'); + + $$('.medium-mention li').get(0).click(); + + await closeMention(); + + let html = await editor.getAttribute("innerHTML"); + + + expect(html).to.be.eql('

    @user5 

    \n'); + + markdownMode(editorWrapper); + + let markdown = await getMarkdownText(editorWrapper); + + expect(markdown).to.be.equal('[@user5](/profile/user5)'); + + htmlMode(editorWrapper); + }); + + it('emojis', async () => { + await edit(editor, editorWrapper, ''); + + editor.sendKeys(':smil'); + + await $$('.medium-mention li').get(2).click(); + + await closeMention(); + + let html = await editor.getAttribute("innerHTML"); + + expect(html).to.include('1f604.png'); + + markdownMode(editorWrapper); + + let markdown = await getMarkdownText(editorWrapper); + + expect(markdown).to.be.equal(':smile:'); + }); + + it('cancel', async () => { + let prevHtml = await editor.getAttribute("innerHTML"); + + await edit(editor, editorWrapper, 'xxx yyy zzz'); + + await cancelEdition(editorWrapper); + + let html = await editor.getAttribute("innerHTML"); + + expect(html).to.be.equal(prevHtml); + }); + + it('code block', async () => { + await edit(editor, editorWrapper, ''); + + editor.sendKeys("var test = 2;"); + + selectEditorFirstChild(editor); + + $('.medium-editor-toolbar-active .medium-editor-button-last').click(); + + browser.actions().doubleClick(editor.$('code')).perform(); + + let lb = getSnippeLightbox(editorWrapper); + + await lb.waitOpen(); + + await lb.select('javascript'); + await lb.save(); + await lb.waitClose(); + + await saveEdition(editorWrapper); + + let hasHightlighter = !!await editor.$$('.token').count(); + + expect(hasHightlighter).to.be.true; + }); +}; diff --git a/e2e/suites/admin/attributes/custom-fields.e2e.js b/e2e/suites/admin/attributes/custom-fields.e2e.js index aef42ac7..5a6b7470 100644 --- a/e2e/suites/admin/attributes/custom-fields.e2e.js +++ b/e2e/suites/admin/attributes/custom-fields.e2e.js @@ -18,21 +18,22 @@ describe('custom-fields', function() { describe('create custom fields', function() { describe('epics', function() { let typeIndex = 0; + let timestamp = new Date().getTime(); it('create', async function() { let oldCountCustomFields = await customFieldsHelper.getCustomFiledsByType(typeIndex).count(); - await customFieldsHelper.create(typeIndex, 'test1-text', 'desc1', 1); + await customFieldsHelper.create(typeIndex, 'test1-text'+timestamp, 'desc1', 1); // debounce :( await utils.notifications.success.open(); - await browser.sleep(2000); + await utils.notifications.success.close(); - await customFieldsHelper.create(typeIndex, 'test1-multi', 'desc1', 3); + await customFieldsHelper.create(typeIndex, 'test1-multi'+timestamp, 'desc1', 3); // debounce :( await utils.notifications.success.open(); - await browser.sleep(2000); + await utils.notifications.success.close(); let countCustomFields = await customFieldsHelper.getCustomFiledsByType(typeIndex).count(); @@ -40,7 +41,7 @@ describe('custom-fields', function() { }); it('edit', async function() { - customFieldsHelper.edit(typeIndex, 0, 'edit', 'desc2', 2); + customFieldsHelper.edit(typeIndex, 0, 'edit'+timestamp, 'desc2', 2); let open = await utils.notifications.success.open(); @@ -74,21 +75,22 @@ describe('custom-fields', function() { describe('userstories', function() { let typeIndex = 1; + let timestamp = new Date().getTime(); it('create', async function() { let oldCountCustomFields = await customFieldsHelper.getCustomFiledsByType(typeIndex).count(); - await customFieldsHelper.create(typeIndex, 'test1-text', 'desc1', 1); + await customFieldsHelper.create(typeIndex, 'test1-text'+timestamp, 'desc1', 1); // debounce :( await utils.notifications.success.open(); - await browser.sleep(2000); + await utils.notifications.success.close(); - await customFieldsHelper.create(typeIndex, 'test1-multi', 'desc1', 3); + await customFieldsHelper.create(typeIndex, 'test1-multi'+timestamp, 'desc1', 3); // debounce :( await utils.notifications.success.open(); - await browser.sleep(2000); + await utils.notifications.success.close(); let countCustomFields = await customFieldsHelper.getCustomFiledsByType(typeIndex).count(); @@ -96,7 +98,7 @@ describe('custom-fields', function() { }); it('edit', async function() { - await customFieldsHelper.edit(typeIndex, 0, 'edit', 'desc2', 1); + await customFieldsHelper.edit(typeIndex, 0, 'edit'+timestamp, 'desc2', 1); let open = await utils.notifications.success.open(); @@ -130,18 +132,19 @@ describe('custom-fields', function() { describe('tasks', function() { let typeIndex = 2; + let timestamp = new Date().getTime(); it('create', async function() { let oldCountCustomFields = await customFieldsHelper.getCustomFiledsByType(typeIndex).count(); - await customFieldsHelper.create(typeIndex, 'test1-text', 'desc1', 1); + await customFieldsHelper.create(typeIndex, 'test1-text'+timestamp, 'desc1', 1); // debounce :( await utils.notifications.success.open(); - await browser.sleep(2500); + await utils.notifications.success.close(); - await customFieldsHelper.create(typeIndex, 'test1-multi', 'desc1', 3); + await customFieldsHelper.create(typeIndex, 'test1-multi'+timestamp, 'desc1', 3); // debounce :( await utils.notifications.success.open(); - await browser.sleep(2500); + await utils.notifications.success.close(); let countCustomFields = await customFieldsHelper.getCustomFiledsByType(typeIndex).count(); @@ -149,7 +152,7 @@ describe('custom-fields', function() { }); it('edit', async function() { - customFieldsHelper.edit(typeIndex, 0, 'edit', 'desc2', 2); + customFieldsHelper.edit(typeIndex, 0, 'edit'+timestamp, 'desc2', 2); let open = await utils.notifications.success.open(); @@ -183,21 +186,22 @@ describe('custom-fields', function() { describe('issues', function() { let typeIndex = 3; + let timestamp = new Date().getTime(); it('create', async function() { let oldCountCustomFields = await customFieldsHelper.getCustomFiledsByType(typeIndex).count(); - await customFieldsHelper.create(typeIndex, 'test1-text', 'desc1', 1); + await customFieldsHelper.create(typeIndex, 'test1-text'+timestamp, 'desc1', 1); // debounce :( await utils.notifications.success.open(); - await browser.sleep(2000); + await utils.notifications.success.close(); - await customFieldsHelper.create(typeIndex, 'test1-multi', 'desc1', 3); + await customFieldsHelper.create(typeIndex, 'test1-multi'+timestamp, 'desc1', 3); // debounce :( await utils.notifications.success.open(); - await browser.sleep(2000); + await utils.notifications.success.close(); let countCustomFields = await customFieldsHelper.getCustomFiledsByType(typeIndex).count(); @@ -205,7 +209,7 @@ describe('custom-fields', function() { }); it('edit', async function() { - customFieldsHelper.edit(typeIndex, 0, 'edit', 'desc2', 2); + customFieldsHelper.edit(typeIndex, 0, 'edit'+timestamp, 'desc2', 2); let open = await utils.notifications.success.open(); diff --git a/e2e/suites/admin/members.e2e.js b/e2e/suites/admin/members.e2e.js index 5178b139..d01d8b75 100644 --- a/e2e/suites/admin/members.e2e.js +++ b/e2e/suites/admin/members.e2e.js @@ -28,25 +28,30 @@ describe('admin - members', function() { adminMembershipsHelper.openNewMemberLightbox(); await newMemberLightbox.waitOpen(); - utils.common.takeScreenshot('memberships', 'new-member'); + utils.common.takeScreenshot('memberships', 'add-new-member'); }); - it('add members row', async function() { + it('add contacts', async function() { + newMemberLightbox.addSuggested(0); + newMemberLightbox.addNew(); newMemberLightbox.newEmail('xxx' + new Date().getTime() + '@xx.es'); + newMemberLightbox.addNew(); newMemberLightbox.newEmail('xxx' + new Date().getTime() + '@xx.es'); - newMemberLightbox.newEmail('xxx' + new Date().getTime() + '@xx.es'); - - let membersRows = await newMemberLightbox.getRows().count(); - - expect(membersRows).to.be.equal(3 + 1); + utils.common.takeScreenshot('memberships', 'add-new-member-form'); }); it('delete members row', async function() { - newMemberLightbox.deleteRow(2); + newMemberLightbox.deleteInvited(2); - let membersRows = await newMemberLightbox.getRows().count(); + let invitedRows = await newMemberLightbox.getInviteds().count(); - expect(membersRows).to.be.equal(2 + 1); + expect(invitedRows).to.be.equal(2); + }); + + it('set roles', async function() { + newMemberLightbox.setRole(0); + newMemberLightbox.setRole(1); + utils.common.takeScreenshot('memberships', 'add-new-member-form-active'); }); it('submit', async function() { diff --git a/e2e/suites/admin/project/create-delete.e2e.js b/e2e/suites/admin/project/create-delete.e2e.js deleted file mode 100644 index 9e3041e2..00000000 --- a/e2e/suites/admin/project/create-delete.e2e.js +++ /dev/null @@ -1,67 +0,0 @@ -var utils = require('../../../utils'); -var createProject = require('../../../helpers').createProject; - -var chai = require('chai'); -var chaiAsPromised = require('chai-as-promised'); - -chai.use(chaiAsPromised); -var expect = chai.expect; - -describe('create-delete project', function() { - before(async function(){ - browser.get(browser.params.glob.host + 'projects/'); - - await utils.common.waitLoader(); - }); - - let lb; - - before(async function() { - lb = createProject.createProjectLightbox(); - - createProject.openWizard(); - - await lb.waitOpen(); - - utils.common.takeScreenshot('project-wizard', 'create-project'); - }); - - it('create project error', async function() { - utils.common.takeScreenshot('project-wizard', 'create-project-errors'); - - await lb.submit(); - - let errors = await lb.errors().count(); - - expect(errors).to.be.equal(2); - }); - - it('create project', async function() { - let originalUrl = await browser.getCurrentUrl(); - - lb.name().sendKeys('aaa'); - lb.description().sendKeys('bbb'); - - await lb.submit(); - - let projectUrl = await browser.getCurrentUrl(); - - expect(projectUrl).not.to.be.equal(originalUrl); - }); - - it('delete', async function() { - let linkAdmin = $('#nav-admin a'); - utils.common.link(linkAdmin); - - browser.wait(function() { - return $('.project-details').isPresent(); - }); - - await createProject.delete(); - await browser.waitForAngular(); - - let url = await browser.getCurrentUrl(); - - expect(url).to.be.equal(browser.params.glob.host); - }); -}); diff --git a/e2e/suites/admin/project/project-detail.e2e.js b/e2e/suites/admin/project/project-detail.e2e.js index 033015a4..2034f4d0 100644 --- a/e2e/suites/admin/project/project-detail.e2e.js +++ b/e2e/suites/admin/project/project-detail.e2e.js @@ -67,6 +67,21 @@ describe('project detail', function() { expect(utils.notifications.success.open()).to.be.eventually.equal(true); }); + it('receive feedback', async function() { + let checked = !! await adminHelper.receiveFeedback().getAttribute('checked'); + + if(!checked) { + adminHelper.togglereceiveFeedback(); + } + + $('button[type="submit"]').click(); + + checked = !! await adminHelper.receiveFeedback().getAttribute('checked'); + + expect(checked).to.be.true; + expect(utils.notifications.success.open()).to.be.eventually.equal(true); + }); + it('edit logo', async function() { let imageContainer = $('.image-container'); diff --git a/e2e/suites/auth/auth.e2e.js b/e2e/suites/auth/auth.e2e.js index ff4557c4..4345e5b1 100644 --- a/e2e/suites/auth/auth.e2e.js +++ b/e2e/suites/auth/auth.e2e.js @@ -47,7 +47,7 @@ describe('auth', function() { let url = await browser.getCurrentUrl(); - expect(url).to.be.equal(browser.params.glob.host + 'login?next=' + encodeURIComponent('/' + path)); + expect(url).to.be.equal(browser.params.glob.host + 'login?unauthorized&next=' + encodeURIComponent('/' + path)); }); it("login redirect to the previous one", async function() { diff --git a/e2e/suites/backlog.e2e.js b/e2e/suites/backlog.e2e.js index f847a4f2..515911e0 100644 --- a/e2e/suites/backlog.e2e.js +++ b/e2e/suites/backlog.e2e.js @@ -449,6 +449,43 @@ describe('backlog', function() { }); }); + describe('velocity forecasting', function() { + it('show', async function() { + browser.get(browser.params.glob.host + 'project/project-1/backlog'); + await utils.common.waitLoader(); + + let usCount = await backlogHelper.userStories().count(); + + await backlogHelper.openVelocityForecasting(); + utils.common.takeScreenshot('backlog', 'velocity-forecasting'); + + let newUsCount = await backlogHelper.userStories().count(); + + expect(newUsCount).is.below(usCount); + }); + it('create sprint from forecasting', async function() { + browser.get(browser.params.glob.host + 'project/project-1/backlog'); + await utils.common.waitLoader(); + + let sprintCount = await backlogHelper.sprintsOpen().count(); + + backlogHelper.openVelocityForecasting(); + backlogHelper.createSprintFromForecasting(); + + let newSprintCount = await backlogHelper.sprintsOpen().count(); + + expect(sprintCount).is.below(newSprintCount); + }); + it('hide forecasting if no velocity', async function() { + browser.get(browser.params.glob.host + 'project/project-5/backlog'); + await utils.common.waitLoader(); + + let forecasting = await backlogHelper.velocityForecasting(); + + expect(forecasting).to.be.empty; + }); + }); + describe('backlog filters', sharedFilters.bind(this, 'backlog', () => { return backlogHelper.userStories().count(); })); diff --git a/e2e/suites/create-project/duplicate.e2e.js b/e2e/suites/create-project/duplicate.e2e.js new file mode 100644 index 00000000..2ed3af95 --- /dev/null +++ b/e2e/suites/create-project/duplicate.e2e.js @@ -0,0 +1,64 @@ +var utils = require('../../utils'); +var createProjectHelper = require('../../helpers/create-project-helper'); +var newProjectScreen = createProjectHelper.newProjectScreen(); + +var chai = require('chai'); +var chaiAsPromised = require('chai-as-promised'); + +chai.use(chaiAsPromised); +var expect = chai.expect; + +describe('create-duplicate-delete project', function() { + + it('duplicate project', async function() { + browser.get(browser.params.glob.host + 'project/new'); + await utils.common.waitLoader(); + utils.common.takeScreenshot('new-project', 'new-project'); + await newProjectScreen.selectDuplicateOption(); + utils.common.takeScreenshot('new-project', 'duplicate-project'); + await newProjectScreen.selectProjectToDuplicate(); + let projectName = 'duplicated-project-' + Date.now(); + newProjectScreen.fillNameAndDescription(projectName, 'Lorem Ipsum') + await newProjectScreen.createProject(); + await browser.waitForAngular(); + let url = await browser.getCurrentUrl(); + expect(url).to.be.equal(browser.params.glob.host + 'project/admin-' + projectName + '/'); + }); + + it('create scrum project', async function() { + browser.get(browser.params.glob.host + 'project/new'); + await utils.common.waitLoader(); + await newProjectScreen.selectScrumOption(); + utils.common.takeScreenshot('new-project', 'create-scrum-project'); + let projectName = 'scrum-project-' + Date.now(); + await newProjectScreen.fillNameAndDescription(projectName, 'Lorem Ipsum'); + await newProjectScreen.createProject(); + let url = await browser.getCurrentUrl(); + expect(url).to.be.equal(browser.params.glob.host + 'project/admin-' + projectName + '/backlog'); + }); + + it('create kanban project', async function() { + browser.get(browser.params.glob.host + 'project/new'); + await utils.common.waitLoader(); + await newProjectScreen.selectKanbanOption(); + utils.common.takeScreenshot('new-project', 'create-kanban-project'); + let projectName = 'kanban-project-' + Date.now(); + await newProjectScreen.fillNameAndDescription(projectName, 'Lorem Ipsum'); + await newProjectScreen.createProject(); + let url = await browser.getCurrentUrl(); + expect(url).to.be.equal(browser.params.glob.host + 'project/admin-' + projectName + '/kanban'); + }); + + it('delete', async function() { + let linkAdmin = $('#nav-admin a'); + utils.common.link(linkAdmin); + browser.wait(function() { + return $('.project-details').isPresent(); + }); + await createProjectHelper.delete(); + await browser.waitForAngular(); + let url = await browser.getCurrentUrl(); + expect(url).to.be.equal(browser.params.glob.host); + }); + +}); diff --git a/e2e/suites/epics/epic-detail.e2e.js b/e2e/suites/epics/epic-detail.e2e.js index 66c5e34a..4db310b6 100644 --- a/e2e/suites/epics/epic-detail.e2e.js +++ b/e2e/suites/epics/epic-detail.e2e.js @@ -1,6 +1,9 @@ var utils = require('../../utils'); var sharedDetail = require('../../shared/detail'); var epicDetailHelper = require('../../helpers').epicDetail; +var wysiwyg = require('../../shared/wysiwyg'); +var sharedWysiwyg = wysiwyg.wysiwygTesting; +var sharedWysiwygComments = wysiwyg.wysiwygTestingComments; var chai = require('chai'); var chaiAsPromised = require('chai-as-promised'); @@ -39,7 +42,7 @@ describe('Epic detail', async function(){ it('tags edition', sharedDetail.tagsTesting); - describe('description', sharedDetail.descriptionTesting); + describe('description', sharedWysiwyg.bind(this, '.duty-content')); describe('related userstories', function() { let relatedUserstories = epicDetailHelper.relatedUserstories(); @@ -68,6 +71,8 @@ describe('Epic detail', async function(){ it('history', sharedDetail.historyTesting.bind(this, "epics")); + describe('comments epics', sharedWysiwygComments.bind(this, '.comments', 'epics')); + it('block', sharedDetail.blockTesting); describe('team requirement edition', sharedDetail.teamRequirementTesting); diff --git a/e2e/suites/home.e2e.js b/e2e/suites/home.e2e.js index 2f7a19ea..58186112 100644 --- a/e2e/suites/home.e2e.js +++ b/e2e/suites/home.e2e.js @@ -33,18 +33,6 @@ describe('home', function() { await utils.common.waitLoader(); utils.common.takeScreenshot("home", "projects"); }); - - it('open create project lightbox', async function() { - $('.master .create-project-btn').click(); - - return expect(await utils.lightbox.open('div[tg-lb-create-project]')).to.be.equal(true); - }); - - it('close create project lightbox', async function() { - $('div[tg-lb-create-project] .close').click(); - - return expect(await utils.lightbox.close('div[tg-lb-create-project]')).to.be.equal(true); - }); }); describe("project drag and drop", function() { @@ -72,7 +60,7 @@ describe('home', function() { }); it('projects menu has the new order', async function() { - var firstElementText = await $$('div[tg-dropdown-project-list] ul a span').first().getInnerHtml(); + var firstElementText = await $$('div[tg-dropdown-project-list] ul a span').first().getAttribute("innerHTML"); expect(firstElementText).to.be.equal(draggedElementText); }); diff --git a/e2e/suites/issues/issue-detail.e2e.js b/e2e/suites/issues/issue-detail.e2e.js index 352d6615..e76fb3da 100644 --- a/e2e/suites/issues/issue-detail.e2e.js +++ b/e2e/suites/issues/issue-detail.e2e.js @@ -1,5 +1,8 @@ var utils = require('../../utils'); var sharedDetail = require('../../shared/detail'); +var wysiwyg = require('../../shared/wysiwyg'); +var sharedWysiwyg = wysiwyg.wysiwygTesting; +var sharedWysiwygComments = wysiwyg.wysiwygTestingComments; var chai = require('chai'); var chaiAsPromised = require('chai-as-promised'); @@ -29,7 +32,7 @@ describe('Issue detail', async function(){ it('tags edition', sharedDetail.tagsTesting); - describe('description', sharedDetail.descriptionTesting); + describe('description', sharedWysiwyg.bind(this, '.duty-content')); it('status edition', sharedDetail.statusTesting.bind(this, 'In progress', 'Ready for test')); @@ -39,6 +42,8 @@ describe('Issue detail', async function(){ it('history', sharedDetail.historyTesting.bind(this, "issues")); + describe('comments issue', sharedWysiwygComments.bind(this, '.comments', 'issues')); + it('block', sharedDetail.blockTesting); it('attachments', sharedDetail.attachmentTesting); diff --git a/e2e/suites/issues/issues.e2e.js b/e2e/suites/issues/issues.e2e.js index 1ead1c3a..39b7bbf0 100644 --- a/e2e/suites/issues/issues.e2e.js +++ b/e2e/suites/issues/issues.e2e.js @@ -13,7 +13,7 @@ describe('issues list', function() { before(async function() { browser.get(browser.params.glob.host + 'project/project-3/issues'); - await utils.common.waitLoader(); + await browser.waitForAngular(); utils.common.takeScreenshot('issues', 'issues'); }); @@ -95,13 +95,10 @@ describe('issues list', function() { // test every column order for(let i = 0; i < 7; i++) { - let htmlChanges = await utils.common.outerHtmlChanges(table); issuesHelper.clickColumn(i); - await htmlChanges(); - - htmlChanges = await utils.common.outerHtmlChanges(table); + await browser.waitForAngular(); issuesHelper.clickColumn(i); - await htmlChanges(); + await browser.waitForAngular(); } }); diff --git a/e2e/suites/project-home.e2e.js b/e2e/suites/project-home.e2e.js index 087e3477..a6973587 100644 --- a/e2e/suites/project-home.e2e.js +++ b/e2e/suites/project-home.e2e.js @@ -14,7 +14,7 @@ describe('project home', function() { await utils.common.takeScreenshot("project", "home-like"); //reset - let link = $('tg-like-project-button a'); + let link = $('tg-like-project-button button'); let likeActive = await utils.common.hasClass(link, 'active'); if (!likeActive) { @@ -47,7 +47,7 @@ describe('project home', function() { }); */ it('unlike', async function() { - let link = $('tg-like-project-button a'); + let link = $('tg-like-project-button button'); let likesCounterOld = parseInt(await link.$('.track-button-counter').getText(), 10); link.click(); @@ -62,7 +62,7 @@ describe('project home', function() { }); it('like', async function() { - let link = $('tg-like-project-button a'); + let link = $('tg-like-project-button button'); let likesCounterOld = parseInt(await link.$('.track-button-counter').getText(), 10); link.click(); @@ -77,8 +77,24 @@ describe('project home', function() { expect(likesCounter).to.be.equal(likesCounterOld + 1); }); + it('contact project', async function() { + $('tg-contact-project-button > .e2e-contact-team').click(); + + let contactProjectLb = $('div[tg-lb-contact-project]'); + + await utils.lightbox.open(contactProjectLb); + await utils.common.takeScreenshot("project", "contact-form"); + + let form = $('.e2e-lightbox-contact-project'); + + await form.$('.e2e-lightbox-contact-project-message').sendKeys('contact'); + form.$('.e2e-lightbox-contact-project-button').click(); + await utils.notifications.success.open(); + await utils.notifications.success.close(); + }); + it('unwatch', async function() { - let link = $('tg-watch-project-button > a'); + let link = $('tg-watch-project-button > button'); let watchOptions = $('tg-watch-project-button .watch-options'); let watchCounterOld = parseInt(await link.$('.track-button-counter').getText(), 10); @@ -104,7 +120,7 @@ describe('project home', function() { }); it('watch', async function() { - let link = $('tg-watch-project-button > a'); + let link = $('tg-watch-project-button > button'); let watchOptions = $('tg-watch-project-button .watch-options'); let watchCounterOld = parseInt(await link.$('.track-button-counter').getText(), 10); diff --git a/e2e/suites/tasks/task-detail.e2e.js b/e2e/suites/tasks/task-detail.e2e.js index 10389c00..f5955513 100644 --- a/e2e/suites/tasks/task-detail.e2e.js +++ b/e2e/suites/tasks/task-detail.e2e.js @@ -1,6 +1,9 @@ var utils = require('../../utils'); var sharedDetail = require('../../shared/detail'); var taskDetailHelper = require('../../helpers').taskDetail; +var wysiwyg = require('../../shared/wysiwyg'); +var sharedWysiwyg = wysiwyg.wysiwygTesting; +var sharedWysiwygComments = wysiwyg.wysiwygTestingComments; var chai = require('chai'); var chaiAsPromised = require('chai-as-promised'); @@ -31,7 +34,7 @@ describe('Task detail', function(){ it('tags edition', sharedDetail.tagsTesting); - describe('description', sharedDetail.descriptionTesting); + describe('description', sharedWysiwyg.bind(this, '.duty-content')); it('status edition', sharedDetail.statusTesting.bind(this, 'In progress', 'Ready for test')); @@ -55,6 +58,8 @@ describe('Task detail', function(){ it('history', sharedDetail.historyTesting.bind(this, "tasks")); + describe('comments task', sharedWysiwygComments.bind(this, '.comments', 'tasks')); + it('block', sharedDetail.blockTesting); it('attachments', sharedDetail.attachmentTesting); diff --git a/e2e/suites/team.e2e.js b/e2e/suites/team.e2e.js index d147cac3..4a85fb0e 100644 --- a/e2e/suites/team.e2e.js +++ b/e2e/suites/team.e2e.js @@ -61,7 +61,7 @@ describe('team', function() { it('team filled', async function() { let total = await teamHelper.team().count(); - expect(total).to.be.equal(10); + expect(total).to.be.equal(9); }); it('search username', async function() { diff --git a/e2e/suites/transfer-project.e2e.js b/e2e/suites/transfer-project.e2e.js index 22b15d4b..c51e2395 100644 --- a/e2e/suites/transfer-project.e2e.js +++ b/e2e/suites/transfer-project.e2e.js @@ -8,8 +8,9 @@ chai.use(chaiAsPromised); var expect = chai.expect; describe('transfer project', () => { + let projectSlug = ''; before(async () => { - await utils.common.createProject(['user5@taigaio.demo']); + projectSlug = await utils.common.createProject(['user5@taigaio.demo']); await utils.nav .init() @@ -22,7 +23,7 @@ describe('transfer project', () => { await lb.waitOpen(); - lb.search('Alicia Flores'); + lb.search('Angela Perez'); lb.select(0); lb.addComment('text'); @@ -41,9 +42,9 @@ describe('transfer project', () => { }); it('reject', async () => { - let token = await utils.common.getTransferProjectToken('admin-aaa', 'user5'); + let token = await utils.common.getTransferProjectToken(projectSlug, 'user5'); - browser.get(browser.params.glob.host + 'project/admin-aaa/transfer/' + token); + browser.get(browser.params.glob.host + 'project/'+ projectSlug +'/transfer/' + token); await utils.common.waitLoader(); @@ -57,9 +58,9 @@ describe('transfer project', () => { }); it('accept', async () => { - let token = await utils.common.getTransferProjectToken('admin-aaa', 'user5'); + let token = await utils.common.getTransferProjectToken(projectSlug, 'user5'); - browser.get(browser.params.glob.host + 'project/admin-aaa/transfer/' + token); + browser.get(browser.params.glob.host + 'project/' + projectSlug + '/transfer/' + token); await utils.common.waitLoader(); @@ -78,9 +79,9 @@ describe('transfer project', () => { max_memberships_public_projects: 0 }); - let token = await utils.common.getTransferProjectToken('admin-aaa', 'user5'); + let token = await utils.common.getTransferProjectToken(projectSlug, 'user5'); - browser.get(browser.params.glob.host + 'project/admin-aaa/transfer/' + token); + browser.get(browser.params.glob.host + 'project/'+ projectSlug +'/transfer/' + token); await utils.common.waitLoader(); diff --git a/e2e/suites/user-profile/user-profile-likes.e2e.js b/e2e/suites/user-profile/user-profile-likes.e2e.js index 5f162ac0..0e3b75f0 100644 --- a/e2e/suites/user-profile/user-profile-likes.e2e.js +++ b/e2e/suites/user-profile/user-profile-likes.e2e.js @@ -16,7 +16,7 @@ describe('user profile - likes', function() { $$('.tab').get(1).click(); - await helper.waitLoader(); + await browser.waitForAngular(); utils.common.takeScreenshot('user-profile', 'current-user-likes'); }); diff --git a/e2e/suites/user-profile/user-profile-votes.e2e.js b/e2e/suites/user-profile/user-profile-votes.e2e.js index f1402e8b..b3df6cc7 100644 --- a/e2e/suites/user-profile/user-profile-votes.e2e.js +++ b/e2e/suites/user-profile/user-profile-votes.e2e.js @@ -41,49 +41,49 @@ describe('user profile - votes', function() { }); it('votes tab - filter epics', async function() { - let allItems = await $('div[infinite-scroll]').getInnerHtml(); + let allItems = await $('div[infinite-scroll]').getAttribute("innerHTML"); await $$('div.filters > a').get(1).click(); await browser.waitForAngular(); - let filteredItems = await $('div[infinite-scroll]').getInnerHtml(); + let filteredItems = await $('div[infinite-scroll]').getAttribute("innerHTML"); expect(allItems).to.be.not.equal(filteredItems); }); it('votes tab - filter user stories', async function() { - let allItems = await $('div[infinite-scroll]').getInnerHtml(); + let allItems = await $('div[infinite-scroll]').getAttribute("innerHTML"); await $$('div.filters > a').get(2).click(); await browser.waitForAngular(); - let filteredItems = await $('div[infinite-scroll]').getInnerHtml(); + let filteredItems = await $('div[infinite-scroll]').getAttribute("innerHTML"); expect(allItems).to.be.not.equal(filteredItems); }); it('votes tab - filter tasks', async function() { - let allItems = await $('div[infinite-scroll]').getInnerHtml(); + let allItems = await $('div[infinite-scroll]').getAttribute("innerHTML"); await $$('div.filters > a').get(3).click(); await browser.waitForAngular(); - let filteredItems = await $('div[infinite-scroll]').getInnerHtml(); + let filteredItems = await $('div[infinite-scroll]').getAttribute("innerHTML"); expect(allItems).to.be.not.equal(filteredItems); }); it('votes tab - filter issues', async function() { - let allItems = await $('div[infinite-scroll]').getInnerHtml(); + let allItems = await $('div[infinite-scroll]').getAttribute("innerHTML"); await $$('div.filters > a').get(4).click(); await browser.waitForAngular(); - let filteredItems = await $('div[infinite-scroll]').getInnerHtml(); + let filteredItems = await $('div[infinite-scroll]').getAttribute("innerHTML"); expect(allItems).to.be.not.equal(filteredItems); }); @@ -143,49 +143,49 @@ describe('user profile - votes', function() { }); it('votes tab - filter epics', async function() { - let allItems = await $('div[infinite-scroll]').getInnerHtml(); + let allItems = await $('div[infinite-scroll]').getAttribute("innerHTML"); await $$('div.filters > a').get(1).click(); await browser.waitForAngular(); - let filteredItems = await $('div[infinite-scroll]').getInnerHtml(); + let filteredItems = await $('div[infinite-scroll]').getAttribute("innerHTML"); expect(allItems).to.be.not.equal(filteredItems); }); it('votes tab - filter user stories', async function() { - let allItems = await $('div[infinite-scroll]').getInnerHtml(); + let allItems = await $('div[infinite-scroll]').getAttribute("innerHTML"); await $$('div.filters > a').get(2).click(); await browser.waitForAngular(); - let filteredItems = await $('div[infinite-scroll]').getInnerHtml(); + let filteredItems = await $('div[infinite-scroll]').getAttribute("innerHTML"); expect(allItems).to.be.not.equal(filteredItems); }); it('votes tab - filter tasks', async function() { - let allItems = await $('div[infinite-scroll]').getInnerHtml(); + let allItems = await $('div[infinite-scroll]').getAttribute("innerHTML"); await $$('div.filters > a').get(3).click(); await browser.waitForAngular(); - let filteredItems = await $('div[infinite-scroll]').getInnerHtml(); + let filteredItems = await $('div[infinite-scroll]').getAttribute("innerHTML"); expect(allItems).to.be.not.equal(filteredItems); }); it('votes tab - filter issues', async function() { - let allItems = await $('div[infinite-scroll]').getInnerHtml(); + let allItems = await $('div[infinite-scroll]').getAttribute("innerHTML"); await $$('div.filters > a').get(4).click(); await browser.waitForAngular(); - let filteredItems = await $('div[infinite-scroll]').getInnerHtml(); + let filteredItems = await $('div[infinite-scroll]').getAttribute("innerHTML"); expect(allItems).to.be.not.equal(filteredItems); }); @@ -205,9 +205,9 @@ describe('user profile - votes', function() { await utils.common.clear($('div.searchbox > input')); await htmlChanges(); - filteredItems = await $$('div[infinite-scroll] > div').count(); + let unfilteredItems = await $$('div[infinite-scroll] > div').count(); - expect(allItems).to.be.equal(filteredItems); + expect(unfilteredItems).to.be.not.equal(filteredItems); }); }); diff --git a/e2e/suites/user-profile/user-profile-watched.e2e.js b/e2e/suites/user-profile/user-profile-watched.e2e.js index df85a428..5de5b4bc 100644 --- a/e2e/suites/user-profile/user-profile-watched.e2e.js +++ b/e2e/suites/user-profile/user-profile-watched.e2e.js @@ -16,7 +16,7 @@ describe('user profile - watched', function() { $$('.tab').get(3).click(); - await helper.waitLoader(); + await browser.waitForAngular(); utils.common.takeScreenshot('user-profile', 'current-user-watched'); }); @@ -42,62 +42,62 @@ describe('user profile - watched', function() { }); it('watched tab - filter projects', async function() { - let allItems = await $('div[infinite-scroll]').getInnerHtml(); + let allItems = await $('div[infinite-scroll]').getAttribute("innerHTML"); await $$('div.filters > a').get(1).click(); await browser.waitForAngular(); - let filteredItems = await $('div[infinite-scroll]').getInnerHtml(); + let filteredItems = await $('div[infinite-scroll]').getAttribute("innerHTML"); expect(allItems).to.be.not.equal(filteredItems); }); it('watched tab - filter epics', async function() { - let allItems = await $('div[infinite-scroll]').getInnerHtml(); + let allItems = await $('div[infinite-scroll]').getAttribute("innerHTML"); await $$('div.filters > a').get(2).click(); await browser.waitForAngular(); - let filteredItems = await $('div[infinite-scroll]').getInnerHtml(); + let filteredItems = await $('div[infinite-scroll]').getAttribute("innerHTML"); expect(allItems).to.be.not.equal(filteredItems); }); it('watched tab - filter user stories', async function() { - let allItems = await $('div[infinite-scroll]').getInnerHtml(); + let allItems = await $('div[infinite-scroll]').getAttribute("innerHTML"); await $$('div.filters > a').get(3).click(); await browser.waitForAngular(); - let filteredItems = await $('div[infinite-scroll]').getInnerHtml(); + let filteredItems = await $('div[infinite-scroll]').getAttribute("innerHTML"); expect(allItems).to.be.not.equal(filteredItems); }); it('watched tab - filter tasks', async function() { - let allItems = await $('div[infinite-scroll]').getInnerHtml(); + let allItems = await $('div[infinite-scroll]').getAttribute("innerHTML"); await $$('div.filters > a').get(4).click(); await browser.waitForAngular(); - let filteredItems = await $('div[infinite-scroll]').getInnerHtml(); + let filteredItems = await $('div[infinite-scroll]').getAttribute("innerHTML"); expect(allItems).to.be.not.equal(filteredItems); }); it('watched tab - filter issues', async function() { - let allItems = await $('div[infinite-scroll]').getInnerHtml(); + let allItems = await $('div[infinite-scroll]').getAttribute("innerHTML"); await $$('div.filters > a').get(5).click(); await browser.waitForAngular(); - let filteredItems = await $('div[infinite-scroll]').getInnerHtml(); + let filteredItems = await $('div[infinite-scroll]').getAttribute("innerHTML"); expect(allItems).to.be.not.equal(filteredItems); }); @@ -157,61 +157,61 @@ describe('user profile - watched', function() { }); it('watched tab - filter projects', async function() { - let allItems = await $('div[infinite-scroll]').getInnerHtml(); + let allItems = await $('div[infinite-scroll]').getAttribute("innerHTML"); await $$('div.filters > a').get(1).click(); await browser.waitForAngular(); - let filteredItems = await $('div[infinite-scroll]').getInnerHtml(); + let filteredItems = await $('div[infinite-scroll]').getAttribute("innerHTML"); expect(allItems).to.be.not.equal(filteredItems); }); it('watched tab - filter epics', async function() { - let allItems = await $('div[infinite-scroll]').getInnerHtml(); + let allItems = await $('div[infinite-scroll]').getAttribute("innerHTML"); await $$('div.filters > a').get(2).click(); await browser.waitForAngular(); - let filteredItems = await $('div[infinite-scroll]').getInnerHtml(); + let filteredItems = await $('div[infinite-scroll]').getAttribute("innerHTML"); expect(allItems).to.be.not.equal(filteredItems); }); it('watched tab - filter user stories', async function() { - let allItems = await $('div[infinite-scroll]').getInnerHtml(); + let allItems = await $('div[infinite-scroll]').getAttribute("innerHTML"); await $$('div.filters > a').get(3).click(); await browser.waitForAngular(); - let filteredItems = await $('div[infinite-scroll]').getInnerHtml(); + let filteredItems = await $('div[infinite-scroll]').getAttribute("innerHTML"); expect(allItems).to.be.not.equal(filteredItems); }); it('watched tab - filter tasks', async function() { - let allItems = await $('div[infinite-scroll]').getInnerHtml(); + let allItems = await $('div[infinite-scroll]').getAttribute("innerHTML"); await $$('div.filters > a').get(4).click(); await browser.waitForAngular(); - let filteredItems = await $('div[infinite-scroll]').getInnerHtml(); + let filteredItems = await $('div[infinite-scroll]').getAttribute("innerHTML"); expect(allItems).to.be.not.equal(filteredItems); }); it('watched tab - filter issues', async function() { - let allItems = await $('div[infinite-scroll]').getInnerHtml(); + let allItems = await $('div[infinite-scroll]').getAttribute("innerHTML"); await $$('div.filters > a').get(5).click(); await browser.waitForAngular(); - let filteredItems = await $('div[infinite-scroll]').getInnerHtml(); + let filteredItems = await $('div[infinite-scroll]').getAttribute("innerHTML"); expect(allItems).to.be.not.equal(filteredItems); }); diff --git a/e2e/suites/user-stories/user-story-detail.e2e.js b/e2e/suites/user-stories/user-story-detail.e2e.js index 1a7d28af..a280e2d9 100644 --- a/e2e/suites/user-stories/user-story-detail.e2e.js +++ b/e2e/suites/user-stories/user-story-detail.e2e.js @@ -1,6 +1,9 @@ var utils = require('../../utils'); var sharedDetail = require('../../shared/detail'); var usDetailHelper = require('../../helpers').usDetail; +var wysiwyg = require('../../shared/wysiwyg'); +var sharedWysiwyg = wysiwyg.wysiwygTesting; +var sharedWysiwygComments = wysiwyg.wysiwygTestingComments; var chai = require('chai'); var chaiAsPromised = require('chai-as-promised'); @@ -30,7 +33,7 @@ describe('User story detail', function(){ it('tags edition', sharedDetail.tagsTesting); - describe('description', sharedDetail.descriptionTesting); + describe('description', sharedWysiwyg.bind(this, '.duty-content')); it('status edition', sharedDetail.statusTesting.bind(this, 'Ready', 'In progress')); @@ -44,6 +47,8 @@ describe('User story detail', function(){ it('history', sharedDetail.historyTesting.bind(this, "user-stories")); + describe('comments us', sharedWysiwygComments.bind(this, '.comments', 'issues')); + it('block', sharedDetail.blockTesting); it('attachments', sharedDetail.attachmentTesting); diff --git a/e2e/suites/wiki.e2e.js b/e2e/suites/wiki.e2e.js index 4f9b6e48..255d8356 100644 --- a/e2e/suites/wiki.e2e.js +++ b/e2e/suites/wiki.e2e.js @@ -1,6 +1,7 @@ var utils = require('../utils'); var sharedDetail = require('../shared/detail'); var wikiHelper = require('../helpers').wiki; +var sharedWysiwyg = require('../shared/wysiwyg').wysiwygTesting; var chai = require('chai'); var chaiAsPromised = require('chai-as-promised'); @@ -64,52 +65,7 @@ describe('wiki', function() { await utils.common.takeScreenshot("wiki", "deleting-the-created-link"); }); - it('edition', async function() { - let timesEdited = wikiHelper.editor().getTimesEdited(); - let lastEditionDatetime = wikiHelper.editor().getLastEditionDateTime(); - wikiHelper.editor().enabledEditionMode(); - let settingText = "This is the new text" + new Date().getTime(); - wikiHelper.editor().setText(settingText); - - //preview - wikiHelper.editor().preview(); - await utils.common.takeScreenshot("wiki", "home-edition-preview"); - wikiHelper.editor().closePreview(); - - //save - wikiHelper.editor().save(); - let newHtml = await wikiHelper.editor().getInnerHtml(); - let newTimesEdited = wikiHelper.editor().getTimesEdited(); - let newLastEditionDatetime = wikiHelper.editor().getLastEditionDateTime(); - - expect(newHtml).to.be.equal("

    " + settingText + "

    "); - expect(newTimesEdited).to.be.eventually.equal(timesEdited+1); - expect(newLastEditionDatetime).to.be.not.equal(lastEditionDatetime); - - await utils.common.takeScreenshot("wiki", "home-edition"); - }); - - it('confirm close with ESC in lightbox', async function() { - wikiHelper.editor().enabledEditionMode(); - - browser.actions().sendKeys(protractor.Key.ESCAPE).perform(); - - await utils.lightbox.confirm.cancel(); - - let descriptionVisibility = await $('.view-wiki-content').isDisplayed(); - - expect(descriptionVisibility).to.be.false; - - wikiHelper.editor().focus(); - - browser.actions().sendKeys(protractor.Key.ESCAPE).perform(); - - await utils.lightbox.confirm.ok(); - - descriptionVisibility = await $('.view-wiki-content').isDisplayed(); - - expect(descriptionVisibility).to.be.true; - }); + describe('wiki editor', sharedWysiwyg.bind(this, '.wiki')); it('attachments', sharedDetail.attachmentTesting); @@ -118,28 +74,4 @@ describe('wiki', function() { expect(browser.getCurrentUrl()).to.be.eventually.equal(browser.params.glob.host + 'project/project-0/wiki/home'); }); - - it('Custom keyboard actions', async function(){ - wikiHelper.editor().enabledEditionMode(); - - wikiHelper.editor().setText("- aa"); - browser.actions().sendKeys(protractor.Key.ENTER).perform(); - let text = await wikiHelper.editor().getText(); - expect(text).to.be.equal("- aa\n- "); - - wikiHelper.editor().setText("- "); - browser.actions().sendKeys(protractor.Key.ENTER).perform(); - text = await wikiHelper.editor().getText(); - expect(text).to.be.equal("\n"); - - wikiHelper.editor().setText("- bbcc"); - browser.actions().sendKeys(protractor.Key.ARROW_LEFT).sendKeys(protractor.Key.ARROW_LEFT).sendKeys(protractor.Key.ENTER).perform(); - text = await wikiHelper.editor().getText(); - expect(text).to.be.equal("- bb\n- cc"); - - wikiHelper.editor().setText("- aa"); - browser.actions().sendKeys(protractor.Key.HOME).sendKeys(protractor.Key.ENTER).perform(); - text = await wikiHelper.editor().getText(); - expect(text).to.be.equal("\n- aa"); - }); }); diff --git a/e2e/utils/common.js b/e2e/utils/common.js index d3a3c4dc..6d59c6ec 100644 --- a/e2e/utils/common.js +++ b/e2e/utils/common.js @@ -20,6 +20,20 @@ common.getElm = function(el) { return deferred.promise; }; +common.waitElementNotPresent = function(el) { + return browser.wait(function() { + return el.isPresent().then(function(present) { + return !present; + }); + }); +}; + +common.waitElementPresent = function(el) { + return browser.wait(function() { + return el.isPresent(); + }); +}; + common.hasClass = async function (element, cls) { let classes = await element.getAttribute('class'); @@ -328,11 +342,11 @@ common.outerHtmlChanges = async function(el='body') { el = $(el); } - let html = await el.getOuterHtml(); + let html = await el.getAttribute('outerHTML'); return function() { return browser.wait(async function() { - let newhtml = await el.getOuterHtml(); + let newhtml = await el.getAttribute('outerHTML'); return html !== newhtml; }, 5000).then(function() { @@ -346,11 +360,11 @@ common.innerHtmlChanges = async function(el='body') { el = $(el); } - let html = await el.getInnerHtml(); + let html = await el.getAttribute('innerHTML'); return function() { return browser.wait(async function() { - let newhtml = await el.getOuterHtml(); + let newhtml = await el.getAttribute('outerHTML'); return html !== newhtml; }, 5000).then(function() { @@ -481,23 +495,18 @@ common.closeJoyride = async function() { }; common.createProject = async function(members = []) { - var createProject = require('../helpers').createProject; - var notifications = require('./notifications'); + var createProjectHelper = require('../helpers/create-project-helper'); + var newProjectScreen = createProjectHelper.newProjectScreen(); - browser.get(browser.params.glob.host + 'projects/'); + browser.get(browser.params.glob.host + 'project/new'); await common.waitLoader(); - - let lb = createProject.createProjectLightbox(); - - createProject.openWizard(); - - await lb.waitOpen(); - - lb.name().sendKeys('aaa'); - - lb.description().sendKeys('bbb'); - - await lb.submit(); + await newProjectScreen.selectScrumOption(); + let projectName = 'name ' + Date.now(); + let projectDescription = 'description ' + Date.now(); + await newProjectScreen.fillNameAndDescription(projectName, projectDescription); + await newProjectScreen.createProject(); + let projectUrl = await browser.getCurrentUrl() + let projectSlug = projectUrl.split('/')[4]; if (members.length) { var adminMembershipsHelper = require('../helpers').adminMemberships; @@ -516,12 +525,14 @@ common.createProject = async function(members = []) { for(var i = 0; i < members.length; i++) { newMemberLightbox.newEmail(members[i]); + newMemberLightbox.setRole(0); } newMemberLightbox.submit(); await newMemberLightbox.waitClose(); } + return projectSlug; }; common.getTransferProjectToken = function(projectSlug, username) { diff --git a/emojis/0023-20e3.png b/emojis/0023-20e3.png new file mode 100644 index 00000000..66e39204 Binary files /dev/null and b/emojis/0023-20e3.png differ diff --git a/emojis/002a-20e3.png b/emojis/002a-20e3.png new file mode 100644 index 00000000..200b3565 Binary files /dev/null and b/emojis/002a-20e3.png differ diff --git a/emojis/0030-20e3.png b/emojis/0030-20e3.png new file mode 100644 index 00000000..ecd15380 Binary files /dev/null and b/emojis/0030-20e3.png differ diff --git a/emojis/0031-20e3.png b/emojis/0031-20e3.png new file mode 100644 index 00000000..3d2c5ffa Binary files /dev/null and b/emojis/0031-20e3.png differ diff --git a/emojis/0032-20e3.png b/emojis/0032-20e3.png new file mode 100644 index 00000000..60191741 Binary files /dev/null and b/emojis/0032-20e3.png differ diff --git a/emojis/0033-20e3.png b/emojis/0033-20e3.png new file mode 100644 index 00000000..f9f679c9 Binary files /dev/null and b/emojis/0033-20e3.png differ diff --git a/emojis/0034-20e3.png b/emojis/0034-20e3.png new file mode 100644 index 00000000..f01e704c Binary files /dev/null and b/emojis/0034-20e3.png differ diff --git a/emojis/0035-20e3.png b/emojis/0035-20e3.png new file mode 100644 index 00000000..f385a072 Binary files /dev/null and b/emojis/0035-20e3.png differ diff --git a/emojis/0036-20e3.png b/emojis/0036-20e3.png new file mode 100644 index 00000000..d370688d Binary files /dev/null and b/emojis/0036-20e3.png differ diff --git a/emojis/0037-20e3.png b/emojis/0037-20e3.png new file mode 100644 index 00000000..aec7df37 Binary files /dev/null and b/emojis/0037-20e3.png differ diff --git a/emojis/0038-20e3.png b/emojis/0038-20e3.png new file mode 100644 index 00000000..a2379d79 Binary files /dev/null and b/emojis/0038-20e3.png differ diff --git a/emojis/0039-20e3.png b/emojis/0039-20e3.png new file mode 100644 index 00000000..e718c0e7 Binary files /dev/null and b/emojis/0039-20e3.png differ diff --git a/emojis/1f004.png b/emojis/1f004.png new file mode 100644 index 00000000..04348650 Binary files /dev/null and b/emojis/1f004.png differ diff --git a/emojis/1f0cf.png b/emojis/1f0cf.png new file mode 100644 index 00000000..683141f3 Binary files /dev/null and b/emojis/1f0cf.png differ diff --git a/emojis/1f170.png b/emojis/1f170.png new file mode 100644 index 00000000..f3b77292 Binary files /dev/null and b/emojis/1f170.png differ diff --git a/emojis/1f171.png b/emojis/1f171.png new file mode 100644 index 00000000..aac0ecd1 Binary files /dev/null and b/emojis/1f171.png differ diff --git a/emojis/1f17e.png b/emojis/1f17e.png new file mode 100644 index 00000000..5b594b5f Binary files /dev/null and b/emojis/1f17e.png differ diff --git a/emojis/1f17f.png b/emojis/1f17f.png new file mode 100644 index 00000000..272caa47 Binary files /dev/null and b/emojis/1f17f.png differ diff --git a/emojis/1f18e.png b/emojis/1f18e.png new file mode 100644 index 00000000..1fb4aa22 Binary files /dev/null and b/emojis/1f18e.png differ diff --git a/emojis/1f191.png b/emojis/1f191.png new file mode 100644 index 00000000..dcd1c68b Binary files /dev/null and b/emojis/1f191.png differ diff --git a/emojis/1f192.png b/emojis/1f192.png new file mode 100644 index 00000000..267ff9e5 Binary files /dev/null and b/emojis/1f192.png differ diff --git a/emojis/1f193.png b/emojis/1f193.png new file mode 100644 index 00000000..db0d1f22 Binary files /dev/null and b/emojis/1f193.png differ diff --git a/emojis/1f194.png b/emojis/1f194.png new file mode 100644 index 00000000..ac05e00d Binary files /dev/null and b/emojis/1f194.png differ diff --git a/emojis/1f195.png b/emojis/1f195.png new file mode 100644 index 00000000..5adfbcf0 Binary files /dev/null and b/emojis/1f195.png differ diff --git a/emojis/1f196.png b/emojis/1f196.png new file mode 100644 index 00000000..260e8c47 Binary files /dev/null and b/emojis/1f196.png differ diff --git a/emojis/1f197.png b/emojis/1f197.png new file mode 100644 index 00000000..becc64cc Binary files /dev/null and b/emojis/1f197.png differ diff --git a/emojis/1f198.png b/emojis/1f198.png new file mode 100644 index 00000000..e35fefd2 Binary files /dev/null and b/emojis/1f198.png differ diff --git a/emojis/1f199.png b/emojis/1f199.png new file mode 100644 index 00000000..a4e63b1e Binary files /dev/null and b/emojis/1f199.png differ diff --git a/emojis/1f19a.png b/emojis/1f19a.png new file mode 100644 index 00000000..51c077d7 Binary files /dev/null and b/emojis/1f19a.png differ diff --git a/emojis/1f1e6-1f1e8.png b/emojis/1f1e6-1f1e8.png new file mode 100644 index 00000000..6e6e3caf Binary files /dev/null and b/emojis/1f1e6-1f1e8.png differ diff --git a/emojis/1f1e6-1f1e9.png b/emojis/1f1e6-1f1e9.png new file mode 100644 index 00000000..76ea6e0a Binary files /dev/null and b/emojis/1f1e6-1f1e9.png differ diff --git a/emojis/1f1e6-1f1ea.png b/emojis/1f1e6-1f1ea.png new file mode 100644 index 00000000..0e0c9da0 Binary files /dev/null and b/emojis/1f1e6-1f1ea.png differ diff --git a/emojis/1f1e6-1f1eb.png b/emojis/1f1e6-1f1eb.png new file mode 100644 index 00000000..f478d275 Binary files /dev/null and b/emojis/1f1e6-1f1eb.png differ diff --git a/emojis/1f1e6-1f1ec.png b/emojis/1f1e6-1f1ec.png new file mode 100644 index 00000000..1be16c60 Binary files /dev/null and b/emojis/1f1e6-1f1ec.png differ diff --git a/emojis/1f1e6-1f1ee.png b/emojis/1f1e6-1f1ee.png new file mode 100644 index 00000000..065229e1 Binary files /dev/null and b/emojis/1f1e6-1f1ee.png differ diff --git a/emojis/1f1e6-1f1f1.png b/emojis/1f1e6-1f1f1.png new file mode 100644 index 00000000..a9eefd05 Binary files /dev/null and b/emojis/1f1e6-1f1f1.png differ diff --git a/emojis/1f1e6-1f1f2.png b/emojis/1f1e6-1f1f2.png new file mode 100644 index 00000000..0bb112b9 Binary files /dev/null and b/emojis/1f1e6-1f1f2.png differ diff --git a/emojis/1f1e6-1f1f4.png b/emojis/1f1e6-1f1f4.png new file mode 100644 index 00000000..9a928da3 Binary files /dev/null and b/emojis/1f1e6-1f1f4.png differ diff --git a/emojis/1f1e6-1f1f6.png b/emojis/1f1e6-1f1f6.png new file mode 100644 index 00000000..c2b3f928 Binary files /dev/null and b/emojis/1f1e6-1f1f6.png differ diff --git a/emojis/1f1e6-1f1f7.png b/emojis/1f1e6-1f1f7.png new file mode 100644 index 00000000..3a98a614 Binary files /dev/null and b/emojis/1f1e6-1f1f7.png differ diff --git a/emojis/1f1e6-1f1f8.png b/emojis/1f1e6-1f1f8.png new file mode 100644 index 00000000..461dd422 Binary files /dev/null and b/emojis/1f1e6-1f1f8.png differ diff --git a/emojis/1f1e6-1f1f9.png b/emojis/1f1e6-1f1f9.png new file mode 100644 index 00000000..eaee0df4 Binary files /dev/null and b/emojis/1f1e6-1f1f9.png differ diff --git a/emojis/1f1e6-1f1fa.png b/emojis/1f1e6-1f1fa.png new file mode 100644 index 00000000..686b2438 Binary files /dev/null and b/emojis/1f1e6-1f1fa.png differ diff --git a/emojis/1f1e6-1f1fc.png b/emojis/1f1e6-1f1fc.png new file mode 100644 index 00000000..241589fc Binary files /dev/null and b/emojis/1f1e6-1f1fc.png differ diff --git a/emojis/1f1e6-1f1fd.png b/emojis/1f1e6-1f1fd.png new file mode 100644 index 00000000..220a61bf Binary files /dev/null and b/emojis/1f1e6-1f1fd.png differ diff --git a/emojis/1f1e6-1f1ff.png b/emojis/1f1e6-1f1ff.png new file mode 100644 index 00000000..6246b5db Binary files /dev/null and b/emojis/1f1e6-1f1ff.png differ diff --git a/emojis/1f1e7-1f1e6.png b/emojis/1f1e7-1f1e6.png new file mode 100644 index 00000000..04bf6084 Binary files /dev/null and b/emojis/1f1e7-1f1e6.png differ diff --git a/emojis/1f1e7-1f1e7.png b/emojis/1f1e7-1f1e7.png new file mode 100644 index 00000000..71727feb Binary files /dev/null and b/emojis/1f1e7-1f1e7.png differ diff --git a/emojis/1f1e7-1f1e9.png b/emojis/1f1e7-1f1e9.png new file mode 100644 index 00000000..f18a7e0b Binary files /dev/null and b/emojis/1f1e7-1f1e9.png differ diff --git a/emojis/1f1e7-1f1ea.png b/emojis/1f1e7-1f1ea.png new file mode 100644 index 00000000..bebd1108 Binary files /dev/null and b/emojis/1f1e7-1f1ea.png differ diff --git a/emojis/1f1e7-1f1eb.png b/emojis/1f1e7-1f1eb.png new file mode 100644 index 00000000..7da4ae86 Binary files /dev/null and b/emojis/1f1e7-1f1eb.png differ diff --git a/emojis/1f1e7-1f1ec.png b/emojis/1f1e7-1f1ec.png new file mode 100644 index 00000000..f62a1645 Binary files /dev/null and b/emojis/1f1e7-1f1ec.png differ diff --git a/emojis/1f1e7-1f1ed.png b/emojis/1f1e7-1f1ed.png new file mode 100644 index 00000000..a2e0c648 Binary files /dev/null and b/emojis/1f1e7-1f1ed.png differ diff --git a/emojis/1f1e7-1f1ee.png b/emojis/1f1e7-1f1ee.png new file mode 100644 index 00000000..67e878cb Binary files /dev/null and b/emojis/1f1e7-1f1ee.png differ diff --git a/emojis/1f1e7-1f1ef.png b/emojis/1f1e7-1f1ef.png new file mode 100644 index 00000000..d8021a04 Binary files /dev/null and b/emojis/1f1e7-1f1ef.png differ diff --git a/emojis/1f1e7-1f1f1.png b/emojis/1f1e7-1f1f1.png new file mode 100644 index 00000000..044ab7d7 Binary files /dev/null and b/emojis/1f1e7-1f1f1.png differ diff --git a/emojis/1f1e7-1f1f2.png b/emojis/1f1e7-1f1f2.png new file mode 100644 index 00000000..3e71c787 Binary files /dev/null and b/emojis/1f1e7-1f1f2.png differ diff --git a/emojis/1f1e7-1f1f3.png b/emojis/1f1e7-1f1f3.png new file mode 100644 index 00000000..1b121dad Binary files /dev/null and b/emojis/1f1e7-1f1f3.png differ diff --git a/emojis/1f1e7-1f1f4.png b/emojis/1f1e7-1f1f4.png new file mode 100644 index 00000000..b7fd1678 Binary files /dev/null and b/emojis/1f1e7-1f1f4.png differ diff --git a/emojis/1f1e7-1f1f6.png b/emojis/1f1e7-1f1f6.png new file mode 100644 index 00000000..ee4187ff Binary files /dev/null and b/emojis/1f1e7-1f1f6.png differ diff --git a/emojis/1f1e7-1f1f7.png b/emojis/1f1e7-1f1f7.png new file mode 100644 index 00000000..a48615e3 Binary files /dev/null and b/emojis/1f1e7-1f1f7.png differ diff --git a/emojis/1f1e7-1f1f8.png b/emojis/1f1e7-1f1f8.png new file mode 100644 index 00000000..7085f732 Binary files /dev/null and b/emojis/1f1e7-1f1f8.png differ diff --git a/emojis/1f1e7-1f1f9.png b/emojis/1f1e7-1f1f9.png new file mode 100644 index 00000000..a13a1b99 Binary files /dev/null and b/emojis/1f1e7-1f1f9.png differ diff --git a/emojis/1f1e7-1f1fb.png b/emojis/1f1e7-1f1fb.png new file mode 100644 index 00000000..62329ed1 Binary files /dev/null and b/emojis/1f1e7-1f1fb.png differ diff --git a/emojis/1f1e7-1f1fc.png b/emojis/1f1e7-1f1fc.png new file mode 100644 index 00000000..9eab7c24 Binary files /dev/null and b/emojis/1f1e7-1f1fc.png differ diff --git a/emojis/1f1e7-1f1fe.png b/emojis/1f1e7-1f1fe.png new file mode 100644 index 00000000..6ee3c78e Binary files /dev/null and b/emojis/1f1e7-1f1fe.png differ diff --git a/emojis/1f1e7-1f1ff.png b/emojis/1f1e7-1f1ff.png new file mode 100644 index 00000000..80c3a266 Binary files /dev/null and b/emojis/1f1e7-1f1ff.png differ diff --git a/emojis/1f1e8-1f1e6.png b/emojis/1f1e8-1f1e6.png new file mode 100644 index 00000000..7d2b2674 Binary files /dev/null and b/emojis/1f1e8-1f1e6.png differ diff --git a/emojis/1f1e8-1f1e8.png b/emojis/1f1e8-1f1e8.png new file mode 100644 index 00000000..08ea22b0 Binary files /dev/null and b/emojis/1f1e8-1f1e8.png differ diff --git a/emojis/1f1e8-1f1e9.png b/emojis/1f1e8-1f1e9.png new file mode 100644 index 00000000..9dc9b176 Binary files /dev/null and b/emojis/1f1e8-1f1e9.png differ diff --git a/emojis/1f1e8-1f1eb.png b/emojis/1f1e8-1f1eb.png new file mode 100644 index 00000000..6d2e94dd Binary files /dev/null and b/emojis/1f1e8-1f1eb.png differ diff --git a/emojis/1f1e8-1f1ec.png b/emojis/1f1e8-1f1ec.png new file mode 100644 index 00000000..eefd21d0 Binary files /dev/null and b/emojis/1f1e8-1f1ec.png differ diff --git a/emojis/1f1e8-1f1ed.png b/emojis/1f1e8-1f1ed.png new file mode 100644 index 00000000..e8b408b9 Binary files /dev/null and b/emojis/1f1e8-1f1ed.png differ diff --git a/emojis/1f1e8-1f1ee.png b/emojis/1f1e8-1f1ee.png new file mode 100644 index 00000000..95554703 Binary files /dev/null and b/emojis/1f1e8-1f1ee.png differ diff --git a/emojis/1f1e8-1f1f0.png b/emojis/1f1e8-1f1f0.png new file mode 100644 index 00000000..9cb9f284 Binary files /dev/null and b/emojis/1f1e8-1f1f0.png differ diff --git a/emojis/1f1e8-1f1f1.png b/emojis/1f1e8-1f1f1.png new file mode 100644 index 00000000..8654b217 Binary files /dev/null and b/emojis/1f1e8-1f1f1.png differ diff --git a/emojis/1f1e8-1f1f2.png b/emojis/1f1e8-1f1f2.png new file mode 100644 index 00000000..5c6a9fbe Binary files /dev/null and b/emojis/1f1e8-1f1f2.png differ diff --git a/emojis/1f1e8-1f1f3.png b/emojis/1f1e8-1f1f3.png new file mode 100644 index 00000000..ecbf96cb Binary files /dev/null and b/emojis/1f1e8-1f1f3.png differ diff --git a/emojis/1f1e8-1f1f4.png b/emojis/1f1e8-1f1f4.png new file mode 100644 index 00000000..12b67862 Binary files /dev/null and b/emojis/1f1e8-1f1f4.png differ diff --git a/emojis/1f1e8-1f1f5.png b/emojis/1f1e8-1f1f5.png new file mode 100644 index 00000000..49d3cee3 Binary files /dev/null and b/emojis/1f1e8-1f1f5.png differ diff --git a/emojis/1f1e8-1f1f7.png b/emojis/1f1e8-1f1f7.png new file mode 100644 index 00000000..ff8bf345 Binary files /dev/null and b/emojis/1f1e8-1f1f7.png differ diff --git a/emojis/1f1e8-1f1fa.png b/emojis/1f1e8-1f1fa.png new file mode 100644 index 00000000..e210dad6 Binary files /dev/null and b/emojis/1f1e8-1f1fa.png differ diff --git a/emojis/1f1e8-1f1fb.png b/emojis/1f1e8-1f1fb.png new file mode 100644 index 00000000..4bc4815f Binary files /dev/null and b/emojis/1f1e8-1f1fb.png differ diff --git a/emojis/1f1e8-1f1fc.png b/emojis/1f1e8-1f1fc.png new file mode 100644 index 00000000..e8b91be3 Binary files /dev/null and b/emojis/1f1e8-1f1fc.png differ diff --git a/emojis/1f1e8-1f1fd.png b/emojis/1f1e8-1f1fd.png new file mode 100644 index 00000000..1b521a6e Binary files /dev/null and b/emojis/1f1e8-1f1fd.png differ diff --git a/emojis/1f1e8-1f1fe.png b/emojis/1f1e8-1f1fe.png new file mode 100644 index 00000000..baef68b9 Binary files /dev/null and b/emojis/1f1e8-1f1fe.png differ diff --git a/emojis/1f1e8-1f1ff.png b/emojis/1f1e8-1f1ff.png new file mode 100644 index 00000000..ac404b0e Binary files /dev/null and b/emojis/1f1e8-1f1ff.png differ diff --git a/emojis/1f1e9-1f1ea.png b/emojis/1f1e9-1f1ea.png new file mode 100644 index 00000000..1664fe83 Binary files /dev/null and b/emojis/1f1e9-1f1ea.png differ diff --git a/emojis/1f1e9-1f1ec.png b/emojis/1f1e9-1f1ec.png new file mode 100644 index 00000000..f96b7e28 Binary files /dev/null and b/emojis/1f1e9-1f1ec.png differ diff --git a/emojis/1f1e9-1f1ef.png b/emojis/1f1e9-1f1ef.png new file mode 100644 index 00000000..5ed815f7 Binary files /dev/null and b/emojis/1f1e9-1f1ef.png differ diff --git a/emojis/1f1e9-1f1f0.png b/emojis/1f1e9-1f1f0.png new file mode 100644 index 00000000..368bc42d Binary files /dev/null and b/emojis/1f1e9-1f1f0.png differ diff --git a/emojis/1f1e9-1f1f2.png b/emojis/1f1e9-1f1f2.png new file mode 100644 index 00000000..e4567739 Binary files /dev/null and b/emojis/1f1e9-1f1f2.png differ diff --git a/emojis/1f1e9-1f1f4.png b/emojis/1f1e9-1f1f4.png new file mode 100644 index 00000000..c1f3c547 Binary files /dev/null and b/emojis/1f1e9-1f1f4.png differ diff --git a/emojis/1f1e9-1f1ff.png b/emojis/1f1e9-1f1ff.png new file mode 100644 index 00000000..25283884 Binary files /dev/null and b/emojis/1f1e9-1f1ff.png differ diff --git a/emojis/1f1ea-1f1e6.png b/emojis/1f1ea-1f1e6.png new file mode 100644 index 00000000..106343e0 Binary files /dev/null and b/emojis/1f1ea-1f1e6.png differ diff --git a/emojis/1f1ea-1f1e8.png b/emojis/1f1ea-1f1e8.png new file mode 100644 index 00000000..85e718ea Binary files /dev/null and b/emojis/1f1ea-1f1e8.png differ diff --git a/emojis/1f1ea-1f1ea.png b/emojis/1f1ea-1f1ea.png new file mode 100644 index 00000000..8610b4ee Binary files /dev/null and b/emojis/1f1ea-1f1ea.png differ diff --git a/emojis/1f1ea-1f1ec.png b/emojis/1f1ea-1f1ec.png new file mode 100644 index 00000000..f2e5b19d Binary files /dev/null and b/emojis/1f1ea-1f1ec.png differ diff --git a/emojis/1f1ea-1f1ed.png b/emojis/1f1ea-1f1ed.png new file mode 100644 index 00000000..7a7af4cd Binary files /dev/null and b/emojis/1f1ea-1f1ed.png differ diff --git a/emojis/1f1ea-1f1f7.png b/emojis/1f1ea-1f1f7.png new file mode 100644 index 00000000..2338a490 Binary files /dev/null and b/emojis/1f1ea-1f1f7.png differ diff --git a/emojis/1f1ea-1f1f8.png b/emojis/1f1ea-1f1f8.png new file mode 100644 index 00000000..106343e0 Binary files /dev/null and b/emojis/1f1ea-1f1f8.png differ diff --git a/emojis/1f1ea-1f1f9.png b/emojis/1f1ea-1f1f9.png new file mode 100644 index 00000000..92ba8492 Binary files /dev/null and b/emojis/1f1ea-1f1f9.png differ diff --git a/emojis/1f1ea-1f1fa.png b/emojis/1f1ea-1f1fa.png new file mode 100644 index 00000000..8505a097 Binary files /dev/null and b/emojis/1f1ea-1f1fa.png differ diff --git a/emojis/1f1eb-1f1ee.png b/emojis/1f1eb-1f1ee.png new file mode 100644 index 00000000..60ae8ba4 Binary files /dev/null and b/emojis/1f1eb-1f1ee.png differ diff --git a/emojis/1f1eb-1f1ef.png b/emojis/1f1eb-1f1ef.png new file mode 100644 index 00000000..2d89f4b2 Binary files /dev/null and b/emojis/1f1eb-1f1ef.png differ diff --git a/emojis/1f1eb-1f1f0.png b/emojis/1f1eb-1f1f0.png new file mode 100644 index 00000000..2ac15c56 Binary files /dev/null and b/emojis/1f1eb-1f1f0.png differ diff --git a/emojis/1f1eb-1f1f2.png b/emojis/1f1eb-1f1f2.png new file mode 100644 index 00000000..7006aaa4 Binary files /dev/null and b/emojis/1f1eb-1f1f2.png differ diff --git a/emojis/1f1eb-1f1f4.png b/emojis/1f1eb-1f1f4.png new file mode 100644 index 00000000..1a4319c0 Binary files /dev/null and b/emojis/1f1eb-1f1f4.png differ diff --git a/emojis/1f1eb-1f1f7.png b/emojis/1f1eb-1f1f7.png new file mode 100644 index 00000000..49d3cee3 Binary files /dev/null and b/emojis/1f1eb-1f1f7.png differ diff --git a/emojis/1f1ec-1f1e6.png b/emojis/1f1ec-1f1e6.png new file mode 100644 index 00000000..140bd24e Binary files /dev/null and b/emojis/1f1ec-1f1e6.png differ diff --git a/emojis/1f1ec-1f1e7.png b/emojis/1f1ec-1f1e7.png new file mode 100644 index 00000000..fe4a4820 Binary files /dev/null and b/emojis/1f1ec-1f1e7.png differ diff --git a/emojis/1f1ec-1f1e9.png b/emojis/1f1ec-1f1e9.png new file mode 100644 index 00000000..42d73882 Binary files /dev/null and b/emojis/1f1ec-1f1e9.png differ diff --git a/emojis/1f1ec-1f1ea.png b/emojis/1f1ec-1f1ea.png new file mode 100644 index 00000000..42054f9b Binary files /dev/null and b/emojis/1f1ec-1f1ea.png differ diff --git a/emojis/1f1ec-1f1eb.png b/emojis/1f1ec-1f1eb.png new file mode 100644 index 00000000..9f5b65a3 Binary files /dev/null and b/emojis/1f1ec-1f1eb.png differ diff --git a/emojis/1f1ec-1f1ec.png b/emojis/1f1ec-1f1ec.png new file mode 100644 index 00000000..060498aa Binary files /dev/null and b/emojis/1f1ec-1f1ec.png differ diff --git a/emojis/1f1ec-1f1ed.png b/emojis/1f1ec-1f1ed.png new file mode 100644 index 00000000..37033413 Binary files /dev/null and b/emojis/1f1ec-1f1ed.png differ diff --git a/emojis/1f1ec-1f1ee.png b/emojis/1f1ec-1f1ee.png new file mode 100644 index 00000000..51c9a4c0 Binary files /dev/null and b/emojis/1f1ec-1f1ee.png differ diff --git a/emojis/1f1ec-1f1f1.png b/emojis/1f1ec-1f1f1.png new file mode 100644 index 00000000..5250c71b Binary files /dev/null and b/emojis/1f1ec-1f1f1.png differ diff --git a/emojis/1f1ec-1f1f2.png b/emojis/1f1ec-1f1f2.png new file mode 100644 index 00000000..d528ee98 Binary files /dev/null and b/emojis/1f1ec-1f1f2.png differ diff --git a/emojis/1f1ec-1f1f3.png b/emojis/1f1ec-1f1f3.png new file mode 100644 index 00000000..e1ab17b0 Binary files /dev/null and b/emojis/1f1ec-1f1f3.png differ diff --git a/emojis/1f1ec-1f1f5.png b/emojis/1f1ec-1f1f5.png new file mode 100644 index 00000000..82f071d3 Binary files /dev/null and b/emojis/1f1ec-1f1f5.png differ diff --git a/emojis/1f1ec-1f1f6.png b/emojis/1f1ec-1f1f6.png new file mode 100644 index 00000000..ae906f7b Binary files /dev/null and b/emojis/1f1ec-1f1f6.png differ diff --git a/emojis/1f1ec-1f1f7.png b/emojis/1f1ec-1f1f7.png new file mode 100644 index 00000000..861da81b Binary files /dev/null and b/emojis/1f1ec-1f1f7.png differ diff --git a/emojis/1f1ec-1f1f8.png b/emojis/1f1ec-1f1f8.png new file mode 100644 index 00000000..b68a84aa Binary files /dev/null and b/emojis/1f1ec-1f1f8.png differ diff --git a/emojis/1f1ec-1f1f9.png b/emojis/1f1ec-1f1f9.png new file mode 100644 index 00000000..7e9a853c Binary files /dev/null and b/emojis/1f1ec-1f1f9.png differ diff --git a/emojis/1f1ec-1f1fa.png b/emojis/1f1ec-1f1fa.png new file mode 100644 index 00000000..b8e4ef22 Binary files /dev/null and b/emojis/1f1ec-1f1fa.png differ diff --git a/emojis/1f1ec-1f1fc.png b/emojis/1f1ec-1f1fc.png new file mode 100644 index 00000000..bc7295be Binary files /dev/null and b/emojis/1f1ec-1f1fc.png differ diff --git a/emojis/1f1ec-1f1fe.png b/emojis/1f1ec-1f1fe.png new file mode 100644 index 00000000..147ae88e Binary files /dev/null and b/emojis/1f1ec-1f1fe.png differ diff --git a/emojis/1f1ed-1f1f0.png b/emojis/1f1ed-1f1f0.png new file mode 100644 index 00000000..bb793930 Binary files /dev/null and b/emojis/1f1ed-1f1f0.png differ diff --git a/emojis/1f1ed-1f1f2.png b/emojis/1f1ed-1f1f2.png new file mode 100644 index 00000000..686b2438 Binary files /dev/null and b/emojis/1f1ed-1f1f2.png differ diff --git a/emojis/1f1ed-1f1f3.png b/emojis/1f1ed-1f1f3.png new file mode 100644 index 00000000..906e928d Binary files /dev/null and b/emojis/1f1ed-1f1f3.png differ diff --git a/emojis/1f1ed-1f1f7.png b/emojis/1f1ed-1f1f7.png new file mode 100644 index 00000000..57845ee8 Binary files /dev/null and b/emojis/1f1ed-1f1f7.png differ diff --git a/emojis/1f1ed-1f1f9.png b/emojis/1f1ed-1f1f9.png new file mode 100644 index 00000000..44233b06 Binary files /dev/null and b/emojis/1f1ed-1f1f9.png differ diff --git a/emojis/1f1ed-1f1fa.png b/emojis/1f1ed-1f1fa.png new file mode 100644 index 00000000..26192115 Binary files /dev/null and b/emojis/1f1ed-1f1fa.png differ diff --git a/emojis/1f1ee-1f1e8.png b/emojis/1f1ee-1f1e8.png new file mode 100644 index 00000000..ad720c55 Binary files /dev/null and b/emojis/1f1ee-1f1e8.png differ diff --git a/emojis/1f1ee-1f1e9.png b/emojis/1f1ee-1f1e9.png new file mode 100644 index 00000000..ca0ac5cd Binary files /dev/null and b/emojis/1f1ee-1f1e9.png differ diff --git a/emojis/1f1ee-1f1ea.png b/emojis/1f1ee-1f1ea.png new file mode 100644 index 00000000..92bcda93 Binary files /dev/null and b/emojis/1f1ee-1f1ea.png differ diff --git a/emojis/1f1ee-1f1f1.png b/emojis/1f1ee-1f1f1.png new file mode 100644 index 00000000..63893052 Binary files /dev/null and b/emojis/1f1ee-1f1f1.png differ diff --git a/emojis/1f1ee-1f1f2.png b/emojis/1f1ee-1f1f2.png new file mode 100644 index 00000000..339e561b Binary files /dev/null and b/emojis/1f1ee-1f1f2.png differ diff --git a/emojis/1f1ee-1f1f3.png b/emojis/1f1ee-1f1f3.png new file mode 100644 index 00000000..49154ab8 Binary files /dev/null and b/emojis/1f1ee-1f1f3.png differ diff --git a/emojis/1f1ee-1f1f4.png b/emojis/1f1ee-1f1f4.png new file mode 100644 index 00000000..f96b7e28 Binary files /dev/null and b/emojis/1f1ee-1f1f4.png differ diff --git a/emojis/1f1ee-1f1f6.png b/emojis/1f1ee-1f1f6.png new file mode 100644 index 00000000..19ca0151 Binary files /dev/null and b/emojis/1f1ee-1f1f6.png differ diff --git a/emojis/1f1ee-1f1f7.png b/emojis/1f1ee-1f1f7.png new file mode 100644 index 00000000..155fe444 Binary files /dev/null and b/emojis/1f1ee-1f1f7.png differ diff --git a/emojis/1f1ee-1f1f8.png b/emojis/1f1ee-1f1f8.png new file mode 100644 index 00000000..2b7ed5c2 Binary files /dev/null and b/emojis/1f1ee-1f1f8.png differ diff --git a/emojis/1f1ee-1f1f9.png b/emojis/1f1ee-1f1f9.png new file mode 100644 index 00000000..a93df5b5 Binary files /dev/null and b/emojis/1f1ee-1f1f9.png differ diff --git a/emojis/1f1ef-1f1ea.png b/emojis/1f1ef-1f1ea.png new file mode 100644 index 00000000..c5889565 Binary files /dev/null and b/emojis/1f1ef-1f1ea.png differ diff --git a/emojis/1f1ef-1f1f2.png b/emojis/1f1ef-1f1f2.png new file mode 100644 index 00000000..ec14aaa6 Binary files /dev/null and b/emojis/1f1ef-1f1f2.png differ diff --git a/emojis/1f1ef-1f1f4.png b/emojis/1f1ef-1f1f4.png new file mode 100644 index 00000000..e00caf69 Binary files /dev/null and b/emojis/1f1ef-1f1f4.png differ diff --git a/emojis/1f1ef-1f1f5.png b/emojis/1f1ef-1f1f5.png new file mode 100644 index 00000000..6524f75a Binary files /dev/null and b/emojis/1f1ef-1f1f5.png differ diff --git a/emojis/1f1f0-1f1ea.png b/emojis/1f1f0-1f1ea.png new file mode 100644 index 00000000..594fc41e Binary files /dev/null and b/emojis/1f1f0-1f1ea.png differ diff --git a/emojis/1f1f0-1f1ec.png b/emojis/1f1f0-1f1ec.png new file mode 100644 index 00000000..b7ab5685 Binary files /dev/null and b/emojis/1f1f0-1f1ec.png differ diff --git a/emojis/1f1f0-1f1ed.png b/emojis/1f1f0-1f1ed.png new file mode 100644 index 00000000..555b891a Binary files /dev/null and b/emojis/1f1f0-1f1ed.png differ diff --git a/emojis/1f1f0-1f1ee.png b/emojis/1f1f0-1f1ee.png new file mode 100644 index 00000000..2d3d680f Binary files /dev/null and b/emojis/1f1f0-1f1ee.png differ diff --git a/emojis/1f1f0-1f1f2.png b/emojis/1f1f0-1f1f2.png new file mode 100644 index 00000000..3c2f4068 Binary files /dev/null and b/emojis/1f1f0-1f1f2.png differ diff --git a/emojis/1f1f0-1f1f3.png b/emojis/1f1f0-1f1f3.png new file mode 100644 index 00000000..2b910241 Binary files /dev/null and b/emojis/1f1f0-1f1f3.png differ diff --git a/emojis/1f1f0-1f1f5.png b/emojis/1f1f0-1f1f5.png new file mode 100644 index 00000000..d484fcb4 Binary files /dev/null and b/emojis/1f1f0-1f1f5.png differ diff --git a/emojis/1f1f0-1f1f7.png b/emojis/1f1f0-1f1f7.png new file mode 100644 index 00000000..34a73124 Binary files /dev/null and b/emojis/1f1f0-1f1f7.png differ diff --git a/emojis/1f1f0-1f1fc.png b/emojis/1f1f0-1f1fc.png new file mode 100644 index 00000000..a9f513b2 Binary files /dev/null and b/emojis/1f1f0-1f1fc.png differ diff --git a/emojis/1f1f0-1f1fe.png b/emojis/1f1f0-1f1fe.png new file mode 100644 index 00000000..509aff96 Binary files /dev/null and b/emojis/1f1f0-1f1fe.png differ diff --git a/emojis/1f1f0-1f1ff.png b/emojis/1f1f0-1f1ff.png new file mode 100644 index 00000000..44a1466b Binary files /dev/null and b/emojis/1f1f0-1f1ff.png differ diff --git a/emojis/1f1f1-1f1e6.png b/emojis/1f1f1-1f1e6.png new file mode 100644 index 00000000..75f95569 Binary files /dev/null and b/emojis/1f1f1-1f1e6.png differ diff --git a/emojis/1f1f1-1f1e7.png b/emojis/1f1f1-1f1e7.png new file mode 100644 index 00000000..1f9bf891 Binary files /dev/null and b/emojis/1f1f1-1f1e7.png differ diff --git a/emojis/1f1f1-1f1e8.png b/emojis/1f1f1-1f1e8.png new file mode 100644 index 00000000..ae52ba40 Binary files /dev/null and b/emojis/1f1f1-1f1e8.png differ diff --git a/emojis/1f1f1-1f1ee.png b/emojis/1f1f1-1f1ee.png new file mode 100644 index 00000000..7c60af3a Binary files /dev/null and b/emojis/1f1f1-1f1ee.png differ diff --git a/emojis/1f1f1-1f1f0.png b/emojis/1f1f1-1f1f0.png new file mode 100644 index 00000000..ff31f6ba Binary files /dev/null and b/emojis/1f1f1-1f1f0.png differ diff --git a/emojis/1f1f1-1f1f7.png b/emojis/1f1f1-1f1f7.png new file mode 100644 index 00000000..9e640bea Binary files /dev/null and b/emojis/1f1f1-1f1f7.png differ diff --git a/emojis/1f1f1-1f1f8.png b/emojis/1f1f1-1f1f8.png new file mode 100644 index 00000000..4814d9ae Binary files /dev/null and b/emojis/1f1f1-1f1f8.png differ diff --git a/emojis/1f1f1-1f1f9.png b/emojis/1f1f1-1f1f9.png new file mode 100644 index 00000000..db81293f Binary files /dev/null and b/emojis/1f1f1-1f1f9.png differ diff --git a/emojis/1f1f1-1f1fa.png b/emojis/1f1f1-1f1fa.png new file mode 100644 index 00000000..11a0b27d Binary files /dev/null and b/emojis/1f1f1-1f1fa.png differ diff --git a/emojis/1f1f1-1f1fb.png b/emojis/1f1f1-1f1fb.png new file mode 100644 index 00000000..aca16066 Binary files /dev/null and b/emojis/1f1f1-1f1fb.png differ diff --git a/emojis/1f1f1-1f1fe.png b/emojis/1f1f1-1f1fe.png new file mode 100644 index 00000000..17d1ebea Binary files /dev/null and b/emojis/1f1f1-1f1fe.png differ diff --git a/emojis/1f1f2-1f1e6.png b/emojis/1f1f2-1f1e6.png new file mode 100644 index 00000000..3bfd6dcd Binary files /dev/null and b/emojis/1f1f2-1f1e6.png differ diff --git a/emojis/1f1f2-1f1e8.png b/emojis/1f1f2-1f1e8.png new file mode 100644 index 00000000..393d0799 Binary files /dev/null and b/emojis/1f1f2-1f1e8.png differ diff --git a/emojis/1f1f2-1f1e9.png b/emojis/1f1f2-1f1e9.png new file mode 100644 index 00000000..cd8a590e Binary files /dev/null and b/emojis/1f1f2-1f1e9.png differ diff --git a/emojis/1f1f2-1f1ea.png b/emojis/1f1f2-1f1ea.png new file mode 100644 index 00000000..6273c123 Binary files /dev/null and b/emojis/1f1f2-1f1ea.png differ diff --git a/emojis/1f1f2-1f1eb.png b/emojis/1f1f2-1f1eb.png new file mode 100644 index 00000000..49d3cee3 Binary files /dev/null and b/emojis/1f1f2-1f1eb.png differ diff --git a/emojis/1f1f2-1f1ec.png b/emojis/1f1f2-1f1ec.png new file mode 100644 index 00000000..f20f72a8 Binary files /dev/null and b/emojis/1f1f2-1f1ec.png differ diff --git a/emojis/1f1f2-1f1ed.png b/emojis/1f1f2-1f1ed.png new file mode 100644 index 00000000..cf741796 Binary files /dev/null and b/emojis/1f1f2-1f1ed.png differ diff --git a/emojis/1f1f2-1f1f0.png b/emojis/1f1f2-1f1f0.png new file mode 100644 index 00000000..dd28a2e0 Binary files /dev/null and b/emojis/1f1f2-1f1f0.png differ diff --git a/emojis/1f1f2-1f1f1.png b/emojis/1f1f2-1f1f1.png new file mode 100644 index 00000000..fce3c1b3 Binary files /dev/null and b/emojis/1f1f2-1f1f1.png differ diff --git a/emojis/1f1f2-1f1f2.png b/emojis/1f1f2-1f1f2.png new file mode 100644 index 00000000..5468bd3a Binary files /dev/null and b/emojis/1f1f2-1f1f2.png differ diff --git a/emojis/1f1f2-1f1f3.png b/emojis/1f1f2-1f1f3.png new file mode 100644 index 00000000..e70d2e9a Binary files /dev/null and b/emojis/1f1f2-1f1f3.png differ diff --git a/emojis/1f1f2-1f1f4.png b/emojis/1f1f2-1f1f4.png new file mode 100644 index 00000000..150fc587 Binary files /dev/null and b/emojis/1f1f2-1f1f4.png differ diff --git a/emojis/1f1f2-1f1f5.png b/emojis/1f1f2-1f1f5.png new file mode 100644 index 00000000..13ca25b0 Binary files /dev/null and b/emojis/1f1f2-1f1f5.png differ diff --git a/emojis/1f1f2-1f1f6.png b/emojis/1f1f2-1f1f6.png new file mode 100644 index 00000000..a6ff03de Binary files /dev/null and b/emojis/1f1f2-1f1f6.png differ diff --git a/emojis/1f1f2-1f1f7.png b/emojis/1f1f2-1f1f7.png new file mode 100644 index 00000000..0e8364f9 Binary files /dev/null and b/emojis/1f1f2-1f1f7.png differ diff --git a/emojis/1f1f2-1f1f8.png b/emojis/1f1f2-1f1f8.png new file mode 100644 index 00000000..b53cdba4 Binary files /dev/null and b/emojis/1f1f2-1f1f8.png differ diff --git a/emojis/1f1f2-1f1f9.png b/emojis/1f1f2-1f1f9.png new file mode 100644 index 00000000..f287dffd Binary files /dev/null and b/emojis/1f1f2-1f1f9.png differ diff --git a/emojis/1f1f2-1f1fa.png b/emojis/1f1f2-1f1fa.png new file mode 100644 index 00000000..7eeeb542 Binary files /dev/null and b/emojis/1f1f2-1f1fa.png differ diff --git a/emojis/1f1f2-1f1fb.png b/emojis/1f1f2-1f1fb.png new file mode 100644 index 00000000..ee0d0f8c Binary files /dev/null and b/emojis/1f1f2-1f1fb.png differ diff --git a/emojis/1f1f2-1f1fc.png b/emojis/1f1f2-1f1fc.png new file mode 100644 index 00000000..0600e5aa Binary files /dev/null and b/emojis/1f1f2-1f1fc.png differ diff --git a/emojis/1f1f2-1f1fd.png b/emojis/1f1f2-1f1fd.png new file mode 100644 index 00000000..f401b400 Binary files /dev/null and b/emojis/1f1f2-1f1fd.png differ diff --git a/emojis/1f1f2-1f1fe.png b/emojis/1f1f2-1f1fe.png new file mode 100644 index 00000000..d2eeba0c Binary files /dev/null and b/emojis/1f1f2-1f1fe.png differ diff --git a/emojis/1f1f2-1f1ff.png b/emojis/1f1f2-1f1ff.png new file mode 100644 index 00000000..b86d6442 Binary files /dev/null and b/emojis/1f1f2-1f1ff.png differ diff --git a/emojis/1f1f3-1f1e6.png b/emojis/1f1f3-1f1e6.png new file mode 100644 index 00000000..7a8adc2f Binary files /dev/null and b/emojis/1f1f3-1f1e6.png differ diff --git a/emojis/1f1f3-1f1e8.png b/emojis/1f1f3-1f1e8.png new file mode 100644 index 00000000..ddc6865b Binary files /dev/null and b/emojis/1f1f3-1f1e8.png differ diff --git a/emojis/1f1f3-1f1ea.png b/emojis/1f1f3-1f1ea.png new file mode 100644 index 00000000..e6bafb13 Binary files /dev/null and b/emojis/1f1f3-1f1ea.png differ diff --git a/emojis/1f1f3-1f1eb.png b/emojis/1f1f3-1f1eb.png new file mode 100644 index 00000000..793813ea Binary files /dev/null and b/emojis/1f1f3-1f1eb.png differ diff --git a/emojis/1f1f3-1f1ec.png b/emojis/1f1f3-1f1ec.png new file mode 100644 index 00000000..75247085 Binary files /dev/null and b/emojis/1f1f3-1f1ec.png differ diff --git a/emojis/1f1f3-1f1ee.png b/emojis/1f1f3-1f1ee.png new file mode 100644 index 00000000..4d860947 Binary files /dev/null and b/emojis/1f1f3-1f1ee.png differ diff --git a/emojis/1f1f3-1f1f1.png b/emojis/1f1f3-1f1f1.png new file mode 100644 index 00000000..108fab62 Binary files /dev/null and b/emojis/1f1f3-1f1f1.png differ diff --git a/emojis/1f1f3-1f1f4.png b/emojis/1f1f3-1f1f4.png new file mode 100644 index 00000000..b6ccaa8e Binary files /dev/null and b/emojis/1f1f3-1f1f4.png differ diff --git a/emojis/1f1f3-1f1f5.png b/emojis/1f1f3-1f1f5.png new file mode 100644 index 00000000..c9f334fc Binary files /dev/null and b/emojis/1f1f3-1f1f5.png differ diff --git a/emojis/1f1f3-1f1f7.png b/emojis/1f1f3-1f1f7.png new file mode 100644 index 00000000..a4990002 Binary files /dev/null and b/emojis/1f1f3-1f1f7.png differ diff --git a/emojis/1f1f3-1f1fa.png b/emojis/1f1f3-1f1fa.png new file mode 100644 index 00000000..f5530bf4 Binary files /dev/null and b/emojis/1f1f3-1f1fa.png differ diff --git a/emojis/1f1f3-1f1ff.png b/emojis/1f1f3-1f1ff.png new file mode 100644 index 00000000..55c450c1 Binary files /dev/null and b/emojis/1f1f3-1f1ff.png differ diff --git a/emojis/1f1f4-1f1f2.png b/emojis/1f1f4-1f1f2.png new file mode 100644 index 00000000..82a76e01 Binary files /dev/null and b/emojis/1f1f4-1f1f2.png differ diff --git a/emojis/1f1f5-1f1e6.png b/emojis/1f1f5-1f1e6.png new file mode 100644 index 00000000..321fcdad Binary files /dev/null and b/emojis/1f1f5-1f1e6.png differ diff --git a/emojis/1f1f5-1f1ea.png b/emojis/1f1f5-1f1ea.png new file mode 100644 index 00000000..f9092204 Binary files /dev/null and b/emojis/1f1f5-1f1ea.png differ diff --git a/emojis/1f1f5-1f1eb.png b/emojis/1f1f5-1f1eb.png new file mode 100644 index 00000000..5cd6d7b8 Binary files /dev/null and b/emojis/1f1f5-1f1eb.png differ diff --git a/emojis/1f1f5-1f1ec.png b/emojis/1f1f5-1f1ec.png new file mode 100644 index 00000000..df254bea Binary files /dev/null and b/emojis/1f1f5-1f1ec.png differ diff --git a/emojis/1f1f5-1f1ed.png b/emojis/1f1f5-1f1ed.png new file mode 100644 index 00000000..a0dde9d6 Binary files /dev/null and b/emojis/1f1f5-1f1ed.png differ diff --git a/emojis/1f1f5-1f1f0.png b/emojis/1f1f5-1f1f0.png new file mode 100644 index 00000000..3c9cbacf Binary files /dev/null and b/emojis/1f1f5-1f1f0.png differ diff --git a/emojis/1f1f5-1f1f1.png b/emojis/1f1f5-1f1f1.png new file mode 100644 index 00000000..e34c68f9 Binary files /dev/null and b/emojis/1f1f5-1f1f1.png differ diff --git a/emojis/1f1f5-1f1f2.png b/emojis/1f1f5-1f1f2.png new file mode 100644 index 00000000..53ea6450 Binary files /dev/null and b/emojis/1f1f5-1f1f2.png differ diff --git a/emojis/1f1f5-1f1f3.png b/emojis/1f1f5-1f1f3.png new file mode 100644 index 00000000..daee9b97 Binary files /dev/null and b/emojis/1f1f5-1f1f3.png differ diff --git a/emojis/1f1f5-1f1f7.png b/emojis/1f1f5-1f1f7.png new file mode 100644 index 00000000..46d73adb Binary files /dev/null and b/emojis/1f1f5-1f1f7.png differ diff --git a/emojis/1f1f5-1f1f8.png b/emojis/1f1f5-1f1f8.png new file mode 100644 index 00000000..8e9df727 Binary files /dev/null and b/emojis/1f1f5-1f1f8.png differ diff --git a/emojis/1f1f5-1f1f9.png b/emojis/1f1f5-1f1f9.png new file mode 100644 index 00000000..9e29d95e Binary files /dev/null and b/emojis/1f1f5-1f1f9.png differ diff --git a/emojis/1f1f5-1f1fc.png b/emojis/1f1f5-1f1fc.png new file mode 100644 index 00000000..12662419 Binary files /dev/null and b/emojis/1f1f5-1f1fc.png differ diff --git a/emojis/1f1f5-1f1fe.png b/emojis/1f1f5-1f1fe.png new file mode 100644 index 00000000..af8da86c Binary files /dev/null and b/emojis/1f1f5-1f1fe.png differ diff --git a/emojis/1f1f6-1f1e6.png b/emojis/1f1f6-1f1e6.png new file mode 100644 index 00000000..a3c05cb0 Binary files /dev/null and b/emojis/1f1f6-1f1e6.png differ diff --git a/emojis/1f1f7-1f1ea.png b/emojis/1f1f7-1f1ea.png new file mode 100644 index 00000000..467754ae Binary files /dev/null and b/emojis/1f1f7-1f1ea.png differ diff --git a/emojis/1f1f7-1f1f4.png b/emojis/1f1f7-1f1f4.png new file mode 100644 index 00000000..d9e64187 Binary files /dev/null and b/emojis/1f1f7-1f1f4.png differ diff --git a/emojis/1f1f7-1f1f8.png b/emojis/1f1f7-1f1f8.png new file mode 100644 index 00000000..a387d8ea Binary files /dev/null and b/emojis/1f1f7-1f1f8.png differ diff --git a/emojis/1f1f7-1f1fa.png b/emojis/1f1f7-1f1fa.png new file mode 100644 index 00000000..38454d2a Binary files /dev/null and b/emojis/1f1f7-1f1fa.png differ diff --git a/emojis/1f1f7-1f1fc.png b/emojis/1f1f7-1f1fc.png new file mode 100644 index 00000000..6c306c18 Binary files /dev/null and b/emojis/1f1f7-1f1fc.png differ diff --git a/emojis/1f1f8-1f1e6.png b/emojis/1f1f8-1f1e6.png new file mode 100644 index 00000000..a2132dff Binary files /dev/null and b/emojis/1f1f8-1f1e6.png differ diff --git a/emojis/1f1f8-1f1e7.png b/emojis/1f1f8-1f1e7.png new file mode 100644 index 00000000..497377b0 Binary files /dev/null and b/emojis/1f1f8-1f1e7.png differ diff --git a/emojis/1f1f8-1f1e8.png b/emojis/1f1f8-1f1e8.png new file mode 100644 index 00000000..798a8a9e Binary files /dev/null and b/emojis/1f1f8-1f1e8.png differ diff --git a/emojis/1f1f8-1f1e9.png b/emojis/1f1f8-1f1e9.png new file mode 100644 index 00000000..6a60ec8c Binary files /dev/null and b/emojis/1f1f8-1f1e9.png differ diff --git a/emojis/1f1f8-1f1ea.png b/emojis/1f1f8-1f1ea.png new file mode 100644 index 00000000..efbfdb00 Binary files /dev/null and b/emojis/1f1f8-1f1ea.png differ diff --git a/emojis/1f1f8-1f1ec.png b/emojis/1f1f8-1f1ec.png new file mode 100644 index 00000000..407d6b28 Binary files /dev/null and b/emojis/1f1f8-1f1ec.png differ diff --git a/emojis/1f1f8-1f1ed.png b/emojis/1f1f8-1f1ed.png new file mode 100644 index 00000000..b2e3973f Binary files /dev/null and b/emojis/1f1f8-1f1ed.png differ diff --git a/emojis/1f1f8-1f1ee.png b/emojis/1f1f8-1f1ee.png new file mode 100644 index 00000000..70772fd3 Binary files /dev/null and b/emojis/1f1f8-1f1ee.png differ diff --git a/emojis/1f1f8-1f1ef.png b/emojis/1f1f8-1f1ef.png new file mode 100644 index 00000000..b6ccaa8e Binary files /dev/null and b/emojis/1f1f8-1f1ef.png differ diff --git a/emojis/1f1f8-1f1f0.png b/emojis/1f1f8-1f1f0.png new file mode 100644 index 00000000..4bfcb818 Binary files /dev/null and b/emojis/1f1f8-1f1f0.png differ diff --git a/emojis/1f1f8-1f1f1.png b/emojis/1f1f8-1f1f1.png new file mode 100644 index 00000000..8ac43964 Binary files /dev/null and b/emojis/1f1f8-1f1f1.png differ diff --git a/emojis/1f1f8-1f1f2.png b/emojis/1f1f8-1f1f2.png new file mode 100644 index 00000000..e0cc6607 Binary files /dev/null and b/emojis/1f1f8-1f1f2.png differ diff --git a/emojis/1f1f8-1f1f3.png b/emojis/1f1f8-1f1f3.png new file mode 100644 index 00000000..4598f9f9 Binary files /dev/null and b/emojis/1f1f8-1f1f3.png differ diff --git a/emojis/1f1f8-1f1f4.png b/emojis/1f1f8-1f1f4.png new file mode 100644 index 00000000..1dcbe44f Binary files /dev/null and b/emojis/1f1f8-1f1f4.png differ diff --git a/emojis/1f1f8-1f1f7.png b/emojis/1f1f8-1f1f7.png new file mode 100644 index 00000000..f49a5542 Binary files /dev/null and b/emojis/1f1f8-1f1f7.png differ diff --git a/emojis/1f1f8-1f1f8.png b/emojis/1f1f8-1f1f8.png new file mode 100644 index 00000000..f3f35fdb Binary files /dev/null and b/emojis/1f1f8-1f1f8.png differ diff --git a/emojis/1f1f8-1f1f9.png b/emojis/1f1f8-1f1f9.png new file mode 100644 index 00000000..2afdea70 Binary files /dev/null and b/emojis/1f1f8-1f1f9.png differ diff --git a/emojis/1f1f8-1f1fb.png b/emojis/1f1f8-1f1fb.png new file mode 100644 index 00000000..4f74d58d Binary files /dev/null and b/emojis/1f1f8-1f1fb.png differ diff --git a/emojis/1f1f8-1f1fd.png b/emojis/1f1f8-1f1fd.png new file mode 100644 index 00000000..6fb29a42 Binary files /dev/null and b/emojis/1f1f8-1f1fd.png differ diff --git a/emojis/1f1f8-1f1fe.png b/emojis/1f1f8-1f1fe.png new file mode 100644 index 00000000..541da3f9 Binary files /dev/null and b/emojis/1f1f8-1f1fe.png differ diff --git a/emojis/1f1f8-1f1ff.png b/emojis/1f1f8-1f1ff.png new file mode 100644 index 00000000..e3de29f7 Binary files /dev/null and b/emojis/1f1f8-1f1ff.png differ diff --git a/emojis/1f1f9-1f1e6.png b/emojis/1f1f9-1f1e6.png new file mode 100644 index 00000000..91ddb125 Binary files /dev/null and b/emojis/1f1f9-1f1e6.png differ diff --git a/emojis/1f1f9-1f1e8.png b/emojis/1f1f9-1f1e8.png new file mode 100644 index 00000000..fac570eb Binary files /dev/null and b/emojis/1f1f9-1f1e8.png differ diff --git a/emojis/1f1f9-1f1e9.png b/emojis/1f1f9-1f1e9.png new file mode 100644 index 00000000..dabd311e Binary files /dev/null and b/emojis/1f1f9-1f1e9.png differ diff --git a/emojis/1f1f9-1f1eb.png b/emojis/1f1f9-1f1eb.png new file mode 100644 index 00000000..c37f3c58 Binary files /dev/null and b/emojis/1f1f9-1f1eb.png differ diff --git a/emojis/1f1f9-1f1ec.png b/emojis/1f1f9-1f1ec.png new file mode 100644 index 00000000..1ef1370c Binary files /dev/null and b/emojis/1f1f9-1f1ec.png differ diff --git a/emojis/1f1f9-1f1ed.png b/emojis/1f1f9-1f1ed.png new file mode 100644 index 00000000..99cf5391 Binary files /dev/null and b/emojis/1f1f9-1f1ed.png differ diff --git a/emojis/1f1f9-1f1ef.png b/emojis/1f1f9-1f1ef.png new file mode 100644 index 00000000..845d2f1d Binary files /dev/null and b/emojis/1f1f9-1f1ef.png differ diff --git a/emojis/1f1f9-1f1f0.png b/emojis/1f1f9-1f1f0.png new file mode 100644 index 00000000..82a53925 Binary files /dev/null and b/emojis/1f1f9-1f1f0.png differ diff --git a/emojis/1f1f9-1f1f1.png b/emojis/1f1f9-1f1f1.png new file mode 100644 index 00000000..af876256 Binary files /dev/null and b/emojis/1f1f9-1f1f1.png differ diff --git a/emojis/1f1f9-1f1f2.png b/emojis/1f1f9-1f1f2.png new file mode 100644 index 00000000..5be97cb5 Binary files /dev/null and b/emojis/1f1f9-1f1f2.png differ diff --git a/emojis/1f1f9-1f1f3.png b/emojis/1f1f9-1f1f3.png new file mode 100644 index 00000000..a935b0b4 Binary files /dev/null and b/emojis/1f1f9-1f1f3.png differ diff --git a/emojis/1f1f9-1f1f4.png b/emojis/1f1f9-1f1f4.png new file mode 100644 index 00000000..5c9099c7 Binary files /dev/null and b/emojis/1f1f9-1f1f4.png differ diff --git a/emojis/1f1f9-1f1f7.png b/emojis/1f1f9-1f1f7.png new file mode 100644 index 00000000..ab80a9a7 Binary files /dev/null and b/emojis/1f1f9-1f1f7.png differ diff --git a/emojis/1f1f9-1f1f9.png b/emojis/1f1f9-1f1f9.png new file mode 100644 index 00000000..49fa13bc Binary files /dev/null and b/emojis/1f1f9-1f1f9.png differ diff --git a/emojis/1f1f9-1f1fb.png b/emojis/1f1f9-1f1fb.png new file mode 100644 index 00000000..3cfdb29d Binary files /dev/null and b/emojis/1f1f9-1f1fb.png differ diff --git a/emojis/1f1f9-1f1fc.png b/emojis/1f1f9-1f1fc.png new file mode 100644 index 00000000..7447face Binary files /dev/null and b/emojis/1f1f9-1f1fc.png differ diff --git a/emojis/1f1f9-1f1ff.png b/emojis/1f1f9-1f1ff.png new file mode 100644 index 00000000..311f43e2 Binary files /dev/null and b/emojis/1f1f9-1f1ff.png differ diff --git a/emojis/1f1fa-1f1e6.png b/emojis/1f1fa-1f1e6.png new file mode 100644 index 00000000..4970ac81 Binary files /dev/null and b/emojis/1f1fa-1f1e6.png differ diff --git a/emojis/1f1fa-1f1ec.png b/emojis/1f1fa-1f1ec.png new file mode 100644 index 00000000..46fd6b67 Binary files /dev/null and b/emojis/1f1fa-1f1ec.png differ diff --git a/emojis/1f1fa-1f1f2.png b/emojis/1f1fa-1f1f2.png new file mode 100644 index 00000000..b9bc8ecf Binary files /dev/null and b/emojis/1f1fa-1f1f2.png differ diff --git a/emojis/1f1fa-1f1f8.png b/emojis/1f1fa-1f1f8.png new file mode 100644 index 00000000..b9bc8ecf Binary files /dev/null and b/emojis/1f1fa-1f1f8.png differ diff --git a/emojis/1f1fa-1f1fe.png b/emojis/1f1fa-1f1fe.png new file mode 100644 index 00000000..8f8dec2f Binary files /dev/null and b/emojis/1f1fa-1f1fe.png differ diff --git a/emojis/1f1fa-1f1ff.png b/emojis/1f1fa-1f1ff.png new file mode 100644 index 00000000..2379bf4a Binary files /dev/null and b/emojis/1f1fa-1f1ff.png differ diff --git a/emojis/1f1fb-1f1e6.png b/emojis/1f1fb-1f1e6.png new file mode 100644 index 00000000..74ed2806 Binary files /dev/null and b/emojis/1f1fb-1f1e6.png differ diff --git a/emojis/1f1fb-1f1e8.png b/emojis/1f1fb-1f1e8.png new file mode 100644 index 00000000..a319a043 Binary files /dev/null and b/emojis/1f1fb-1f1e8.png differ diff --git a/emojis/1f1fb-1f1ea.png b/emojis/1f1fb-1f1ea.png new file mode 100644 index 00000000..2af4c6cd Binary files /dev/null and b/emojis/1f1fb-1f1ea.png differ diff --git a/emojis/1f1fb-1f1ec.png b/emojis/1f1fb-1f1ec.png new file mode 100644 index 00000000..90e2af61 Binary files /dev/null and b/emojis/1f1fb-1f1ec.png differ diff --git a/emojis/1f1fb-1f1ee.png b/emojis/1f1fb-1f1ee.png new file mode 100644 index 00000000..6ff10308 Binary files /dev/null and b/emojis/1f1fb-1f1ee.png differ diff --git a/emojis/1f1fb-1f1f3.png b/emojis/1f1fb-1f1f3.png new file mode 100644 index 00000000..8e8b998a Binary files /dev/null and b/emojis/1f1fb-1f1f3.png differ diff --git a/emojis/1f1fb-1f1fa.png b/emojis/1f1fb-1f1fa.png new file mode 100644 index 00000000..a6780dbd Binary files /dev/null and b/emojis/1f1fb-1f1fa.png differ diff --git a/emojis/1f1fc-1f1eb.png b/emojis/1f1fc-1f1eb.png new file mode 100644 index 00000000..edf9ec30 Binary files /dev/null and b/emojis/1f1fc-1f1eb.png differ diff --git a/emojis/1f1fc-1f1f8.png b/emojis/1f1fc-1f1f8.png new file mode 100644 index 00000000..2b6f6388 Binary files /dev/null and b/emojis/1f1fc-1f1f8.png differ diff --git a/emojis/1f1fd-1f1f0.png b/emojis/1f1fd-1f1f0.png new file mode 100644 index 00000000..ba53b654 Binary files /dev/null and b/emojis/1f1fd-1f1f0.png differ diff --git a/emojis/1f1fe-1f1ea.png b/emojis/1f1fe-1f1ea.png new file mode 100644 index 00000000..47f96ef4 Binary files /dev/null and b/emojis/1f1fe-1f1ea.png differ diff --git a/emojis/1f1fe-1f1f9.png b/emojis/1f1fe-1f1f9.png new file mode 100644 index 00000000..5a1b2d9b Binary files /dev/null and b/emojis/1f1fe-1f1f9.png differ diff --git a/emojis/1f1ff-1f1e6.png b/emojis/1f1ff-1f1e6.png new file mode 100644 index 00000000..178709f6 Binary files /dev/null and b/emojis/1f1ff-1f1e6.png differ diff --git a/emojis/1f1ff-1f1f2.png b/emojis/1f1ff-1f1f2.png new file mode 100644 index 00000000..66afe555 Binary files /dev/null and b/emojis/1f1ff-1f1f2.png differ diff --git a/emojis/1f1ff-1f1fc.png b/emojis/1f1ff-1f1fc.png new file mode 100644 index 00000000..1ccd92c5 Binary files /dev/null and b/emojis/1f1ff-1f1fc.png differ diff --git a/emojis/1f201.png b/emojis/1f201.png new file mode 100644 index 00000000..7f81f8d0 Binary files /dev/null and b/emojis/1f201.png differ diff --git a/emojis/1f202.png b/emojis/1f202.png new file mode 100644 index 00000000..b5af88d9 Binary files /dev/null and b/emojis/1f202.png differ diff --git a/emojis/1f21a.png b/emojis/1f21a.png new file mode 100644 index 00000000..241fb799 Binary files /dev/null and b/emojis/1f21a.png differ diff --git a/emojis/1f22f.png b/emojis/1f22f.png new file mode 100644 index 00000000..b12caac7 Binary files /dev/null and b/emojis/1f22f.png differ diff --git a/emojis/1f232.png b/emojis/1f232.png new file mode 100644 index 00000000..b53f3d91 Binary files /dev/null and b/emojis/1f232.png differ diff --git a/emojis/1f233.png b/emojis/1f233.png new file mode 100644 index 00000000..97ad4460 Binary files /dev/null and b/emojis/1f233.png differ diff --git a/emojis/1f234.png b/emojis/1f234.png new file mode 100644 index 00000000..2cd2d980 Binary files /dev/null and b/emojis/1f234.png differ diff --git a/emojis/1f235.png b/emojis/1f235.png new file mode 100644 index 00000000..82652e6c Binary files /dev/null and b/emojis/1f235.png differ diff --git a/emojis/1f236.png b/emojis/1f236.png new file mode 100644 index 00000000..172ef999 Binary files /dev/null and b/emojis/1f236.png differ diff --git a/emojis/1f237.png b/emojis/1f237.png new file mode 100644 index 00000000..4d8388f0 Binary files /dev/null and b/emojis/1f237.png differ diff --git a/emojis/1f238.png b/emojis/1f238.png new file mode 100644 index 00000000..356c6460 Binary files /dev/null and b/emojis/1f238.png differ diff --git a/emojis/1f239.png b/emojis/1f239.png new file mode 100644 index 00000000..a06ee803 Binary files /dev/null and b/emojis/1f239.png differ diff --git a/emojis/1f23a.png b/emojis/1f23a.png new file mode 100644 index 00000000..d011c055 Binary files /dev/null and b/emojis/1f23a.png differ diff --git a/emojis/1f250.png b/emojis/1f250.png new file mode 100644 index 00000000..875e6474 Binary files /dev/null and b/emojis/1f250.png differ diff --git a/emojis/1f251.png b/emojis/1f251.png new file mode 100644 index 00000000..d23ab77b Binary files /dev/null and b/emojis/1f251.png differ diff --git a/emojis/1f300.png b/emojis/1f300.png new file mode 100644 index 00000000..a4935a98 Binary files /dev/null and b/emojis/1f300.png differ diff --git a/emojis/1f301.png b/emojis/1f301.png new file mode 100644 index 00000000..0959db7c Binary files /dev/null and b/emojis/1f301.png differ diff --git a/emojis/1f302.png b/emojis/1f302.png new file mode 100644 index 00000000..9d2be1fa Binary files /dev/null and b/emojis/1f302.png differ diff --git a/emojis/1f303.png b/emojis/1f303.png new file mode 100644 index 00000000..d7397b55 Binary files /dev/null and b/emojis/1f303.png differ diff --git a/emojis/1f304.png b/emojis/1f304.png new file mode 100644 index 00000000..fdc62a87 Binary files /dev/null and b/emojis/1f304.png differ diff --git a/emojis/1f305.png b/emojis/1f305.png new file mode 100644 index 00000000..eb83dd99 Binary files /dev/null and b/emojis/1f305.png differ diff --git a/emojis/1f306.png b/emojis/1f306.png new file mode 100644 index 00000000..99572259 Binary files /dev/null and b/emojis/1f306.png differ diff --git a/emojis/1f307.png b/emojis/1f307.png new file mode 100644 index 00000000..377727d0 Binary files /dev/null and b/emojis/1f307.png differ diff --git a/emojis/1f308.png b/emojis/1f308.png new file mode 100644 index 00000000..ab59038c Binary files /dev/null and b/emojis/1f308.png differ diff --git a/emojis/1f309.png b/emojis/1f309.png new file mode 100644 index 00000000..62b1efd7 Binary files /dev/null and b/emojis/1f309.png differ diff --git a/emojis/1f30a.png b/emojis/1f30a.png new file mode 100644 index 00000000..466afeb6 Binary files /dev/null and b/emojis/1f30a.png differ diff --git a/emojis/1f30b.png b/emojis/1f30b.png new file mode 100644 index 00000000..c697714c Binary files /dev/null and b/emojis/1f30b.png differ diff --git a/emojis/1f30c.png b/emojis/1f30c.png new file mode 100644 index 00000000..9f79fe7f Binary files /dev/null and b/emojis/1f30c.png differ diff --git a/emojis/1f30d.png b/emojis/1f30d.png new file mode 100644 index 00000000..afdefecd Binary files /dev/null and b/emojis/1f30d.png differ diff --git a/emojis/1f30e.png b/emojis/1f30e.png new file mode 100644 index 00000000..b4371023 Binary files /dev/null and b/emojis/1f30e.png differ diff --git a/emojis/1f30f.png b/emojis/1f30f.png new file mode 100644 index 00000000..c557645e Binary files /dev/null and b/emojis/1f30f.png differ diff --git a/emojis/1f310.png b/emojis/1f310.png new file mode 100644 index 00000000..d890f6a1 Binary files /dev/null and b/emojis/1f310.png differ diff --git a/emojis/1f311.png b/emojis/1f311.png new file mode 100644 index 00000000..376435e4 Binary files /dev/null and b/emojis/1f311.png differ diff --git a/emojis/1f312.png b/emojis/1f312.png new file mode 100644 index 00000000..8a8e8eae Binary files /dev/null and b/emojis/1f312.png differ diff --git a/emojis/1f313.png b/emojis/1f313.png new file mode 100644 index 00000000..60493a47 Binary files /dev/null and b/emojis/1f313.png differ diff --git a/emojis/1f314.png b/emojis/1f314.png new file mode 100644 index 00000000..c43e16c1 Binary files /dev/null and b/emojis/1f314.png differ diff --git a/emojis/1f315.png b/emojis/1f315.png new file mode 100644 index 00000000..995ccf7c Binary files /dev/null and b/emojis/1f315.png differ diff --git a/emojis/1f316.png b/emojis/1f316.png new file mode 100644 index 00000000..0a14c1e0 Binary files /dev/null and b/emojis/1f316.png differ diff --git a/emojis/1f317.png b/emojis/1f317.png new file mode 100644 index 00000000..b5095e24 Binary files /dev/null and b/emojis/1f317.png differ diff --git a/emojis/1f318.png b/emojis/1f318.png new file mode 100644 index 00000000..14abe44a Binary files /dev/null and b/emojis/1f318.png differ diff --git a/emojis/1f319.png b/emojis/1f319.png new file mode 100644 index 00000000..169ce3d7 Binary files /dev/null and b/emojis/1f319.png differ diff --git a/emojis/1f31a.png b/emojis/1f31a.png new file mode 100644 index 00000000..44c9b5db Binary files /dev/null and b/emojis/1f31a.png differ diff --git a/emojis/1f31b.png b/emojis/1f31b.png new file mode 100644 index 00000000..69d7ae6f Binary files /dev/null and b/emojis/1f31b.png differ diff --git a/emojis/1f31c.png b/emojis/1f31c.png new file mode 100644 index 00000000..176cce28 Binary files /dev/null and b/emojis/1f31c.png differ diff --git a/emojis/1f31d.png b/emojis/1f31d.png new file mode 100644 index 00000000..ff73594b Binary files /dev/null and b/emojis/1f31d.png differ diff --git a/emojis/1f31e.png b/emojis/1f31e.png new file mode 100644 index 00000000..85df9bc4 Binary files /dev/null and b/emojis/1f31e.png differ diff --git a/emojis/1f31f.png b/emojis/1f31f.png new file mode 100644 index 00000000..78898cc0 Binary files /dev/null and b/emojis/1f31f.png differ diff --git a/emojis/1f320.png b/emojis/1f320.png new file mode 100644 index 00000000..84a6d159 Binary files /dev/null and b/emojis/1f320.png differ diff --git a/emojis/1f321.png b/emojis/1f321.png new file mode 100644 index 00000000..42ae0658 Binary files /dev/null and b/emojis/1f321.png differ diff --git a/emojis/1f324.png b/emojis/1f324.png new file mode 100644 index 00000000..1c374a5f Binary files /dev/null and b/emojis/1f324.png differ diff --git a/emojis/1f325.png b/emojis/1f325.png new file mode 100644 index 00000000..87f70797 Binary files /dev/null and b/emojis/1f325.png differ diff --git a/emojis/1f326.png b/emojis/1f326.png new file mode 100644 index 00000000..5fa89ded Binary files /dev/null and b/emojis/1f326.png differ diff --git a/emojis/1f327.png b/emojis/1f327.png new file mode 100644 index 00000000..51712964 Binary files /dev/null and b/emojis/1f327.png differ diff --git a/emojis/1f328.png b/emojis/1f328.png new file mode 100644 index 00000000..70010deb Binary files /dev/null and b/emojis/1f328.png differ diff --git a/emojis/1f329.png b/emojis/1f329.png new file mode 100644 index 00000000..cb08e47b Binary files /dev/null and b/emojis/1f329.png differ diff --git a/emojis/1f32a.png b/emojis/1f32a.png new file mode 100644 index 00000000..f87600b1 Binary files /dev/null and b/emojis/1f32a.png differ diff --git a/emojis/1f32b.png b/emojis/1f32b.png new file mode 100644 index 00000000..21b036fb Binary files /dev/null and b/emojis/1f32b.png differ diff --git a/emojis/1f32c.png b/emojis/1f32c.png new file mode 100644 index 00000000..67d1d70a Binary files /dev/null and b/emojis/1f32c.png differ diff --git a/emojis/1f32d.png b/emojis/1f32d.png new file mode 100644 index 00000000..f834ce46 Binary files /dev/null and b/emojis/1f32d.png differ diff --git a/emojis/1f32e.png b/emojis/1f32e.png new file mode 100644 index 00000000..c44b9318 Binary files /dev/null and b/emojis/1f32e.png differ diff --git a/emojis/1f32f.png b/emojis/1f32f.png new file mode 100644 index 00000000..0e7cde89 Binary files /dev/null and b/emojis/1f32f.png differ diff --git a/emojis/1f330.png b/emojis/1f330.png new file mode 100644 index 00000000..632f9e2a Binary files /dev/null and b/emojis/1f330.png differ diff --git a/emojis/1f331.png b/emojis/1f331.png new file mode 100644 index 00000000..51c2c92e Binary files /dev/null and b/emojis/1f331.png differ diff --git a/emojis/1f332.png b/emojis/1f332.png new file mode 100644 index 00000000..d1aebc43 Binary files /dev/null and b/emojis/1f332.png differ diff --git a/emojis/1f333.png b/emojis/1f333.png new file mode 100644 index 00000000..e7948a34 Binary files /dev/null and b/emojis/1f333.png differ diff --git a/emojis/1f334.png b/emojis/1f334.png new file mode 100644 index 00000000..f00a24bc Binary files /dev/null and b/emojis/1f334.png differ diff --git a/emojis/1f335.png b/emojis/1f335.png new file mode 100644 index 00000000..664ae7e7 Binary files /dev/null and b/emojis/1f335.png differ diff --git a/emojis/1f336.png b/emojis/1f336.png new file mode 100644 index 00000000..aec088d9 Binary files /dev/null and b/emojis/1f336.png differ diff --git a/emojis/1f337.png b/emojis/1f337.png new file mode 100644 index 00000000..a8ef0ce0 Binary files /dev/null and b/emojis/1f337.png differ diff --git a/emojis/1f338.png b/emojis/1f338.png new file mode 100644 index 00000000..82910117 Binary files /dev/null and b/emojis/1f338.png differ diff --git a/emojis/1f339.png b/emojis/1f339.png new file mode 100644 index 00000000..4c0f5b0b Binary files /dev/null and b/emojis/1f339.png differ diff --git a/emojis/1f33a.png b/emojis/1f33a.png new file mode 100644 index 00000000..27cc8b6f Binary files /dev/null and b/emojis/1f33a.png differ diff --git a/emojis/1f33b.png b/emojis/1f33b.png new file mode 100644 index 00000000..3bde2ad6 Binary files /dev/null and b/emojis/1f33b.png differ diff --git a/emojis/1f33c.png b/emojis/1f33c.png new file mode 100644 index 00000000..7d8f1e9d Binary files /dev/null and b/emojis/1f33c.png differ diff --git a/emojis/1f33d.png b/emojis/1f33d.png new file mode 100644 index 00000000..ae2bbe52 Binary files /dev/null and b/emojis/1f33d.png differ diff --git a/emojis/1f33e.png b/emojis/1f33e.png new file mode 100644 index 00000000..04a7fcd8 Binary files /dev/null and b/emojis/1f33e.png differ diff --git a/emojis/1f33f.png b/emojis/1f33f.png new file mode 100644 index 00000000..1ea9b400 Binary files /dev/null and b/emojis/1f33f.png differ diff --git a/emojis/1f340.png b/emojis/1f340.png new file mode 100644 index 00000000..54cb4a1c Binary files /dev/null and b/emojis/1f340.png differ diff --git a/emojis/1f341.png b/emojis/1f341.png new file mode 100644 index 00000000..6b9f4717 Binary files /dev/null and b/emojis/1f341.png differ diff --git a/emojis/1f342.png b/emojis/1f342.png new file mode 100644 index 00000000..4c5ed023 Binary files /dev/null and b/emojis/1f342.png differ diff --git a/emojis/1f343.png b/emojis/1f343.png new file mode 100644 index 00000000..70ede459 Binary files /dev/null and b/emojis/1f343.png differ diff --git a/emojis/1f344.png b/emojis/1f344.png new file mode 100644 index 00000000..8db9f0b8 Binary files /dev/null and b/emojis/1f344.png differ diff --git a/emojis/1f345.png b/emojis/1f345.png new file mode 100644 index 00000000..c90bd513 Binary files /dev/null and b/emojis/1f345.png differ diff --git a/emojis/1f346.png b/emojis/1f346.png new file mode 100644 index 00000000..ca69e7b8 Binary files /dev/null and b/emojis/1f346.png differ diff --git a/emojis/1f347.png b/emojis/1f347.png new file mode 100644 index 00000000..0c193db3 Binary files /dev/null and b/emojis/1f347.png differ diff --git a/emojis/1f348.png b/emojis/1f348.png new file mode 100644 index 00000000..98eb6336 Binary files /dev/null and b/emojis/1f348.png differ diff --git a/emojis/1f349.png b/emojis/1f349.png new file mode 100644 index 00000000..26417714 Binary files /dev/null and b/emojis/1f349.png differ diff --git a/emojis/1f34a.png b/emojis/1f34a.png new file mode 100644 index 00000000..590d80ad Binary files /dev/null and b/emojis/1f34a.png differ diff --git a/emojis/1f34b.png b/emojis/1f34b.png new file mode 100644 index 00000000..c61aad48 Binary files /dev/null and b/emojis/1f34b.png differ diff --git a/emojis/1f34c.png b/emojis/1f34c.png new file mode 100644 index 00000000..9d5793ff Binary files /dev/null and b/emojis/1f34c.png differ diff --git a/emojis/1f34d.png b/emojis/1f34d.png new file mode 100644 index 00000000..526f72cf Binary files /dev/null and b/emojis/1f34d.png differ diff --git a/emojis/1f34e.png b/emojis/1f34e.png new file mode 100644 index 00000000..a70cde15 Binary files /dev/null and b/emojis/1f34e.png differ diff --git a/emojis/1f34f.png b/emojis/1f34f.png new file mode 100644 index 00000000..e9fe7785 Binary files /dev/null and b/emojis/1f34f.png differ diff --git a/emojis/1f350.png b/emojis/1f350.png new file mode 100644 index 00000000..a4f11726 Binary files /dev/null and b/emojis/1f350.png differ diff --git a/emojis/1f351.png b/emojis/1f351.png new file mode 100644 index 00000000..2151ebac Binary files /dev/null and b/emojis/1f351.png differ diff --git a/emojis/1f352.png b/emojis/1f352.png new file mode 100644 index 00000000..4c81dccc Binary files /dev/null and b/emojis/1f352.png differ diff --git a/emojis/1f353.png b/emojis/1f353.png new file mode 100644 index 00000000..03d57e7b Binary files /dev/null and b/emojis/1f353.png differ diff --git a/emojis/1f354.png b/emojis/1f354.png new file mode 100644 index 00000000..5231bed1 Binary files /dev/null and b/emojis/1f354.png differ diff --git a/emojis/1f355.png b/emojis/1f355.png new file mode 100644 index 00000000..1f43782b Binary files /dev/null and b/emojis/1f355.png differ diff --git a/emojis/1f356.png b/emojis/1f356.png new file mode 100644 index 00000000..e7c8b7a2 Binary files /dev/null and b/emojis/1f356.png differ diff --git a/emojis/1f357.png b/emojis/1f357.png new file mode 100644 index 00000000..6924bdbc Binary files /dev/null and b/emojis/1f357.png differ diff --git a/emojis/1f358.png b/emojis/1f358.png new file mode 100644 index 00000000..7067fb72 Binary files /dev/null and b/emojis/1f358.png differ diff --git a/emojis/1f359.png b/emojis/1f359.png new file mode 100644 index 00000000..9a670d04 Binary files /dev/null and b/emojis/1f359.png differ diff --git a/emojis/1f35a.png b/emojis/1f35a.png new file mode 100644 index 00000000..d9e3d267 Binary files /dev/null and b/emojis/1f35a.png differ diff --git a/emojis/1f35b.png b/emojis/1f35b.png new file mode 100644 index 00000000..330c53f3 Binary files /dev/null and b/emojis/1f35b.png differ diff --git a/emojis/1f35c.png b/emojis/1f35c.png new file mode 100644 index 00000000..dd3a7349 Binary files /dev/null and b/emojis/1f35c.png differ diff --git a/emojis/1f35d.png b/emojis/1f35d.png new file mode 100644 index 00000000..ec2416e8 Binary files /dev/null and b/emojis/1f35d.png differ diff --git a/emojis/1f35e.png b/emojis/1f35e.png new file mode 100644 index 00000000..46331354 Binary files /dev/null and b/emojis/1f35e.png differ diff --git a/emojis/1f35f.png b/emojis/1f35f.png new file mode 100644 index 00000000..58c3cdd7 Binary files /dev/null and b/emojis/1f35f.png differ diff --git a/emojis/1f360.png b/emojis/1f360.png new file mode 100644 index 00000000..de9d9139 Binary files /dev/null and b/emojis/1f360.png differ diff --git a/emojis/1f361.png b/emojis/1f361.png new file mode 100644 index 00000000..3c476860 Binary files /dev/null and b/emojis/1f361.png differ diff --git a/emojis/1f362.png b/emojis/1f362.png new file mode 100644 index 00000000..607a8278 Binary files /dev/null and b/emojis/1f362.png differ diff --git a/emojis/1f363.png b/emojis/1f363.png new file mode 100644 index 00000000..84463e2c Binary files /dev/null and b/emojis/1f363.png differ diff --git a/emojis/1f364.png b/emojis/1f364.png new file mode 100644 index 00000000..d9b68b30 Binary files /dev/null and b/emojis/1f364.png differ diff --git a/emojis/1f365.png b/emojis/1f365.png new file mode 100644 index 00000000..fcb93b18 Binary files /dev/null and b/emojis/1f365.png differ diff --git a/emojis/1f366.png b/emojis/1f366.png new file mode 100644 index 00000000..c30a07cc Binary files /dev/null and b/emojis/1f366.png differ diff --git a/emojis/1f367.png b/emojis/1f367.png new file mode 100644 index 00000000..c284b4e4 Binary files /dev/null and b/emojis/1f367.png differ diff --git a/emojis/1f368.png b/emojis/1f368.png new file mode 100644 index 00000000..28d6fbb6 Binary files /dev/null and b/emojis/1f368.png differ diff --git a/emojis/1f369.png b/emojis/1f369.png new file mode 100644 index 00000000..4f9a2115 Binary files /dev/null and b/emojis/1f369.png differ diff --git a/emojis/1f36a.png b/emojis/1f36a.png new file mode 100644 index 00000000..9f9650c4 Binary files /dev/null and b/emojis/1f36a.png differ diff --git a/emojis/1f36b.png b/emojis/1f36b.png new file mode 100644 index 00000000..6981c442 Binary files /dev/null and b/emojis/1f36b.png differ diff --git a/emojis/1f36c.png b/emojis/1f36c.png new file mode 100644 index 00000000..a532ec49 Binary files /dev/null and b/emojis/1f36c.png differ diff --git a/emojis/1f36d.png b/emojis/1f36d.png new file mode 100644 index 00000000..7859036c Binary files /dev/null and b/emojis/1f36d.png differ diff --git a/emojis/1f36e.png b/emojis/1f36e.png new file mode 100644 index 00000000..40c6e740 Binary files /dev/null and b/emojis/1f36e.png differ diff --git a/emojis/1f36f.png b/emojis/1f36f.png new file mode 100644 index 00000000..2d3ea469 Binary files /dev/null and b/emojis/1f36f.png differ diff --git a/emojis/1f370.png b/emojis/1f370.png new file mode 100644 index 00000000..0d5c3563 Binary files /dev/null and b/emojis/1f370.png differ diff --git a/emojis/1f371.png b/emojis/1f371.png new file mode 100644 index 00000000..97a27f26 Binary files /dev/null and b/emojis/1f371.png differ diff --git a/emojis/1f372.png b/emojis/1f372.png new file mode 100644 index 00000000..09b220ee Binary files /dev/null and b/emojis/1f372.png differ diff --git a/emojis/1f373.png b/emojis/1f373.png new file mode 100644 index 00000000..a02cd3b5 Binary files /dev/null and b/emojis/1f373.png differ diff --git a/emojis/1f374.png b/emojis/1f374.png new file mode 100644 index 00000000..381eee18 Binary files /dev/null and b/emojis/1f374.png differ diff --git a/emojis/1f375.png b/emojis/1f375.png new file mode 100644 index 00000000..8a132568 Binary files /dev/null and b/emojis/1f375.png differ diff --git a/emojis/1f376.png b/emojis/1f376.png new file mode 100644 index 00000000..375a5975 Binary files /dev/null and b/emojis/1f376.png differ diff --git a/emojis/1f377.png b/emojis/1f377.png new file mode 100644 index 00000000..8c04a183 Binary files /dev/null and b/emojis/1f377.png differ diff --git a/emojis/1f378.png b/emojis/1f378.png new file mode 100644 index 00000000..c18dac4d Binary files /dev/null and b/emojis/1f378.png differ diff --git a/emojis/1f379.png b/emojis/1f379.png new file mode 100644 index 00000000..03217e27 Binary files /dev/null and b/emojis/1f379.png differ diff --git a/emojis/1f37a.png b/emojis/1f37a.png new file mode 100644 index 00000000..b98a026e Binary files /dev/null and b/emojis/1f37a.png differ diff --git a/emojis/1f37b.png b/emojis/1f37b.png new file mode 100644 index 00000000..161d7fde Binary files /dev/null and b/emojis/1f37b.png differ diff --git a/emojis/1f37c.png b/emojis/1f37c.png new file mode 100644 index 00000000..99b01c4c Binary files /dev/null and b/emojis/1f37c.png differ diff --git a/emojis/1f37d.png b/emojis/1f37d.png new file mode 100644 index 00000000..9e7c6de0 Binary files /dev/null and b/emojis/1f37d.png differ diff --git a/emojis/1f37e.png b/emojis/1f37e.png new file mode 100644 index 00000000..1ede0f4b Binary files /dev/null and b/emojis/1f37e.png differ diff --git a/emojis/1f37f.png b/emojis/1f37f.png new file mode 100644 index 00000000..1ffcd671 Binary files /dev/null and b/emojis/1f37f.png differ diff --git a/emojis/1f380.png b/emojis/1f380.png new file mode 100644 index 00000000..152348a0 Binary files /dev/null and b/emojis/1f380.png differ diff --git a/emojis/1f381.png b/emojis/1f381.png new file mode 100644 index 00000000..40ac1e50 Binary files /dev/null and b/emojis/1f381.png differ diff --git a/emojis/1f382.png b/emojis/1f382.png new file mode 100644 index 00000000..8b4dacd9 Binary files /dev/null and b/emojis/1f382.png differ diff --git a/emojis/1f383.png b/emojis/1f383.png new file mode 100644 index 00000000..31da8e62 Binary files /dev/null and b/emojis/1f383.png differ diff --git a/emojis/1f384.png b/emojis/1f384.png new file mode 100644 index 00000000..c758f4ff Binary files /dev/null and b/emojis/1f384.png differ diff --git a/emojis/1f385.png b/emojis/1f385.png new file mode 100644 index 00000000..4a4485a4 Binary files /dev/null and b/emojis/1f385.png differ diff --git a/emojis/1f386.png b/emojis/1f386.png new file mode 100644 index 00000000..43e7bda6 Binary files /dev/null and b/emojis/1f386.png differ diff --git a/emojis/1f387.png b/emojis/1f387.png new file mode 100644 index 00000000..623cb0b0 Binary files /dev/null and b/emojis/1f387.png differ diff --git a/emojis/1f388.png b/emojis/1f388.png new file mode 100644 index 00000000..ca775142 Binary files /dev/null and b/emojis/1f388.png differ diff --git a/emojis/1f389.png b/emojis/1f389.png new file mode 100644 index 00000000..c0e0234b Binary files /dev/null and b/emojis/1f389.png differ diff --git a/emojis/1f38a.png b/emojis/1f38a.png new file mode 100644 index 00000000..4d52260a Binary files /dev/null and b/emojis/1f38a.png differ diff --git a/emojis/1f38b.png b/emojis/1f38b.png new file mode 100644 index 00000000..fe353582 Binary files /dev/null and b/emojis/1f38b.png differ diff --git a/emojis/1f38c.png b/emojis/1f38c.png new file mode 100644 index 00000000..49886853 Binary files /dev/null and b/emojis/1f38c.png differ diff --git a/emojis/1f38d.png b/emojis/1f38d.png new file mode 100644 index 00000000..8369970b Binary files /dev/null and b/emojis/1f38d.png differ diff --git a/emojis/1f38e.png b/emojis/1f38e.png new file mode 100644 index 00000000..978ca843 Binary files /dev/null and b/emojis/1f38e.png differ diff --git a/emojis/1f38f.png b/emojis/1f38f.png new file mode 100644 index 00000000..c2b4aa46 Binary files /dev/null and b/emojis/1f38f.png differ diff --git a/emojis/1f390.png b/emojis/1f390.png new file mode 100644 index 00000000..912955f1 Binary files /dev/null and b/emojis/1f390.png differ diff --git a/emojis/1f391.png b/emojis/1f391.png new file mode 100644 index 00000000..5163e5ce Binary files /dev/null and b/emojis/1f391.png differ diff --git a/emojis/1f392.png b/emojis/1f392.png new file mode 100644 index 00000000..c2b6a443 Binary files /dev/null and b/emojis/1f392.png differ diff --git a/emojis/1f393.png b/emojis/1f393.png new file mode 100644 index 00000000..fe380c24 Binary files /dev/null and b/emojis/1f393.png differ diff --git a/emojis/1f396.png b/emojis/1f396.png new file mode 100644 index 00000000..5b1a3f66 Binary files /dev/null and b/emojis/1f396.png differ diff --git a/emojis/1f397.png b/emojis/1f397.png new file mode 100644 index 00000000..0c75838f Binary files /dev/null and b/emojis/1f397.png differ diff --git a/emojis/1f399.png b/emojis/1f399.png new file mode 100644 index 00000000..a9cf3323 Binary files /dev/null and b/emojis/1f399.png differ diff --git a/emojis/1f39a.png b/emojis/1f39a.png new file mode 100644 index 00000000..ae958370 Binary files /dev/null and b/emojis/1f39a.png differ diff --git a/emojis/1f39b.png b/emojis/1f39b.png new file mode 100644 index 00000000..c4992d91 Binary files /dev/null and b/emojis/1f39b.png differ diff --git a/emojis/1f39e.png b/emojis/1f39e.png new file mode 100644 index 00000000..39939745 Binary files /dev/null and b/emojis/1f39e.png differ diff --git a/emojis/1f39f.png b/emojis/1f39f.png new file mode 100644 index 00000000..9fa260f6 Binary files /dev/null and b/emojis/1f39f.png differ diff --git a/emojis/1f3a0.png b/emojis/1f3a0.png new file mode 100644 index 00000000..f2a17910 Binary files /dev/null and b/emojis/1f3a0.png differ diff --git a/emojis/1f3a1.png b/emojis/1f3a1.png new file mode 100644 index 00000000..4de439ad Binary files /dev/null and b/emojis/1f3a1.png differ diff --git a/emojis/1f3a2.png b/emojis/1f3a2.png new file mode 100644 index 00000000..776c56c8 Binary files /dev/null and b/emojis/1f3a2.png differ diff --git a/emojis/1f3a3.png b/emojis/1f3a3.png new file mode 100644 index 00000000..32f5e909 Binary files /dev/null and b/emojis/1f3a3.png differ diff --git a/emojis/1f3a4.png b/emojis/1f3a4.png new file mode 100644 index 00000000..726ff37a Binary files /dev/null and b/emojis/1f3a4.png differ diff --git a/emojis/1f3a5.png b/emojis/1f3a5.png new file mode 100644 index 00000000..5d49eac4 Binary files /dev/null and b/emojis/1f3a5.png differ diff --git a/emojis/1f3a6.png b/emojis/1f3a6.png new file mode 100644 index 00000000..291299e6 Binary files /dev/null and b/emojis/1f3a6.png differ diff --git a/emojis/1f3a7.png b/emojis/1f3a7.png new file mode 100644 index 00000000..3473aefc Binary files /dev/null and b/emojis/1f3a7.png differ diff --git a/emojis/1f3a8.png b/emojis/1f3a8.png new file mode 100644 index 00000000..59dc84e7 Binary files /dev/null and b/emojis/1f3a8.png differ diff --git a/emojis/1f3a9.png b/emojis/1f3a9.png new file mode 100644 index 00000000..00af7a7a Binary files /dev/null and b/emojis/1f3a9.png differ diff --git a/emojis/1f3aa.png b/emojis/1f3aa.png new file mode 100644 index 00000000..36b4d72b Binary files /dev/null and b/emojis/1f3aa.png differ diff --git a/emojis/1f3ab.png b/emojis/1f3ab.png new file mode 100644 index 00000000..b25d2fa0 Binary files /dev/null and b/emojis/1f3ab.png differ diff --git a/emojis/1f3ac.png b/emojis/1f3ac.png new file mode 100644 index 00000000..1ba9532c Binary files /dev/null and b/emojis/1f3ac.png differ diff --git a/emojis/1f3ad.png b/emojis/1f3ad.png new file mode 100644 index 00000000..8bd0b3b5 Binary files /dev/null and b/emojis/1f3ad.png differ diff --git a/emojis/1f3ae.png b/emojis/1f3ae.png new file mode 100644 index 00000000..70916d21 Binary files /dev/null and b/emojis/1f3ae.png differ diff --git a/emojis/1f3af.png b/emojis/1f3af.png new file mode 100644 index 00000000..81131f3f Binary files /dev/null and b/emojis/1f3af.png differ diff --git a/emojis/1f3b0.png b/emojis/1f3b0.png new file mode 100644 index 00000000..5ccddee5 Binary files /dev/null and b/emojis/1f3b0.png differ diff --git a/emojis/1f3b1.png b/emojis/1f3b1.png new file mode 100644 index 00000000..3fd1cc4b Binary files /dev/null and b/emojis/1f3b1.png differ diff --git a/emojis/1f3b2.png b/emojis/1f3b2.png new file mode 100644 index 00000000..3ba81637 Binary files /dev/null and b/emojis/1f3b2.png differ diff --git a/emojis/1f3b3.png b/emojis/1f3b3.png new file mode 100644 index 00000000..52ba4715 Binary files /dev/null and b/emojis/1f3b3.png differ diff --git a/emojis/1f3b4.png b/emojis/1f3b4.png new file mode 100644 index 00000000..6a7cd731 Binary files /dev/null and b/emojis/1f3b4.png differ diff --git a/emojis/1f3b5.png b/emojis/1f3b5.png new file mode 100644 index 00000000..317accfd Binary files /dev/null and b/emojis/1f3b5.png differ diff --git a/emojis/1f3b6.png b/emojis/1f3b6.png new file mode 100644 index 00000000..467c6e6e Binary files /dev/null and b/emojis/1f3b6.png differ diff --git a/emojis/1f3b7.png b/emojis/1f3b7.png new file mode 100644 index 00000000..bb629257 Binary files /dev/null and b/emojis/1f3b7.png differ diff --git a/emojis/1f3b8.png b/emojis/1f3b8.png new file mode 100644 index 00000000..9b9bd5ab Binary files /dev/null and b/emojis/1f3b8.png differ diff --git a/emojis/1f3b9.png b/emojis/1f3b9.png new file mode 100644 index 00000000..7633f868 Binary files /dev/null and b/emojis/1f3b9.png differ diff --git a/emojis/1f3ba.png b/emojis/1f3ba.png new file mode 100644 index 00000000..b4fcc879 Binary files /dev/null and b/emojis/1f3ba.png differ diff --git a/emojis/1f3bb.png b/emojis/1f3bb.png new file mode 100644 index 00000000..5b0fdc00 Binary files /dev/null and b/emojis/1f3bb.png differ diff --git a/emojis/1f3bc.png b/emojis/1f3bc.png new file mode 100644 index 00000000..fa2edfae Binary files /dev/null and b/emojis/1f3bc.png differ diff --git a/emojis/1f3bd.png b/emojis/1f3bd.png new file mode 100644 index 00000000..69112fba Binary files /dev/null and b/emojis/1f3bd.png differ diff --git a/emojis/1f3be.png b/emojis/1f3be.png new file mode 100644 index 00000000..51b45a03 Binary files /dev/null and b/emojis/1f3be.png differ diff --git a/emojis/1f3bf.png b/emojis/1f3bf.png new file mode 100644 index 00000000..353767e6 Binary files /dev/null and b/emojis/1f3bf.png differ diff --git a/emojis/1f3c0.png b/emojis/1f3c0.png new file mode 100644 index 00000000..c743018f Binary files /dev/null and b/emojis/1f3c0.png differ diff --git a/emojis/1f3c1.png b/emojis/1f3c1.png new file mode 100644 index 00000000..b497b495 Binary files /dev/null and b/emojis/1f3c1.png differ diff --git a/emojis/1f3c2.png b/emojis/1f3c2.png new file mode 100644 index 00000000..d61994a5 Binary files /dev/null and b/emojis/1f3c2.png differ diff --git a/emojis/1f3c3.png b/emojis/1f3c3.png new file mode 100644 index 00000000..fd7ce435 Binary files /dev/null and b/emojis/1f3c3.png differ diff --git a/emojis/1f3c4.png b/emojis/1f3c4.png new file mode 100644 index 00000000..f05801c7 Binary files /dev/null and b/emojis/1f3c4.png differ diff --git a/emojis/1f3c5.png b/emojis/1f3c5.png new file mode 100644 index 00000000..775d93ed Binary files /dev/null and b/emojis/1f3c5.png differ diff --git a/emojis/1f3c6.png b/emojis/1f3c6.png new file mode 100644 index 00000000..7ce831af Binary files /dev/null and b/emojis/1f3c6.png differ diff --git a/emojis/1f3c7.png b/emojis/1f3c7.png new file mode 100644 index 00000000..d170130a Binary files /dev/null and b/emojis/1f3c7.png differ diff --git a/emojis/1f3c8.png b/emojis/1f3c8.png new file mode 100644 index 00000000..bcaa9827 Binary files /dev/null and b/emojis/1f3c8.png differ diff --git a/emojis/1f3c9.png b/emojis/1f3c9.png new file mode 100644 index 00000000..972757aa Binary files /dev/null and b/emojis/1f3c9.png differ diff --git a/emojis/1f3ca.png b/emojis/1f3ca.png new file mode 100644 index 00000000..616ee3d2 Binary files /dev/null and b/emojis/1f3ca.png differ diff --git a/emojis/1f3cb.png b/emojis/1f3cb.png new file mode 100644 index 00000000..90384ba8 Binary files /dev/null and b/emojis/1f3cb.png differ diff --git a/emojis/1f3cc.png b/emojis/1f3cc.png new file mode 100644 index 00000000..f3a744bd Binary files /dev/null and b/emojis/1f3cc.png differ diff --git a/emojis/1f3cd.png b/emojis/1f3cd.png new file mode 100644 index 00000000..7cc7a338 Binary files /dev/null and b/emojis/1f3cd.png differ diff --git a/emojis/1f3ce.png b/emojis/1f3ce.png new file mode 100644 index 00000000..5bc5f990 Binary files /dev/null and b/emojis/1f3ce.png differ diff --git a/emojis/1f3cf.png b/emojis/1f3cf.png new file mode 100644 index 00000000..a3bafefd Binary files /dev/null and b/emojis/1f3cf.png differ diff --git a/emojis/1f3d0.png b/emojis/1f3d0.png new file mode 100644 index 00000000..46bc628a Binary files /dev/null and b/emojis/1f3d0.png differ diff --git a/emojis/1f3d1.png b/emojis/1f3d1.png new file mode 100644 index 00000000..f2388391 Binary files /dev/null and b/emojis/1f3d1.png differ diff --git a/emojis/1f3d2.png b/emojis/1f3d2.png new file mode 100644 index 00000000..70abff04 Binary files /dev/null and b/emojis/1f3d2.png differ diff --git a/emojis/1f3d3.png b/emojis/1f3d3.png new file mode 100644 index 00000000..a5323e26 Binary files /dev/null and b/emojis/1f3d3.png differ diff --git a/emojis/1f3d4.png b/emojis/1f3d4.png new file mode 100644 index 00000000..b2fbdccb Binary files /dev/null and b/emojis/1f3d4.png differ diff --git a/emojis/1f3d5.png b/emojis/1f3d5.png new file mode 100644 index 00000000..51841c57 Binary files /dev/null and b/emojis/1f3d5.png differ diff --git a/emojis/1f3d6.png b/emojis/1f3d6.png new file mode 100644 index 00000000..7ea70066 Binary files /dev/null and b/emojis/1f3d6.png differ diff --git a/emojis/1f3d7.png b/emojis/1f3d7.png new file mode 100644 index 00000000..3494cf87 Binary files /dev/null and b/emojis/1f3d7.png differ diff --git a/emojis/1f3d8.png b/emojis/1f3d8.png new file mode 100644 index 00000000..f477d9b3 Binary files /dev/null and b/emojis/1f3d8.png differ diff --git a/emojis/1f3d9.png b/emojis/1f3d9.png new file mode 100644 index 00000000..faff16fe Binary files /dev/null and b/emojis/1f3d9.png differ diff --git a/emojis/1f3da.png b/emojis/1f3da.png new file mode 100644 index 00000000..d036029e Binary files /dev/null and b/emojis/1f3da.png differ diff --git a/emojis/1f3db.png b/emojis/1f3db.png new file mode 100644 index 00000000..036d4dde Binary files /dev/null and b/emojis/1f3db.png differ diff --git a/emojis/1f3dc.png b/emojis/1f3dc.png new file mode 100644 index 00000000..fa4a937a Binary files /dev/null and b/emojis/1f3dc.png differ diff --git a/emojis/1f3dd.png b/emojis/1f3dd.png new file mode 100644 index 00000000..48555994 Binary files /dev/null and b/emojis/1f3dd.png differ diff --git a/emojis/1f3de.png b/emojis/1f3de.png new file mode 100644 index 00000000..776c2850 Binary files /dev/null and b/emojis/1f3de.png differ diff --git a/emojis/1f3df.png b/emojis/1f3df.png new file mode 100644 index 00000000..2e72fb17 Binary files /dev/null and b/emojis/1f3df.png differ diff --git a/emojis/1f3e0.png b/emojis/1f3e0.png new file mode 100644 index 00000000..e9963c28 Binary files /dev/null and b/emojis/1f3e0.png differ diff --git a/emojis/1f3e1.png b/emojis/1f3e1.png new file mode 100644 index 00000000..923af654 Binary files /dev/null and b/emojis/1f3e1.png differ diff --git a/emojis/1f3e2.png b/emojis/1f3e2.png new file mode 100644 index 00000000..3fcc0461 Binary files /dev/null and b/emojis/1f3e2.png differ diff --git a/emojis/1f3e3.png b/emojis/1f3e3.png new file mode 100644 index 00000000..c644e6af Binary files /dev/null and b/emojis/1f3e3.png differ diff --git a/emojis/1f3e4.png b/emojis/1f3e4.png new file mode 100644 index 00000000..13e1a4d3 Binary files /dev/null and b/emojis/1f3e4.png differ diff --git a/emojis/1f3e5.png b/emojis/1f3e5.png new file mode 100644 index 00000000..b3c7d1ea Binary files /dev/null and b/emojis/1f3e5.png differ diff --git a/emojis/1f3e6.png b/emojis/1f3e6.png new file mode 100644 index 00000000..fa5aa7eb Binary files /dev/null and b/emojis/1f3e6.png differ diff --git a/emojis/1f3e7.png b/emojis/1f3e7.png new file mode 100644 index 00000000..04eee2db Binary files /dev/null and b/emojis/1f3e7.png differ diff --git a/emojis/1f3e8.png b/emojis/1f3e8.png new file mode 100644 index 00000000..955dc23b Binary files /dev/null and b/emojis/1f3e8.png differ diff --git a/emojis/1f3e9.png b/emojis/1f3e9.png new file mode 100644 index 00000000..3b00df21 Binary files /dev/null and b/emojis/1f3e9.png differ diff --git a/emojis/1f3ea.png b/emojis/1f3ea.png new file mode 100644 index 00000000..8b36db91 Binary files /dev/null and b/emojis/1f3ea.png differ diff --git a/emojis/1f3eb.png b/emojis/1f3eb.png new file mode 100644 index 00000000..338702a1 Binary files /dev/null and b/emojis/1f3eb.png differ diff --git a/emojis/1f3ec.png b/emojis/1f3ec.png new file mode 100644 index 00000000..99c6f8b1 Binary files /dev/null and b/emojis/1f3ec.png differ diff --git a/emojis/1f3ed.png b/emojis/1f3ed.png new file mode 100644 index 00000000..2ae0b10d Binary files /dev/null and b/emojis/1f3ed.png differ diff --git a/emojis/1f3ee.png b/emojis/1f3ee.png new file mode 100644 index 00000000..82f8b2db Binary files /dev/null and b/emojis/1f3ee.png differ diff --git a/emojis/1f3ef.png b/emojis/1f3ef.png new file mode 100644 index 00000000..4f4c0401 Binary files /dev/null and b/emojis/1f3ef.png differ diff --git a/emojis/1f3f0.png b/emojis/1f3f0.png new file mode 100644 index 00000000..90b60e9c Binary files /dev/null and b/emojis/1f3f0.png differ diff --git a/emojis/1f3f3.png b/emojis/1f3f3.png new file mode 100644 index 00000000..0acfd4cf Binary files /dev/null and b/emojis/1f3f3.png differ diff --git a/emojis/1f3f4.png b/emojis/1f3f4.png new file mode 100644 index 00000000..88631b0e Binary files /dev/null and b/emojis/1f3f4.png differ diff --git a/emojis/1f3f5.png b/emojis/1f3f5.png new file mode 100644 index 00000000..87e29815 Binary files /dev/null and b/emojis/1f3f5.png differ diff --git a/emojis/1f3f7.png b/emojis/1f3f7.png new file mode 100644 index 00000000..7b105684 Binary files /dev/null and b/emojis/1f3f7.png differ diff --git a/emojis/1f3f8.png b/emojis/1f3f8.png new file mode 100644 index 00000000..1179a419 Binary files /dev/null and b/emojis/1f3f8.png differ diff --git a/emojis/1f3f9.png b/emojis/1f3f9.png new file mode 100644 index 00000000..890d56f1 Binary files /dev/null and b/emojis/1f3f9.png differ diff --git a/emojis/1f3fa.png b/emojis/1f3fa.png new file mode 100644 index 00000000..3a128cf7 Binary files /dev/null and b/emojis/1f3fa.png differ diff --git a/emojis/1f3fb.png b/emojis/1f3fb.png new file mode 100644 index 00000000..eff586e8 Binary files /dev/null and b/emojis/1f3fb.png differ diff --git a/emojis/1f3fc.png b/emojis/1f3fc.png new file mode 100644 index 00000000..4132ae87 Binary files /dev/null and b/emojis/1f3fc.png differ diff --git a/emojis/1f3fd.png b/emojis/1f3fd.png new file mode 100644 index 00000000..eb8a7c2e Binary files /dev/null and b/emojis/1f3fd.png differ diff --git a/emojis/1f3fe.png b/emojis/1f3fe.png new file mode 100644 index 00000000..91abd3e4 Binary files /dev/null and b/emojis/1f3fe.png differ diff --git a/emojis/1f3ff.png b/emojis/1f3ff.png new file mode 100644 index 00000000..a74d7093 Binary files /dev/null and b/emojis/1f3ff.png differ diff --git a/emojis/1f400.png b/emojis/1f400.png new file mode 100644 index 00000000..8d030df5 Binary files /dev/null and b/emojis/1f400.png differ diff --git a/emojis/1f401.png b/emojis/1f401.png new file mode 100644 index 00000000..3ee08d2a Binary files /dev/null and b/emojis/1f401.png differ diff --git a/emojis/1f402.png b/emojis/1f402.png new file mode 100644 index 00000000..ca7e2ae2 Binary files /dev/null and b/emojis/1f402.png differ diff --git a/emojis/1f403.png b/emojis/1f403.png new file mode 100644 index 00000000..995064e5 Binary files /dev/null and b/emojis/1f403.png differ diff --git a/emojis/1f404.png b/emojis/1f404.png new file mode 100644 index 00000000..f2c239f6 Binary files /dev/null and b/emojis/1f404.png differ diff --git a/emojis/1f405.png b/emojis/1f405.png new file mode 100644 index 00000000..df7e9001 Binary files /dev/null and b/emojis/1f405.png differ diff --git a/emojis/1f406.png b/emojis/1f406.png new file mode 100644 index 00000000..901ae6d7 Binary files /dev/null and b/emojis/1f406.png differ diff --git a/emojis/1f407.png b/emojis/1f407.png new file mode 100644 index 00000000..7494da23 Binary files /dev/null and b/emojis/1f407.png differ diff --git a/emojis/1f408.png b/emojis/1f408.png new file mode 100644 index 00000000..5ab22aef Binary files /dev/null and b/emojis/1f408.png differ diff --git a/emojis/1f409.png b/emojis/1f409.png new file mode 100644 index 00000000..a8865276 Binary files /dev/null and b/emojis/1f409.png differ diff --git a/emojis/1f40a.png b/emojis/1f40a.png new file mode 100644 index 00000000..191d874d Binary files /dev/null and b/emojis/1f40a.png differ diff --git a/emojis/1f40b.png b/emojis/1f40b.png new file mode 100644 index 00000000..4d1d09b5 Binary files /dev/null and b/emojis/1f40b.png differ diff --git a/emojis/1f40c.png b/emojis/1f40c.png new file mode 100644 index 00000000..ea715ca1 Binary files /dev/null and b/emojis/1f40c.png differ diff --git a/emojis/1f40d.png b/emojis/1f40d.png new file mode 100644 index 00000000..f710c380 Binary files /dev/null and b/emojis/1f40d.png differ diff --git a/emojis/1f40e.png b/emojis/1f40e.png new file mode 100644 index 00000000..3b640e30 Binary files /dev/null and b/emojis/1f40e.png differ diff --git a/emojis/1f40f.png b/emojis/1f40f.png new file mode 100644 index 00000000..1c405852 Binary files /dev/null and b/emojis/1f40f.png differ diff --git a/emojis/1f410.png b/emojis/1f410.png new file mode 100644 index 00000000..9867fc5f Binary files /dev/null and b/emojis/1f410.png differ diff --git a/emojis/1f411.png b/emojis/1f411.png new file mode 100644 index 00000000..539c024d Binary files /dev/null and b/emojis/1f411.png differ diff --git a/emojis/1f412.png b/emojis/1f412.png new file mode 100644 index 00000000..e4a69006 Binary files /dev/null and b/emojis/1f412.png differ diff --git a/emojis/1f413.png b/emojis/1f413.png new file mode 100644 index 00000000..6a1e1b9d Binary files /dev/null and b/emojis/1f413.png differ diff --git a/emojis/1f414.png b/emojis/1f414.png new file mode 100644 index 00000000..aa2c1dd1 Binary files /dev/null and b/emojis/1f414.png differ diff --git a/emojis/1f415.png b/emojis/1f415.png new file mode 100644 index 00000000..707298c4 Binary files /dev/null and b/emojis/1f415.png differ diff --git a/emojis/1f416.png b/emojis/1f416.png new file mode 100644 index 00000000..cc7ae2e3 Binary files /dev/null and b/emojis/1f416.png differ diff --git a/emojis/1f417.png b/emojis/1f417.png new file mode 100644 index 00000000..fa588872 Binary files /dev/null and b/emojis/1f417.png differ diff --git a/emojis/1f418.png b/emojis/1f418.png new file mode 100644 index 00000000..dfaf4254 Binary files /dev/null and b/emojis/1f418.png differ diff --git a/emojis/1f419.png b/emojis/1f419.png new file mode 100644 index 00000000..9bd26fa8 Binary files /dev/null and b/emojis/1f419.png differ diff --git a/emojis/1f41a.png b/emojis/1f41a.png new file mode 100644 index 00000000..aab26309 Binary files /dev/null and b/emojis/1f41a.png differ diff --git a/emojis/1f41b.png b/emojis/1f41b.png new file mode 100644 index 00000000..e19daab6 Binary files /dev/null and b/emojis/1f41b.png differ diff --git a/emojis/1f41c.png b/emojis/1f41c.png new file mode 100644 index 00000000..7c9ff9cd Binary files /dev/null and b/emojis/1f41c.png differ diff --git a/emojis/1f41d.png b/emojis/1f41d.png new file mode 100644 index 00000000..f26766c0 Binary files /dev/null and b/emojis/1f41d.png differ diff --git a/emojis/1f41e.png b/emojis/1f41e.png new file mode 100644 index 00000000..2401b69b Binary files /dev/null and b/emojis/1f41e.png differ diff --git a/emojis/1f41f.png b/emojis/1f41f.png new file mode 100644 index 00000000..412bbb16 Binary files /dev/null and b/emojis/1f41f.png differ diff --git a/emojis/1f420.png b/emojis/1f420.png new file mode 100644 index 00000000..2d420222 Binary files /dev/null and b/emojis/1f420.png differ diff --git a/emojis/1f421.png b/emojis/1f421.png new file mode 100644 index 00000000..7a2e2dcd Binary files /dev/null and b/emojis/1f421.png differ diff --git a/emojis/1f422.png b/emojis/1f422.png new file mode 100644 index 00000000..fdeecd1b Binary files /dev/null and b/emojis/1f422.png differ diff --git a/emojis/1f423.png b/emojis/1f423.png new file mode 100644 index 00000000..9e08fec9 Binary files /dev/null and b/emojis/1f423.png differ diff --git a/emojis/1f424.png b/emojis/1f424.png new file mode 100644 index 00000000..17fa07fc Binary files /dev/null and b/emojis/1f424.png differ diff --git a/emojis/1f425.png b/emojis/1f425.png new file mode 100644 index 00000000..dc73a9c7 Binary files /dev/null and b/emojis/1f425.png differ diff --git a/emojis/1f426.png b/emojis/1f426.png new file mode 100644 index 00000000..dc5c6294 Binary files /dev/null and b/emojis/1f426.png differ diff --git a/emojis/1f427.png b/emojis/1f427.png new file mode 100644 index 00000000..c5233dc8 Binary files /dev/null and b/emojis/1f427.png differ diff --git a/emojis/1f428.png b/emojis/1f428.png new file mode 100644 index 00000000..fe0dd5f7 Binary files /dev/null and b/emojis/1f428.png differ diff --git a/emojis/1f429.png b/emojis/1f429.png new file mode 100644 index 00000000..f3d92335 Binary files /dev/null and b/emojis/1f429.png differ diff --git a/emojis/1f42a.png b/emojis/1f42a.png new file mode 100644 index 00000000..25cf8ab7 Binary files /dev/null and b/emojis/1f42a.png differ diff --git a/emojis/1f42b.png b/emojis/1f42b.png new file mode 100644 index 00000000..a5aa04b3 Binary files /dev/null and b/emojis/1f42b.png differ diff --git a/emojis/1f42c.png b/emojis/1f42c.png new file mode 100644 index 00000000..341ca4ad Binary files /dev/null and b/emojis/1f42c.png differ diff --git a/emojis/1f42d.png b/emojis/1f42d.png new file mode 100644 index 00000000..89e25dc2 Binary files /dev/null and b/emojis/1f42d.png differ diff --git a/emojis/1f42e.png b/emojis/1f42e.png new file mode 100644 index 00000000..369f357d Binary files /dev/null and b/emojis/1f42e.png differ diff --git a/emojis/1f42f.png b/emojis/1f42f.png new file mode 100644 index 00000000..2bb5d8c2 Binary files /dev/null and b/emojis/1f42f.png differ diff --git a/emojis/1f430.png b/emojis/1f430.png new file mode 100644 index 00000000..175b1aba Binary files /dev/null and b/emojis/1f430.png differ diff --git a/emojis/1f431.png b/emojis/1f431.png new file mode 100644 index 00000000..3bdb9972 Binary files /dev/null and b/emojis/1f431.png differ diff --git a/emojis/1f432.png b/emojis/1f432.png new file mode 100644 index 00000000..a78c7b20 Binary files /dev/null and b/emojis/1f432.png differ diff --git a/emojis/1f433.png b/emojis/1f433.png new file mode 100644 index 00000000..df4080dc Binary files /dev/null and b/emojis/1f433.png differ diff --git a/emojis/1f434.png b/emojis/1f434.png new file mode 100644 index 00000000..b3c4aa4d Binary files /dev/null and b/emojis/1f434.png differ diff --git a/emojis/1f435.png b/emojis/1f435.png new file mode 100644 index 00000000..52e4d811 Binary files /dev/null and b/emojis/1f435.png differ diff --git a/emojis/1f436.png b/emojis/1f436.png new file mode 100644 index 00000000..3d21c7fc Binary files /dev/null and b/emojis/1f436.png differ diff --git a/emojis/1f437.png b/emojis/1f437.png new file mode 100644 index 00000000..416aa5d7 Binary files /dev/null and b/emojis/1f437.png differ diff --git a/emojis/1f438.png b/emojis/1f438.png new file mode 100644 index 00000000..83ce21ea Binary files /dev/null and b/emojis/1f438.png differ diff --git a/emojis/1f439.png b/emojis/1f439.png new file mode 100644 index 00000000..3b1dd2cf Binary files /dev/null and b/emojis/1f439.png differ diff --git a/emojis/1f43a.png b/emojis/1f43a.png new file mode 100644 index 00000000..1291eee8 Binary files /dev/null and b/emojis/1f43a.png differ diff --git a/emojis/1f43b.png b/emojis/1f43b.png new file mode 100644 index 00000000..98fbf70f Binary files /dev/null and b/emojis/1f43b.png differ diff --git a/emojis/1f43c.png b/emojis/1f43c.png new file mode 100644 index 00000000..16bb947e Binary files /dev/null and b/emojis/1f43c.png differ diff --git a/emojis/1f43d.png b/emojis/1f43d.png new file mode 100644 index 00000000..2723d5e7 Binary files /dev/null and b/emojis/1f43d.png differ diff --git a/emojis/1f43e.png b/emojis/1f43e.png new file mode 100644 index 00000000..4eb4b11e Binary files /dev/null and b/emojis/1f43e.png differ diff --git a/emojis/1f43f.png b/emojis/1f43f.png new file mode 100644 index 00000000..667fc5fc Binary files /dev/null and b/emojis/1f43f.png differ diff --git a/emojis/1f440.png b/emojis/1f440.png new file mode 100644 index 00000000..a2656738 Binary files /dev/null and b/emojis/1f440.png differ diff --git a/emojis/1f441.png b/emojis/1f441.png new file mode 100644 index 00000000..6a460d2b Binary files /dev/null and b/emojis/1f441.png differ diff --git a/emojis/1f442.png b/emojis/1f442.png new file mode 100644 index 00000000..15158d25 Binary files /dev/null and b/emojis/1f442.png differ diff --git a/emojis/1f443.png b/emojis/1f443.png new file mode 100644 index 00000000..5e004410 Binary files /dev/null and b/emojis/1f443.png differ diff --git a/emojis/1f444.png b/emojis/1f444.png new file mode 100644 index 00000000..ea5cc01a Binary files /dev/null and b/emojis/1f444.png differ diff --git a/emojis/1f445.png b/emojis/1f445.png new file mode 100644 index 00000000..0b348665 Binary files /dev/null and b/emojis/1f445.png differ diff --git a/emojis/1f446.png b/emojis/1f446.png new file mode 100644 index 00000000..39865d71 Binary files /dev/null and b/emojis/1f446.png differ diff --git a/emojis/1f447.png b/emojis/1f447.png new file mode 100644 index 00000000..186b79a8 Binary files /dev/null and b/emojis/1f447.png differ diff --git a/emojis/1f448.png b/emojis/1f448.png new file mode 100644 index 00000000..b9c08208 Binary files /dev/null and b/emojis/1f448.png differ diff --git a/emojis/1f449.png b/emojis/1f449.png new file mode 100644 index 00000000..2d1ac932 Binary files /dev/null and b/emojis/1f449.png differ diff --git a/emojis/1f44a.png b/emojis/1f44a.png new file mode 100644 index 00000000..a4ae5b29 Binary files /dev/null and b/emojis/1f44a.png differ diff --git a/emojis/1f44b.png b/emojis/1f44b.png new file mode 100644 index 00000000..e4a09d72 Binary files /dev/null and b/emojis/1f44b.png differ diff --git a/emojis/1f44c.png b/emojis/1f44c.png new file mode 100644 index 00000000..c2690631 Binary files /dev/null and b/emojis/1f44c.png differ diff --git a/emojis/1f44d.png b/emojis/1f44d.png new file mode 100644 index 00000000..66f41b44 Binary files /dev/null and b/emojis/1f44d.png differ diff --git a/emojis/1f44e.png b/emojis/1f44e.png new file mode 100644 index 00000000..738a67cc Binary files /dev/null and b/emojis/1f44e.png differ diff --git a/emojis/1f44f.png b/emojis/1f44f.png new file mode 100644 index 00000000..2051be03 Binary files /dev/null and b/emojis/1f44f.png differ diff --git a/emojis/1f450.png b/emojis/1f450.png new file mode 100644 index 00000000..3cb8896e Binary files /dev/null and b/emojis/1f450.png differ diff --git a/emojis/1f451.png b/emojis/1f451.png new file mode 100644 index 00000000..9ef877af Binary files /dev/null and b/emojis/1f451.png differ diff --git a/emojis/1f452.png b/emojis/1f452.png new file mode 100644 index 00000000..8b88825f Binary files /dev/null and b/emojis/1f452.png differ diff --git a/emojis/1f453.png b/emojis/1f453.png new file mode 100644 index 00000000..8a898067 Binary files /dev/null and b/emojis/1f453.png differ diff --git a/emojis/1f454.png b/emojis/1f454.png new file mode 100644 index 00000000..2ef0bf05 Binary files /dev/null and b/emojis/1f454.png differ diff --git a/emojis/1f455.png b/emojis/1f455.png new file mode 100644 index 00000000..151f87d1 Binary files /dev/null and b/emojis/1f455.png differ diff --git a/emojis/1f456.png b/emojis/1f456.png new file mode 100644 index 00000000..d69d74ab Binary files /dev/null and b/emojis/1f456.png differ diff --git a/emojis/1f457.png b/emojis/1f457.png new file mode 100644 index 00000000..9fa12a00 Binary files /dev/null and b/emojis/1f457.png differ diff --git a/emojis/1f458.png b/emojis/1f458.png new file mode 100644 index 00000000..059c68df Binary files /dev/null and b/emojis/1f458.png differ diff --git a/emojis/1f459.png b/emojis/1f459.png new file mode 100644 index 00000000..37326c10 Binary files /dev/null and b/emojis/1f459.png differ diff --git a/emojis/1f45a.png b/emojis/1f45a.png new file mode 100644 index 00000000..c0f8d38b Binary files /dev/null and b/emojis/1f45a.png differ diff --git a/emojis/1f45b.png b/emojis/1f45b.png new file mode 100644 index 00000000..6e38ee5d Binary files /dev/null and b/emojis/1f45b.png differ diff --git a/emojis/1f45c.png b/emojis/1f45c.png new file mode 100644 index 00000000..35b75737 Binary files /dev/null and b/emojis/1f45c.png differ diff --git a/emojis/1f45d.png b/emojis/1f45d.png new file mode 100644 index 00000000..0157070a Binary files /dev/null and b/emojis/1f45d.png differ diff --git a/emojis/1f45e.png b/emojis/1f45e.png new file mode 100644 index 00000000..a1a742e5 Binary files /dev/null and b/emojis/1f45e.png differ diff --git a/emojis/1f45f.png b/emojis/1f45f.png new file mode 100644 index 00000000..bacfc115 Binary files /dev/null and b/emojis/1f45f.png differ diff --git a/emojis/1f460.png b/emojis/1f460.png new file mode 100644 index 00000000..5035f773 Binary files /dev/null and b/emojis/1f460.png differ diff --git a/emojis/1f461.png b/emojis/1f461.png new file mode 100644 index 00000000..d52c231b Binary files /dev/null and b/emojis/1f461.png differ diff --git a/emojis/1f462.png b/emojis/1f462.png new file mode 100644 index 00000000..843f16eb Binary files /dev/null and b/emojis/1f462.png differ diff --git a/emojis/1f463.png b/emojis/1f463.png new file mode 100644 index 00000000..0a654e9f Binary files /dev/null and b/emojis/1f463.png differ diff --git a/emojis/1f464.png b/emojis/1f464.png new file mode 100644 index 00000000..72a1a15f Binary files /dev/null and b/emojis/1f464.png differ diff --git a/emojis/1f465.png b/emojis/1f465.png new file mode 100644 index 00000000..5dd5c388 Binary files /dev/null and b/emojis/1f465.png differ diff --git a/emojis/1f466.png b/emojis/1f466.png new file mode 100644 index 00000000..04f6707a Binary files /dev/null and b/emojis/1f466.png differ diff --git a/emojis/1f467.png b/emojis/1f467.png new file mode 100644 index 00000000..91ac83cf Binary files /dev/null and b/emojis/1f467.png differ diff --git a/emojis/1f468-200d-1f468-200d-1f466-200d-1f466.png b/emojis/1f468-200d-1f468-200d-1f466-200d-1f466.png new file mode 100644 index 00000000..309a9ba3 Binary files /dev/null and b/emojis/1f468-200d-1f468-200d-1f466-200d-1f466.png differ diff --git a/emojis/1f468-200d-1f468-200d-1f466.png b/emojis/1f468-200d-1f468-200d-1f466.png new file mode 100644 index 00000000..4c1de049 Binary files /dev/null and b/emojis/1f468-200d-1f468-200d-1f466.png differ diff --git a/emojis/1f468-200d-1f468-200d-1f467-200d-1f466.png b/emojis/1f468-200d-1f468-200d-1f467-200d-1f466.png new file mode 100644 index 00000000..562dba71 Binary files /dev/null and b/emojis/1f468-200d-1f468-200d-1f467-200d-1f466.png differ diff --git a/emojis/1f468-200d-1f468-200d-1f467-200d-1f467.png b/emojis/1f468-200d-1f468-200d-1f467-200d-1f467.png new file mode 100644 index 00000000..de2a626b Binary files /dev/null and b/emojis/1f468-200d-1f468-200d-1f467-200d-1f467.png differ diff --git a/emojis/1f468-200d-1f468-200d-1f467.png b/emojis/1f468-200d-1f468-200d-1f467.png new file mode 100644 index 00000000..4a111dd4 Binary files /dev/null and b/emojis/1f468-200d-1f468-200d-1f467.png differ diff --git a/emojis/1f468-200d-1f469-200d-1f466-200d-1f466.png b/emojis/1f468-200d-1f469-200d-1f466-200d-1f466.png new file mode 100644 index 00000000..c4ae16b9 Binary files /dev/null and b/emojis/1f468-200d-1f469-200d-1f466-200d-1f466.png differ diff --git a/emojis/1f468-200d-1f469-200d-1f467-200d-1f466.png b/emojis/1f468-200d-1f469-200d-1f467-200d-1f466.png new file mode 100644 index 00000000..45346941 Binary files /dev/null and b/emojis/1f468-200d-1f469-200d-1f467-200d-1f466.png differ diff --git a/emojis/1f468-200d-1f469-200d-1f467-200d-1f467.png b/emojis/1f468-200d-1f469-200d-1f467-200d-1f467.png new file mode 100644 index 00000000..ec303847 Binary files /dev/null and b/emojis/1f468-200d-1f469-200d-1f467-200d-1f467.png differ diff --git a/emojis/1f468-200d-1f469-200d-1f467.png b/emojis/1f468-200d-1f469-200d-1f467.png new file mode 100644 index 00000000..dbbc5d81 Binary files /dev/null and b/emojis/1f468-200d-1f469-200d-1f467.png differ diff --git a/emojis/1f468-200d-2764-fe0f-200d-1f468.png b/emojis/1f468-200d-2764-fe0f-200d-1f468.png new file mode 100644 index 00000000..1474b1a4 Binary files /dev/null and b/emojis/1f468-200d-2764-fe0f-200d-1f468.png differ diff --git a/emojis/1f468-200d-2764-fe0f-200d-1f48b-200d-1f468.png b/emojis/1f468-200d-2764-fe0f-200d-1f48b-200d-1f468.png new file mode 100644 index 00000000..e2850f09 Binary files /dev/null and b/emojis/1f468-200d-2764-fe0f-200d-1f48b-200d-1f468.png differ diff --git a/emojis/1f468.png b/emojis/1f468.png new file mode 100644 index 00000000..80f78fb2 Binary files /dev/null and b/emojis/1f468.png differ diff --git a/emojis/1f469-200d-1f469-200d-1f466-200d-1f466.png b/emojis/1f469-200d-1f469-200d-1f466-200d-1f466.png new file mode 100644 index 00000000..256b8676 Binary files /dev/null and b/emojis/1f469-200d-1f469-200d-1f466-200d-1f466.png differ diff --git a/emojis/1f469-200d-1f469-200d-1f466.png b/emojis/1f469-200d-1f469-200d-1f466.png new file mode 100644 index 00000000..81ebca03 Binary files /dev/null and b/emojis/1f469-200d-1f469-200d-1f466.png differ diff --git a/emojis/1f469-200d-1f469-200d-1f467-200d-1f466.png b/emojis/1f469-200d-1f469-200d-1f467-200d-1f466.png new file mode 100644 index 00000000..34dcba26 Binary files /dev/null and b/emojis/1f469-200d-1f469-200d-1f467-200d-1f466.png differ diff --git a/emojis/1f469-200d-1f469-200d-1f467-200d-1f467.png b/emojis/1f469-200d-1f469-200d-1f467-200d-1f467.png new file mode 100644 index 00000000..79cad7eb Binary files /dev/null and b/emojis/1f469-200d-1f469-200d-1f467-200d-1f467.png differ diff --git a/emojis/1f469-200d-1f469-200d-1f467.png b/emojis/1f469-200d-1f469-200d-1f467.png new file mode 100644 index 00000000..c512c43b Binary files /dev/null and b/emojis/1f469-200d-1f469-200d-1f467.png differ diff --git a/emojis/1f469-200d-2764-fe0f-200d-1f469.png b/emojis/1f469-200d-2764-fe0f-200d-1f469.png new file mode 100644 index 00000000..aa1fc0c4 Binary files /dev/null and b/emojis/1f469-200d-2764-fe0f-200d-1f469.png differ diff --git a/emojis/1f469-200d-2764-fe0f-200d-1f48b-200d-1f469.png b/emojis/1f469-200d-2764-fe0f-200d-1f48b-200d-1f469.png new file mode 100644 index 00000000..54b468e5 Binary files /dev/null and b/emojis/1f469-200d-2764-fe0f-200d-1f48b-200d-1f469.png differ diff --git a/emojis/1f469.png b/emojis/1f469.png new file mode 100644 index 00000000..65dc7846 Binary files /dev/null and b/emojis/1f469.png differ diff --git a/emojis/1f46a.png b/emojis/1f46a.png new file mode 100644 index 00000000..8ab628c1 Binary files /dev/null and b/emojis/1f46a.png differ diff --git a/emojis/1f46b.png b/emojis/1f46b.png new file mode 100644 index 00000000..5edf7b0d Binary files /dev/null and b/emojis/1f46b.png differ diff --git a/emojis/1f46c.png b/emojis/1f46c.png new file mode 100644 index 00000000..0034b8a2 Binary files /dev/null and b/emojis/1f46c.png differ diff --git a/emojis/1f46d.png b/emojis/1f46d.png new file mode 100644 index 00000000..525e6b95 Binary files /dev/null and b/emojis/1f46d.png differ diff --git a/emojis/1f46e.png b/emojis/1f46e.png new file mode 100644 index 00000000..71f79151 Binary files /dev/null and b/emojis/1f46e.png differ diff --git a/emojis/1f46f.png b/emojis/1f46f.png new file mode 100644 index 00000000..935cfb96 Binary files /dev/null and b/emojis/1f46f.png differ diff --git a/emojis/1f470.png b/emojis/1f470.png new file mode 100644 index 00000000..3566b8bc Binary files /dev/null and b/emojis/1f470.png differ diff --git a/emojis/1f471.png b/emojis/1f471.png new file mode 100644 index 00000000..46c2e7a3 Binary files /dev/null and b/emojis/1f471.png differ diff --git a/emojis/1f472.png b/emojis/1f472.png new file mode 100644 index 00000000..33086fca Binary files /dev/null and b/emojis/1f472.png differ diff --git a/emojis/1f473.png b/emojis/1f473.png new file mode 100644 index 00000000..49b8b85a Binary files /dev/null and b/emojis/1f473.png differ diff --git a/emojis/1f474.png b/emojis/1f474.png new file mode 100644 index 00000000..806a4223 Binary files /dev/null and b/emojis/1f474.png differ diff --git a/emojis/1f475.png b/emojis/1f475.png new file mode 100644 index 00000000..998a4ae3 Binary files /dev/null and b/emojis/1f475.png differ diff --git a/emojis/1f476.png b/emojis/1f476.png new file mode 100644 index 00000000..a21fd452 Binary files /dev/null and b/emojis/1f476.png differ diff --git a/emojis/1f477.png b/emojis/1f477.png new file mode 100644 index 00000000..5129bfb4 Binary files /dev/null and b/emojis/1f477.png differ diff --git a/emojis/1f478.png b/emojis/1f478.png new file mode 100644 index 00000000..f49d0213 Binary files /dev/null and b/emojis/1f478.png differ diff --git a/emojis/1f479.png b/emojis/1f479.png new file mode 100644 index 00000000..35a1a369 Binary files /dev/null and b/emojis/1f479.png differ diff --git a/emojis/1f47a.png b/emojis/1f47a.png new file mode 100644 index 00000000..8e5b5765 Binary files /dev/null and b/emojis/1f47a.png differ diff --git a/emojis/1f47b.png b/emojis/1f47b.png new file mode 100644 index 00000000..9eca01f5 Binary files /dev/null and b/emojis/1f47b.png differ diff --git a/emojis/1f47c.png b/emojis/1f47c.png new file mode 100644 index 00000000..0d8b84ba Binary files /dev/null and b/emojis/1f47c.png differ diff --git a/emojis/1f47d.png b/emojis/1f47d.png new file mode 100644 index 00000000..721a9ee9 Binary files /dev/null and b/emojis/1f47d.png differ diff --git a/emojis/1f47e.png b/emojis/1f47e.png new file mode 100644 index 00000000..4181acae Binary files /dev/null and b/emojis/1f47e.png differ diff --git a/emojis/1f47f.png b/emojis/1f47f.png new file mode 100644 index 00000000..6f4ffd88 Binary files /dev/null and b/emojis/1f47f.png differ diff --git a/emojis/1f480.png b/emojis/1f480.png new file mode 100644 index 00000000..3f7761b1 Binary files /dev/null and b/emojis/1f480.png differ diff --git a/emojis/1f481.png b/emojis/1f481.png new file mode 100644 index 00000000..6f22fc3b Binary files /dev/null and b/emojis/1f481.png differ diff --git a/emojis/1f482.png b/emojis/1f482.png new file mode 100644 index 00000000..51ded209 Binary files /dev/null and b/emojis/1f482.png differ diff --git a/emojis/1f483.png b/emojis/1f483.png new file mode 100644 index 00000000..d8a9a4f4 Binary files /dev/null and b/emojis/1f483.png differ diff --git a/emojis/1f484.png b/emojis/1f484.png new file mode 100644 index 00000000..140e7c16 Binary files /dev/null and b/emojis/1f484.png differ diff --git a/emojis/1f485.png b/emojis/1f485.png new file mode 100644 index 00000000..7c016bb0 Binary files /dev/null and b/emojis/1f485.png differ diff --git a/emojis/1f486.png b/emojis/1f486.png new file mode 100644 index 00000000..73b56903 Binary files /dev/null and b/emojis/1f486.png differ diff --git a/emojis/1f487.png b/emojis/1f487.png new file mode 100644 index 00000000..c11e5afc Binary files /dev/null and b/emojis/1f487.png differ diff --git a/emojis/1f488.png b/emojis/1f488.png new file mode 100644 index 00000000..53bb57bb Binary files /dev/null and b/emojis/1f488.png differ diff --git a/emojis/1f489.png b/emojis/1f489.png new file mode 100644 index 00000000..39ae8d16 Binary files /dev/null and b/emojis/1f489.png differ diff --git a/emojis/1f48a.png b/emojis/1f48a.png new file mode 100644 index 00000000..93dd1b23 Binary files /dev/null and b/emojis/1f48a.png differ diff --git a/emojis/1f48b.png b/emojis/1f48b.png new file mode 100644 index 00000000..bc3101c5 Binary files /dev/null and b/emojis/1f48b.png differ diff --git a/emojis/1f48c.png b/emojis/1f48c.png new file mode 100644 index 00000000..37a3f0ab Binary files /dev/null and b/emojis/1f48c.png differ diff --git a/emojis/1f48d.png b/emojis/1f48d.png new file mode 100644 index 00000000..ea8ce85d Binary files /dev/null and b/emojis/1f48d.png differ diff --git a/emojis/1f48e.png b/emojis/1f48e.png new file mode 100644 index 00000000..babec910 Binary files /dev/null and b/emojis/1f48e.png differ diff --git a/emojis/1f48f.png b/emojis/1f48f.png new file mode 100644 index 00000000..d169c8b3 Binary files /dev/null and b/emojis/1f48f.png differ diff --git a/emojis/1f490.png b/emojis/1f490.png new file mode 100644 index 00000000..cd119065 Binary files /dev/null and b/emojis/1f490.png differ diff --git a/emojis/1f491.png b/emojis/1f491.png new file mode 100644 index 00000000..d6f82e30 Binary files /dev/null and b/emojis/1f491.png differ diff --git a/emojis/1f492.png b/emojis/1f492.png new file mode 100644 index 00000000..5ddc9e8f Binary files /dev/null and b/emojis/1f492.png differ diff --git a/emojis/1f493.png b/emojis/1f493.png new file mode 100644 index 00000000..85e1b311 Binary files /dev/null and b/emojis/1f493.png differ diff --git a/emojis/1f494.png b/emojis/1f494.png new file mode 100644 index 00000000..00dab8eb Binary files /dev/null and b/emojis/1f494.png differ diff --git a/emojis/1f495.png b/emojis/1f495.png new file mode 100644 index 00000000..e5cd0f83 Binary files /dev/null and b/emojis/1f495.png differ diff --git a/emojis/1f496.png b/emojis/1f496.png new file mode 100644 index 00000000..0f9f4a5a Binary files /dev/null and b/emojis/1f496.png differ diff --git a/emojis/1f497.png b/emojis/1f497.png new file mode 100644 index 00000000..cd0a4ba8 Binary files /dev/null and b/emojis/1f497.png differ diff --git a/emojis/1f498.png b/emojis/1f498.png new file mode 100644 index 00000000..f4f10882 Binary files /dev/null and b/emojis/1f498.png differ diff --git a/emojis/1f499.png b/emojis/1f499.png new file mode 100644 index 00000000..3831cb0c Binary files /dev/null and b/emojis/1f499.png differ diff --git a/emojis/1f49a.png b/emojis/1f49a.png new file mode 100644 index 00000000..e495bf7d Binary files /dev/null and b/emojis/1f49a.png differ diff --git a/emojis/1f49b.png b/emojis/1f49b.png new file mode 100644 index 00000000..b325d41e Binary files /dev/null and b/emojis/1f49b.png differ diff --git a/emojis/1f49c.png b/emojis/1f49c.png new file mode 100644 index 00000000..43c65244 Binary files /dev/null and b/emojis/1f49c.png differ diff --git a/emojis/1f49d.png b/emojis/1f49d.png new file mode 100644 index 00000000..792953dd Binary files /dev/null and b/emojis/1f49d.png differ diff --git a/emojis/1f49e.png b/emojis/1f49e.png new file mode 100644 index 00000000..d63c74f3 Binary files /dev/null and b/emojis/1f49e.png differ diff --git a/emojis/1f49f.png b/emojis/1f49f.png new file mode 100644 index 00000000..69806936 Binary files /dev/null and b/emojis/1f49f.png differ diff --git a/emojis/1f4a0.png b/emojis/1f4a0.png new file mode 100644 index 00000000..22c3b133 Binary files /dev/null and b/emojis/1f4a0.png differ diff --git a/emojis/1f4a1.png b/emojis/1f4a1.png new file mode 100644 index 00000000..708640b5 Binary files /dev/null and b/emojis/1f4a1.png differ diff --git a/emojis/1f4a2.png b/emojis/1f4a2.png new file mode 100644 index 00000000..deaabf2d Binary files /dev/null and b/emojis/1f4a2.png differ diff --git a/emojis/1f4a3.png b/emojis/1f4a3.png new file mode 100644 index 00000000..6674491b Binary files /dev/null and b/emojis/1f4a3.png differ diff --git a/emojis/1f4a4.png b/emojis/1f4a4.png new file mode 100644 index 00000000..89d7b883 Binary files /dev/null and b/emojis/1f4a4.png differ diff --git a/emojis/1f4a5.png b/emojis/1f4a5.png new file mode 100644 index 00000000..bee635cc Binary files /dev/null and b/emojis/1f4a5.png differ diff --git a/emojis/1f4a6.png b/emojis/1f4a6.png new file mode 100644 index 00000000..ec66fccb Binary files /dev/null and b/emojis/1f4a6.png differ diff --git a/emojis/1f4a7.png b/emojis/1f4a7.png new file mode 100644 index 00000000..d931cdf6 Binary files /dev/null and b/emojis/1f4a7.png differ diff --git a/emojis/1f4a8.png b/emojis/1f4a8.png new file mode 100644 index 00000000..2df3ad98 Binary files /dev/null and b/emojis/1f4a8.png differ diff --git a/emojis/1f4a9.png b/emojis/1f4a9.png new file mode 100644 index 00000000..eb8f3c4c Binary files /dev/null and b/emojis/1f4a9.png differ diff --git a/emojis/1f4aa.png b/emojis/1f4aa.png new file mode 100644 index 00000000..eb4aa967 Binary files /dev/null and b/emojis/1f4aa.png differ diff --git a/emojis/1f4ab.png b/emojis/1f4ab.png new file mode 100644 index 00000000..d48d5f62 Binary files /dev/null and b/emojis/1f4ab.png differ diff --git a/emojis/1f4ac.png b/emojis/1f4ac.png new file mode 100644 index 00000000..36075f0e Binary files /dev/null and b/emojis/1f4ac.png differ diff --git a/emojis/1f4ad.png b/emojis/1f4ad.png new file mode 100644 index 00000000..b40f2a90 Binary files /dev/null and b/emojis/1f4ad.png differ diff --git a/emojis/1f4ae.png b/emojis/1f4ae.png new file mode 100644 index 00000000..89cb9728 Binary files /dev/null and b/emojis/1f4ae.png differ diff --git a/emojis/1f4af.png b/emojis/1f4af.png new file mode 100644 index 00000000..36680b5a Binary files /dev/null and b/emojis/1f4af.png differ diff --git a/emojis/1f4b0.png b/emojis/1f4b0.png new file mode 100644 index 00000000..7f246f1b Binary files /dev/null and b/emojis/1f4b0.png differ diff --git a/emojis/1f4b1.png b/emojis/1f4b1.png new file mode 100644 index 00000000..02332181 Binary files /dev/null and b/emojis/1f4b1.png differ diff --git a/emojis/1f4b2.png b/emojis/1f4b2.png new file mode 100644 index 00000000..636aeed1 Binary files /dev/null and b/emojis/1f4b2.png differ diff --git a/emojis/1f4b3.png b/emojis/1f4b3.png new file mode 100644 index 00000000..c922db14 Binary files /dev/null and b/emojis/1f4b3.png differ diff --git a/emojis/1f4b4.png b/emojis/1f4b4.png new file mode 100644 index 00000000..3cb5ed49 Binary files /dev/null and b/emojis/1f4b4.png differ diff --git a/emojis/1f4b5.png b/emojis/1f4b5.png new file mode 100644 index 00000000..bd292578 Binary files /dev/null and b/emojis/1f4b5.png differ diff --git a/emojis/1f4b6.png b/emojis/1f4b6.png new file mode 100644 index 00000000..dc93ccfb Binary files /dev/null and b/emojis/1f4b6.png differ diff --git a/emojis/1f4b7.png b/emojis/1f4b7.png new file mode 100644 index 00000000..4755a008 Binary files /dev/null and b/emojis/1f4b7.png differ diff --git a/emojis/1f4b8.png b/emojis/1f4b8.png new file mode 100644 index 00000000..b02fc5a3 Binary files /dev/null and b/emojis/1f4b8.png differ diff --git a/emojis/1f4b9.png b/emojis/1f4b9.png new file mode 100644 index 00000000..ab86303b Binary files /dev/null and b/emojis/1f4b9.png differ diff --git a/emojis/1f4ba.png b/emojis/1f4ba.png new file mode 100644 index 00000000..9dd62627 Binary files /dev/null and b/emojis/1f4ba.png differ diff --git a/emojis/1f4bb.png b/emojis/1f4bb.png new file mode 100644 index 00000000..510d0cea Binary files /dev/null and b/emojis/1f4bb.png differ diff --git a/emojis/1f4bc.png b/emojis/1f4bc.png new file mode 100644 index 00000000..f38a1b96 Binary files /dev/null and b/emojis/1f4bc.png differ diff --git a/emojis/1f4bd.png b/emojis/1f4bd.png new file mode 100644 index 00000000..66cada1b Binary files /dev/null and b/emojis/1f4bd.png differ diff --git a/emojis/1f4be.png b/emojis/1f4be.png new file mode 100644 index 00000000..2a34b199 Binary files /dev/null and b/emojis/1f4be.png differ diff --git a/emojis/1f4bf.png b/emojis/1f4bf.png new file mode 100644 index 00000000..608da0db Binary files /dev/null and b/emojis/1f4bf.png differ diff --git a/emojis/1f4c0.png b/emojis/1f4c0.png new file mode 100644 index 00000000..b703d90e Binary files /dev/null and b/emojis/1f4c0.png differ diff --git a/emojis/1f4c1.png b/emojis/1f4c1.png new file mode 100644 index 00000000..1be20b33 Binary files /dev/null and b/emojis/1f4c1.png differ diff --git a/emojis/1f4c2.png b/emojis/1f4c2.png new file mode 100644 index 00000000..c0798516 Binary files /dev/null and b/emojis/1f4c2.png differ diff --git a/emojis/1f4c3.png b/emojis/1f4c3.png new file mode 100644 index 00000000..99169866 Binary files /dev/null and b/emojis/1f4c3.png differ diff --git a/emojis/1f4c4.png b/emojis/1f4c4.png new file mode 100644 index 00000000..dcbb065a Binary files /dev/null and b/emojis/1f4c4.png differ diff --git a/emojis/1f4c5.png b/emojis/1f4c5.png new file mode 100644 index 00000000..b6388b51 Binary files /dev/null and b/emojis/1f4c5.png differ diff --git a/emojis/1f4c6.png b/emojis/1f4c6.png new file mode 100644 index 00000000..54a78a03 Binary files /dev/null and b/emojis/1f4c6.png differ diff --git a/emojis/1f4c7.png b/emojis/1f4c7.png new file mode 100644 index 00000000..a5743a16 Binary files /dev/null and b/emojis/1f4c7.png differ diff --git a/emojis/1f4c8.png b/emojis/1f4c8.png new file mode 100644 index 00000000..74decbc4 Binary files /dev/null and b/emojis/1f4c8.png differ diff --git a/emojis/1f4c9.png b/emojis/1f4c9.png new file mode 100644 index 00000000..3b5934ea Binary files /dev/null and b/emojis/1f4c9.png differ diff --git a/emojis/1f4ca.png b/emojis/1f4ca.png new file mode 100644 index 00000000..a39be4fa Binary files /dev/null and b/emojis/1f4ca.png differ diff --git a/emojis/1f4cb.png b/emojis/1f4cb.png new file mode 100644 index 00000000..9528d173 Binary files /dev/null and b/emojis/1f4cb.png differ diff --git a/emojis/1f4cc.png b/emojis/1f4cc.png new file mode 100644 index 00000000..02b168d2 Binary files /dev/null and b/emojis/1f4cc.png differ diff --git a/emojis/1f4cd.png b/emojis/1f4cd.png new file mode 100644 index 00000000..0287a07d Binary files /dev/null and b/emojis/1f4cd.png differ diff --git a/emojis/1f4ce.png b/emojis/1f4ce.png new file mode 100644 index 00000000..6ee0c5fb Binary files /dev/null and b/emojis/1f4ce.png differ diff --git a/emojis/1f4cf.png b/emojis/1f4cf.png new file mode 100644 index 00000000..8c5af697 Binary files /dev/null and b/emojis/1f4cf.png differ diff --git a/emojis/1f4d0.png b/emojis/1f4d0.png new file mode 100644 index 00000000..91efab93 Binary files /dev/null and b/emojis/1f4d0.png differ diff --git a/emojis/1f4d1.png b/emojis/1f4d1.png new file mode 100644 index 00000000..e836cafc Binary files /dev/null and b/emojis/1f4d1.png differ diff --git a/emojis/1f4d2.png b/emojis/1f4d2.png new file mode 100644 index 00000000..3b11d66b Binary files /dev/null and b/emojis/1f4d2.png differ diff --git a/emojis/1f4d3.png b/emojis/1f4d3.png new file mode 100644 index 00000000..7840b145 Binary files /dev/null and b/emojis/1f4d3.png differ diff --git a/emojis/1f4d4.png b/emojis/1f4d4.png new file mode 100644 index 00000000..417ea55f Binary files /dev/null and b/emojis/1f4d4.png differ diff --git a/emojis/1f4d5.png b/emojis/1f4d5.png new file mode 100644 index 00000000..cab168b0 Binary files /dev/null and b/emojis/1f4d5.png differ diff --git a/emojis/1f4d6.png b/emojis/1f4d6.png new file mode 100644 index 00000000..7879f451 Binary files /dev/null and b/emojis/1f4d6.png differ diff --git a/emojis/1f4d7.png b/emojis/1f4d7.png new file mode 100644 index 00000000..da823fb5 Binary files /dev/null and b/emojis/1f4d7.png differ diff --git a/emojis/1f4d8.png b/emojis/1f4d8.png new file mode 100644 index 00000000..eb35e803 Binary files /dev/null and b/emojis/1f4d8.png differ diff --git a/emojis/1f4d9.png b/emojis/1f4d9.png new file mode 100644 index 00000000..880a0b0b Binary files /dev/null and b/emojis/1f4d9.png differ diff --git a/emojis/1f4da.png b/emojis/1f4da.png new file mode 100644 index 00000000..43a319fd Binary files /dev/null and b/emojis/1f4da.png differ diff --git a/emojis/1f4db.png b/emojis/1f4db.png new file mode 100644 index 00000000..b7e858bf Binary files /dev/null and b/emojis/1f4db.png differ diff --git a/emojis/1f4dc.png b/emojis/1f4dc.png new file mode 100644 index 00000000..069f16c6 Binary files /dev/null and b/emojis/1f4dc.png differ diff --git a/emojis/1f4dd.png b/emojis/1f4dd.png new file mode 100644 index 00000000..0f731b2b Binary files /dev/null and b/emojis/1f4dd.png differ diff --git a/emojis/1f4de.png b/emojis/1f4de.png new file mode 100644 index 00000000..d760f75e Binary files /dev/null and b/emojis/1f4de.png differ diff --git a/emojis/1f4df.png b/emojis/1f4df.png new file mode 100644 index 00000000..c38a2a8a Binary files /dev/null and b/emojis/1f4df.png differ diff --git a/emojis/1f4e0.png b/emojis/1f4e0.png new file mode 100644 index 00000000..b71bd81c Binary files /dev/null and b/emojis/1f4e0.png differ diff --git a/emojis/1f4e1.png b/emojis/1f4e1.png new file mode 100644 index 00000000..d5b1870a Binary files /dev/null and b/emojis/1f4e1.png differ diff --git a/emojis/1f4e2.png b/emojis/1f4e2.png new file mode 100644 index 00000000..7329cd96 Binary files /dev/null and b/emojis/1f4e2.png differ diff --git a/emojis/1f4e3.png b/emojis/1f4e3.png new file mode 100644 index 00000000..28b20310 Binary files /dev/null and b/emojis/1f4e3.png differ diff --git a/emojis/1f4e4.png b/emojis/1f4e4.png new file mode 100644 index 00000000..0953827b Binary files /dev/null and b/emojis/1f4e4.png differ diff --git a/emojis/1f4e5.png b/emojis/1f4e5.png new file mode 100644 index 00000000..c23faaad Binary files /dev/null and b/emojis/1f4e5.png differ diff --git a/emojis/1f4e6.png b/emojis/1f4e6.png new file mode 100644 index 00000000..dc7f04af Binary files /dev/null and b/emojis/1f4e6.png differ diff --git a/emojis/1f4e7.png b/emojis/1f4e7.png new file mode 100644 index 00000000..330688d7 Binary files /dev/null and b/emojis/1f4e7.png differ diff --git a/emojis/1f4e8.png b/emojis/1f4e8.png new file mode 100644 index 00000000..2028c3c8 Binary files /dev/null and b/emojis/1f4e8.png differ diff --git a/emojis/1f4e9.png b/emojis/1f4e9.png new file mode 100644 index 00000000..04b04066 Binary files /dev/null and b/emojis/1f4e9.png differ diff --git a/emojis/1f4ea.png b/emojis/1f4ea.png new file mode 100644 index 00000000..1fa43ced Binary files /dev/null and b/emojis/1f4ea.png differ diff --git a/emojis/1f4eb.png b/emojis/1f4eb.png new file mode 100644 index 00000000..0795291e Binary files /dev/null and b/emojis/1f4eb.png differ diff --git a/emojis/1f4ec.png b/emojis/1f4ec.png new file mode 100644 index 00000000..2ffca371 Binary files /dev/null and b/emojis/1f4ec.png differ diff --git a/emojis/1f4ed.png b/emojis/1f4ed.png new file mode 100644 index 00000000..594618fa Binary files /dev/null and b/emojis/1f4ed.png differ diff --git a/emojis/1f4ee.png b/emojis/1f4ee.png new file mode 100644 index 00000000..edbf9261 Binary files /dev/null and b/emojis/1f4ee.png differ diff --git a/emojis/1f4ef.png b/emojis/1f4ef.png new file mode 100644 index 00000000..8c47f6c0 Binary files /dev/null and b/emojis/1f4ef.png differ diff --git a/emojis/1f4f0.png b/emojis/1f4f0.png new file mode 100644 index 00000000..b7f063e6 Binary files /dev/null and b/emojis/1f4f0.png differ diff --git a/emojis/1f4f1.png b/emojis/1f4f1.png new file mode 100644 index 00000000..ddb7a310 Binary files /dev/null and b/emojis/1f4f1.png differ diff --git a/emojis/1f4f2.png b/emojis/1f4f2.png new file mode 100644 index 00000000..9ab86410 Binary files /dev/null and b/emojis/1f4f2.png differ diff --git a/emojis/1f4f3.png b/emojis/1f4f3.png new file mode 100644 index 00000000..22ca0e5c Binary files /dev/null and b/emojis/1f4f3.png differ diff --git a/emojis/1f4f4.png b/emojis/1f4f4.png new file mode 100644 index 00000000..4ae348ed Binary files /dev/null and b/emojis/1f4f4.png differ diff --git a/emojis/1f4f5.png b/emojis/1f4f5.png new file mode 100644 index 00000000..6e8d29ad Binary files /dev/null and b/emojis/1f4f5.png differ diff --git a/emojis/1f4f6.png b/emojis/1f4f6.png new file mode 100644 index 00000000..ba1bcd2a Binary files /dev/null and b/emojis/1f4f6.png differ diff --git a/emojis/1f4f7.png b/emojis/1f4f7.png new file mode 100644 index 00000000..b95b2e09 Binary files /dev/null and b/emojis/1f4f7.png differ diff --git a/emojis/1f4f8.png b/emojis/1f4f8.png new file mode 100644 index 00000000..1b6270a6 Binary files /dev/null and b/emojis/1f4f8.png differ diff --git a/emojis/1f4f9.png b/emojis/1f4f9.png new file mode 100644 index 00000000..856ccccc Binary files /dev/null and b/emojis/1f4f9.png differ diff --git a/emojis/1f4fa.png b/emojis/1f4fa.png new file mode 100644 index 00000000..da1a7079 Binary files /dev/null and b/emojis/1f4fa.png differ diff --git a/emojis/1f4fb.png b/emojis/1f4fb.png new file mode 100644 index 00000000..dfb91a83 Binary files /dev/null and b/emojis/1f4fb.png differ diff --git a/emojis/1f4fc.png b/emojis/1f4fc.png new file mode 100644 index 00000000..ab7c96d5 Binary files /dev/null and b/emojis/1f4fc.png differ diff --git a/emojis/1f4fd.png b/emojis/1f4fd.png new file mode 100644 index 00000000..cdf67014 Binary files /dev/null and b/emojis/1f4fd.png differ diff --git a/emojis/1f4ff.png b/emojis/1f4ff.png new file mode 100644 index 00000000..4db33923 Binary files /dev/null and b/emojis/1f4ff.png differ diff --git a/emojis/1f500.png b/emojis/1f500.png new file mode 100644 index 00000000..8d52f177 Binary files /dev/null and b/emojis/1f500.png differ diff --git a/emojis/1f501.png b/emojis/1f501.png new file mode 100644 index 00000000..2331b22c Binary files /dev/null and b/emojis/1f501.png differ diff --git a/emojis/1f502.png b/emojis/1f502.png new file mode 100644 index 00000000..c79f5c32 Binary files /dev/null and b/emojis/1f502.png differ diff --git a/emojis/1f503.png b/emojis/1f503.png new file mode 100644 index 00000000..935cd74f Binary files /dev/null and b/emojis/1f503.png differ diff --git a/emojis/1f504.png b/emojis/1f504.png new file mode 100644 index 00000000..1c17faa7 Binary files /dev/null and b/emojis/1f504.png differ diff --git a/emojis/1f505.png b/emojis/1f505.png new file mode 100644 index 00000000..dca4099e Binary files /dev/null and b/emojis/1f505.png differ diff --git a/emojis/1f506.png b/emojis/1f506.png new file mode 100644 index 00000000..807a11b2 Binary files /dev/null and b/emojis/1f506.png differ diff --git a/emojis/1f507.png b/emojis/1f507.png new file mode 100644 index 00000000..ba3b16ed Binary files /dev/null and b/emojis/1f507.png differ diff --git a/emojis/1f508.png b/emojis/1f508.png new file mode 100644 index 00000000..6439703c Binary files /dev/null and b/emojis/1f508.png differ diff --git a/emojis/1f509.png b/emojis/1f509.png new file mode 100644 index 00000000..f6706053 Binary files /dev/null and b/emojis/1f509.png differ diff --git a/emojis/1f50a.png b/emojis/1f50a.png new file mode 100644 index 00000000..ff6a3676 Binary files /dev/null and b/emojis/1f50a.png differ diff --git a/emojis/1f50b.png b/emojis/1f50b.png new file mode 100644 index 00000000..d5ecdbc8 Binary files /dev/null and b/emojis/1f50b.png differ diff --git a/emojis/1f50c.png b/emojis/1f50c.png new file mode 100644 index 00000000..aa57f6a7 Binary files /dev/null and b/emojis/1f50c.png differ diff --git a/emojis/1f50d.png b/emojis/1f50d.png new file mode 100644 index 00000000..ca651a3f Binary files /dev/null and b/emojis/1f50d.png differ diff --git a/emojis/1f50e.png b/emojis/1f50e.png new file mode 100644 index 00000000..648d7c76 Binary files /dev/null and b/emojis/1f50e.png differ diff --git a/emojis/1f50f.png b/emojis/1f50f.png new file mode 100644 index 00000000..01f59f59 Binary files /dev/null and b/emojis/1f50f.png differ diff --git a/emojis/1f510.png b/emojis/1f510.png new file mode 100644 index 00000000..a51075dc Binary files /dev/null and b/emojis/1f510.png differ diff --git a/emojis/1f511.png b/emojis/1f511.png new file mode 100644 index 00000000..8ed93504 Binary files /dev/null and b/emojis/1f511.png differ diff --git a/emojis/1f512.png b/emojis/1f512.png new file mode 100644 index 00000000..a2a85ac7 Binary files /dev/null and b/emojis/1f512.png differ diff --git a/emojis/1f513.png b/emojis/1f513.png new file mode 100644 index 00000000..c10c6b7a Binary files /dev/null and b/emojis/1f513.png differ diff --git a/emojis/1f514.png b/emojis/1f514.png new file mode 100644 index 00000000..aa48445b Binary files /dev/null and b/emojis/1f514.png differ diff --git a/emojis/1f515.png b/emojis/1f515.png new file mode 100644 index 00000000..305a8c8d Binary files /dev/null and b/emojis/1f515.png differ diff --git a/emojis/1f516.png b/emojis/1f516.png new file mode 100644 index 00000000..be095754 Binary files /dev/null and b/emojis/1f516.png differ diff --git a/emojis/1f517.png b/emojis/1f517.png new file mode 100644 index 00000000..20c0312d Binary files /dev/null and b/emojis/1f517.png differ diff --git a/emojis/1f518.png b/emojis/1f518.png new file mode 100644 index 00000000..8e845a57 Binary files /dev/null and b/emojis/1f518.png differ diff --git a/emojis/1f519.png b/emojis/1f519.png new file mode 100644 index 00000000..13c27ede Binary files /dev/null and b/emojis/1f519.png differ diff --git a/emojis/1f51a.png b/emojis/1f51a.png new file mode 100644 index 00000000..eee9b471 Binary files /dev/null and b/emojis/1f51a.png differ diff --git a/emojis/1f51b.png b/emojis/1f51b.png new file mode 100644 index 00000000..f4f5dc4a Binary files /dev/null and b/emojis/1f51b.png differ diff --git a/emojis/1f51c.png b/emojis/1f51c.png new file mode 100644 index 00000000..4a22b2c5 Binary files /dev/null and b/emojis/1f51c.png differ diff --git a/emojis/1f51d.png b/emojis/1f51d.png new file mode 100644 index 00000000..aa439737 Binary files /dev/null and b/emojis/1f51d.png differ diff --git a/emojis/1f51e.png b/emojis/1f51e.png new file mode 100644 index 00000000..13547738 Binary files /dev/null and b/emojis/1f51e.png differ diff --git a/emojis/1f51f.png b/emojis/1f51f.png new file mode 100644 index 00000000..a9a6bf19 Binary files /dev/null and b/emojis/1f51f.png differ diff --git a/emojis/1f520.png b/emojis/1f520.png new file mode 100644 index 00000000..eca27a9b Binary files /dev/null and b/emojis/1f520.png differ diff --git a/emojis/1f521.png b/emojis/1f521.png new file mode 100644 index 00000000..1ca305de Binary files /dev/null and b/emojis/1f521.png differ diff --git a/emojis/1f522.png b/emojis/1f522.png new file mode 100644 index 00000000..b341c9e0 Binary files /dev/null and b/emojis/1f522.png differ diff --git a/emojis/1f523.png b/emojis/1f523.png new file mode 100644 index 00000000..3a5d9d99 Binary files /dev/null and b/emojis/1f523.png differ diff --git a/emojis/1f524.png b/emojis/1f524.png new file mode 100644 index 00000000..219c4b53 Binary files /dev/null and b/emojis/1f524.png differ diff --git a/emojis/1f525.png b/emojis/1f525.png new file mode 100644 index 00000000..a02f59ed Binary files /dev/null and b/emojis/1f525.png differ diff --git a/emojis/1f526.png b/emojis/1f526.png new file mode 100644 index 00000000..add89316 Binary files /dev/null and b/emojis/1f526.png differ diff --git a/emojis/1f527.png b/emojis/1f527.png new file mode 100644 index 00000000..49a62419 Binary files /dev/null and b/emojis/1f527.png differ diff --git a/emojis/1f528.png b/emojis/1f528.png new file mode 100644 index 00000000..342995e9 Binary files /dev/null and b/emojis/1f528.png differ diff --git a/emojis/1f529.png b/emojis/1f529.png new file mode 100644 index 00000000..a779f1f5 Binary files /dev/null and b/emojis/1f529.png differ diff --git a/emojis/1f52a.png b/emojis/1f52a.png new file mode 100644 index 00000000..cd6cee11 Binary files /dev/null and b/emojis/1f52a.png differ diff --git a/emojis/1f52b.png b/emojis/1f52b.png new file mode 100644 index 00000000..b3b3a1a3 Binary files /dev/null and b/emojis/1f52b.png differ diff --git a/emojis/1f52c.png b/emojis/1f52c.png new file mode 100644 index 00000000..76f2b0be Binary files /dev/null and b/emojis/1f52c.png differ diff --git a/emojis/1f52d.png b/emojis/1f52d.png new file mode 100644 index 00000000..6a63be45 Binary files /dev/null and b/emojis/1f52d.png differ diff --git a/emojis/1f52e.png b/emojis/1f52e.png new file mode 100644 index 00000000..332f4daa Binary files /dev/null and b/emojis/1f52e.png differ diff --git a/emojis/1f52f.png b/emojis/1f52f.png new file mode 100644 index 00000000..458fa9da Binary files /dev/null and b/emojis/1f52f.png differ diff --git a/emojis/1f530.png b/emojis/1f530.png new file mode 100644 index 00000000..a25019fc Binary files /dev/null and b/emojis/1f530.png differ diff --git a/emojis/1f531.png b/emojis/1f531.png new file mode 100644 index 00000000..76f7e0d6 Binary files /dev/null and b/emojis/1f531.png differ diff --git a/emojis/1f532.png b/emojis/1f532.png new file mode 100644 index 00000000..83292cc8 Binary files /dev/null and b/emojis/1f532.png differ diff --git a/emojis/1f533.png b/emojis/1f533.png new file mode 100644 index 00000000..11bb5c1c Binary files /dev/null and b/emojis/1f533.png differ diff --git a/emojis/1f534.png b/emojis/1f534.png new file mode 100644 index 00000000..53186df7 Binary files /dev/null and b/emojis/1f534.png differ diff --git a/emojis/1f535.png b/emojis/1f535.png new file mode 100644 index 00000000..b7372a6f Binary files /dev/null and b/emojis/1f535.png differ diff --git a/emojis/1f536.png b/emojis/1f536.png new file mode 100644 index 00000000..42a34b03 Binary files /dev/null and b/emojis/1f536.png differ diff --git a/emojis/1f537.png b/emojis/1f537.png new file mode 100644 index 00000000..297bdd59 Binary files /dev/null and b/emojis/1f537.png differ diff --git a/emojis/1f538.png b/emojis/1f538.png new file mode 100644 index 00000000..ff5a3ccd Binary files /dev/null and b/emojis/1f538.png differ diff --git a/emojis/1f539.png b/emojis/1f539.png new file mode 100644 index 00000000..f700e0c1 Binary files /dev/null and b/emojis/1f539.png differ diff --git a/emojis/1f53a.png b/emojis/1f53a.png new file mode 100644 index 00000000..e8d57e2a Binary files /dev/null and b/emojis/1f53a.png differ diff --git a/emojis/1f53b.png b/emojis/1f53b.png new file mode 100644 index 00000000..f6c7787e Binary files /dev/null and b/emojis/1f53b.png differ diff --git a/emojis/1f53c.png b/emojis/1f53c.png new file mode 100644 index 00000000..5aee3436 Binary files /dev/null and b/emojis/1f53c.png differ diff --git a/emojis/1f53d.png b/emojis/1f53d.png new file mode 100644 index 00000000..c7c3d6d2 Binary files /dev/null and b/emojis/1f53d.png differ diff --git a/emojis/1f549.png b/emojis/1f549.png new file mode 100644 index 00000000..afbbe7c0 Binary files /dev/null and b/emojis/1f549.png differ diff --git a/emojis/1f54a.png b/emojis/1f54a.png new file mode 100644 index 00000000..4d3dc44d Binary files /dev/null and b/emojis/1f54a.png differ diff --git a/emojis/1f54b.png b/emojis/1f54b.png new file mode 100644 index 00000000..8ff62e96 Binary files /dev/null and b/emojis/1f54b.png differ diff --git a/emojis/1f54c.png b/emojis/1f54c.png new file mode 100644 index 00000000..a2b11e82 Binary files /dev/null and b/emojis/1f54c.png differ diff --git a/emojis/1f54d.png b/emojis/1f54d.png new file mode 100644 index 00000000..23ca5c88 Binary files /dev/null and b/emojis/1f54d.png differ diff --git a/emojis/1f54e.png b/emojis/1f54e.png new file mode 100644 index 00000000..814afe57 Binary files /dev/null and b/emojis/1f54e.png differ diff --git a/emojis/1f550.png b/emojis/1f550.png new file mode 100644 index 00000000..a4f575fc Binary files /dev/null and b/emojis/1f550.png differ diff --git a/emojis/1f551.png b/emojis/1f551.png new file mode 100644 index 00000000..17540371 Binary files /dev/null and b/emojis/1f551.png differ diff --git a/emojis/1f552.png b/emojis/1f552.png new file mode 100644 index 00000000..5cebf205 Binary files /dev/null and b/emojis/1f552.png differ diff --git a/emojis/1f553.png b/emojis/1f553.png new file mode 100644 index 00000000..f5dcb68e Binary files /dev/null and b/emojis/1f553.png differ diff --git a/emojis/1f554.png b/emojis/1f554.png new file mode 100644 index 00000000..07ba3c2a Binary files /dev/null and b/emojis/1f554.png differ diff --git a/emojis/1f555.png b/emojis/1f555.png new file mode 100644 index 00000000..ec37a8e7 Binary files /dev/null and b/emojis/1f555.png differ diff --git a/emojis/1f556.png b/emojis/1f556.png new file mode 100644 index 00000000..e56f611a Binary files /dev/null and b/emojis/1f556.png differ diff --git a/emojis/1f557.png b/emojis/1f557.png new file mode 100644 index 00000000..9eb1d7be Binary files /dev/null and b/emojis/1f557.png differ diff --git a/emojis/1f558.png b/emojis/1f558.png new file mode 100644 index 00000000..27aaf682 Binary files /dev/null and b/emojis/1f558.png differ diff --git a/emojis/1f559.png b/emojis/1f559.png new file mode 100644 index 00000000..6991b878 Binary files /dev/null and b/emojis/1f559.png differ diff --git a/emojis/1f55a.png b/emojis/1f55a.png new file mode 100644 index 00000000..2b1aa9b9 Binary files /dev/null and b/emojis/1f55a.png differ diff --git a/emojis/1f55b.png b/emojis/1f55b.png new file mode 100644 index 00000000..57221643 Binary files /dev/null and b/emojis/1f55b.png differ diff --git a/emojis/1f55c.png b/emojis/1f55c.png new file mode 100644 index 00000000..8dc54f24 Binary files /dev/null and b/emojis/1f55c.png differ diff --git a/emojis/1f55d.png b/emojis/1f55d.png new file mode 100644 index 00000000..7af8cb7e Binary files /dev/null and b/emojis/1f55d.png differ diff --git a/emojis/1f55e.png b/emojis/1f55e.png new file mode 100644 index 00000000..4cf1144f Binary files /dev/null and b/emojis/1f55e.png differ diff --git a/emojis/1f55f.png b/emojis/1f55f.png new file mode 100644 index 00000000..9926b32a Binary files /dev/null and b/emojis/1f55f.png differ diff --git a/emojis/1f560.png b/emojis/1f560.png new file mode 100644 index 00000000..1e4e5753 Binary files /dev/null and b/emojis/1f560.png differ diff --git a/emojis/1f561.png b/emojis/1f561.png new file mode 100644 index 00000000..38f614b8 Binary files /dev/null and b/emojis/1f561.png differ diff --git a/emojis/1f562.png b/emojis/1f562.png new file mode 100644 index 00000000..13f69486 Binary files /dev/null and b/emojis/1f562.png differ diff --git a/emojis/1f563.png b/emojis/1f563.png new file mode 100644 index 00000000..19a8ff81 Binary files /dev/null and b/emojis/1f563.png differ diff --git a/emojis/1f564.png b/emojis/1f564.png new file mode 100644 index 00000000..eef0caae Binary files /dev/null and b/emojis/1f564.png differ diff --git a/emojis/1f565.png b/emojis/1f565.png new file mode 100644 index 00000000..a8112f2c Binary files /dev/null and b/emojis/1f565.png differ diff --git a/emojis/1f566.png b/emojis/1f566.png new file mode 100644 index 00000000..935ba679 Binary files /dev/null and b/emojis/1f566.png differ diff --git a/emojis/1f567.png b/emojis/1f567.png new file mode 100644 index 00000000..802483de Binary files /dev/null and b/emojis/1f567.png differ diff --git a/emojis/1f56f.png b/emojis/1f56f.png new file mode 100644 index 00000000..f56b2f11 Binary files /dev/null and b/emojis/1f56f.png differ diff --git a/emojis/1f570.png b/emojis/1f570.png new file mode 100644 index 00000000..ab6ac628 Binary files /dev/null and b/emojis/1f570.png differ diff --git a/emojis/1f573.png b/emojis/1f573.png new file mode 100644 index 00000000..194c86f8 Binary files /dev/null and b/emojis/1f573.png differ diff --git a/emojis/1f574.png b/emojis/1f574.png new file mode 100644 index 00000000..50a59dab Binary files /dev/null and b/emojis/1f574.png differ diff --git a/emojis/1f575.png b/emojis/1f575.png new file mode 100644 index 00000000..d0969e45 Binary files /dev/null and b/emojis/1f575.png differ diff --git a/emojis/1f576.png b/emojis/1f576.png new file mode 100644 index 00000000..0d0e5556 Binary files /dev/null and b/emojis/1f576.png differ diff --git a/emojis/1f577.png b/emojis/1f577.png new file mode 100644 index 00000000..a37b18ae Binary files /dev/null and b/emojis/1f577.png differ diff --git a/emojis/1f578.png b/emojis/1f578.png new file mode 100644 index 00000000..3ce29d81 Binary files /dev/null and b/emojis/1f578.png differ diff --git a/emojis/1f579.png b/emojis/1f579.png new file mode 100644 index 00000000..0a74d0cf Binary files /dev/null and b/emojis/1f579.png differ diff --git a/emojis/1f587.png b/emojis/1f587.png new file mode 100644 index 00000000..23c118f5 Binary files /dev/null and b/emojis/1f587.png differ diff --git a/emojis/1f58a.png b/emojis/1f58a.png new file mode 100644 index 00000000..b8279e8d Binary files /dev/null and b/emojis/1f58a.png differ diff --git a/emojis/1f58b.png b/emojis/1f58b.png new file mode 100644 index 00000000..a92c8369 Binary files /dev/null and b/emojis/1f58b.png differ diff --git a/emojis/1f58c.png b/emojis/1f58c.png new file mode 100644 index 00000000..9b458075 Binary files /dev/null and b/emojis/1f58c.png differ diff --git a/emojis/1f58d.png b/emojis/1f58d.png new file mode 100644 index 00000000..fcf2d267 Binary files /dev/null and b/emojis/1f58d.png differ diff --git a/emojis/1f590.png b/emojis/1f590.png new file mode 100644 index 00000000..225b357e Binary files /dev/null and b/emojis/1f590.png differ diff --git a/emojis/1f595.png b/emojis/1f595.png new file mode 100644 index 00000000..f6806c9c Binary files /dev/null and b/emojis/1f595.png differ diff --git a/emojis/1f596.png b/emojis/1f596.png new file mode 100644 index 00000000..e6ab2524 Binary files /dev/null and b/emojis/1f596.png differ diff --git a/emojis/1f5a5.png b/emojis/1f5a5.png new file mode 100644 index 00000000..c9c28eaa Binary files /dev/null and b/emojis/1f5a5.png differ diff --git a/emojis/1f5a8.png b/emojis/1f5a8.png new file mode 100644 index 00000000..f9956aa3 Binary files /dev/null and b/emojis/1f5a8.png differ diff --git a/emojis/1f5b1.png b/emojis/1f5b1.png new file mode 100644 index 00000000..dbb8e296 Binary files /dev/null and b/emojis/1f5b1.png differ diff --git a/emojis/1f5b2.png b/emojis/1f5b2.png new file mode 100644 index 00000000..647bf79a Binary files /dev/null and b/emojis/1f5b2.png differ diff --git a/emojis/1f5bc.png b/emojis/1f5bc.png new file mode 100644 index 00000000..a570fd28 Binary files /dev/null and b/emojis/1f5bc.png differ diff --git a/emojis/1f5c2.png b/emojis/1f5c2.png new file mode 100644 index 00000000..0ec497b0 Binary files /dev/null and b/emojis/1f5c2.png differ diff --git a/emojis/1f5c3.png b/emojis/1f5c3.png new file mode 100644 index 00000000..37215d0b Binary files /dev/null and b/emojis/1f5c3.png differ diff --git a/emojis/1f5c4.png b/emojis/1f5c4.png new file mode 100644 index 00000000..578de13e Binary files /dev/null and b/emojis/1f5c4.png differ diff --git a/emojis/1f5d1.png b/emojis/1f5d1.png new file mode 100644 index 00000000..db8b3524 Binary files /dev/null and b/emojis/1f5d1.png differ diff --git a/emojis/1f5d2.png b/emojis/1f5d2.png new file mode 100644 index 00000000..8ae63942 Binary files /dev/null and b/emojis/1f5d2.png differ diff --git a/emojis/1f5d3.png b/emojis/1f5d3.png new file mode 100644 index 00000000..549d931f Binary files /dev/null and b/emojis/1f5d3.png differ diff --git a/emojis/1f5dc.png b/emojis/1f5dc.png new file mode 100644 index 00000000..80981d74 Binary files /dev/null and b/emojis/1f5dc.png differ diff --git a/emojis/1f5dd.png b/emojis/1f5dd.png new file mode 100644 index 00000000..b778e702 Binary files /dev/null and b/emojis/1f5dd.png differ diff --git a/emojis/1f5de.png b/emojis/1f5de.png new file mode 100644 index 00000000..ba5b6aab Binary files /dev/null and b/emojis/1f5de.png differ diff --git a/emojis/1f5e1.png b/emojis/1f5e1.png new file mode 100644 index 00000000..d28bb0a3 Binary files /dev/null and b/emojis/1f5e1.png differ diff --git a/emojis/1f5e3.png b/emojis/1f5e3.png new file mode 100644 index 00000000..63f583ae Binary files /dev/null and b/emojis/1f5e3.png differ diff --git a/emojis/1f5e8.png b/emojis/1f5e8.png new file mode 100644 index 00000000..b3d6fdb7 Binary files /dev/null and b/emojis/1f5e8.png differ diff --git a/emojis/1f5ef.png b/emojis/1f5ef.png new file mode 100644 index 00000000..a6c7fb71 Binary files /dev/null and b/emojis/1f5ef.png differ diff --git a/emojis/1f5f3.png b/emojis/1f5f3.png new file mode 100644 index 00000000..1ab91c33 Binary files /dev/null and b/emojis/1f5f3.png differ diff --git a/emojis/1f5fa.png b/emojis/1f5fa.png new file mode 100644 index 00000000..eb7a0bae Binary files /dev/null and b/emojis/1f5fa.png differ diff --git a/emojis/1f5fb.png b/emojis/1f5fb.png new file mode 100644 index 00000000..2effd625 Binary files /dev/null and b/emojis/1f5fb.png differ diff --git a/emojis/1f5fc.png b/emojis/1f5fc.png new file mode 100644 index 00000000..a6f4915e Binary files /dev/null and b/emojis/1f5fc.png differ diff --git a/emojis/1f5fd.png b/emojis/1f5fd.png new file mode 100644 index 00000000..5d4a0fac Binary files /dev/null and b/emojis/1f5fd.png differ diff --git a/emojis/1f5fe.png b/emojis/1f5fe.png new file mode 100644 index 00000000..38181631 Binary files /dev/null and b/emojis/1f5fe.png differ diff --git a/emojis/1f5ff.png b/emojis/1f5ff.png new file mode 100644 index 00000000..cb2695f4 Binary files /dev/null and b/emojis/1f5ff.png differ diff --git a/emojis/1f600.png b/emojis/1f600.png new file mode 100644 index 00000000..4e365499 Binary files /dev/null and b/emojis/1f600.png differ diff --git a/emojis/1f601.png b/emojis/1f601.png new file mode 100644 index 00000000..5faf9160 Binary files /dev/null and b/emojis/1f601.png differ diff --git a/emojis/1f602.png b/emojis/1f602.png new file mode 100644 index 00000000..f4214ea6 Binary files /dev/null and b/emojis/1f602.png differ diff --git a/emojis/1f603.png b/emojis/1f603.png new file mode 100644 index 00000000..b376ae45 Binary files /dev/null and b/emojis/1f603.png differ diff --git a/emojis/1f604.png b/emojis/1f604.png new file mode 100644 index 00000000..696511b1 Binary files /dev/null and b/emojis/1f604.png differ diff --git a/emojis/1f605.png b/emojis/1f605.png new file mode 100644 index 00000000..09d984f9 Binary files /dev/null and b/emojis/1f605.png differ diff --git a/emojis/1f606.png b/emojis/1f606.png new file mode 100644 index 00000000..8459ac05 Binary files /dev/null and b/emojis/1f606.png differ diff --git a/emojis/1f607.png b/emojis/1f607.png new file mode 100644 index 00000000..10cfb624 Binary files /dev/null and b/emojis/1f607.png differ diff --git a/emojis/1f608.png b/emojis/1f608.png new file mode 100644 index 00000000..98b33d73 Binary files /dev/null and b/emojis/1f608.png differ diff --git a/emojis/1f609.png b/emojis/1f609.png new file mode 100644 index 00000000..3685570b Binary files /dev/null and b/emojis/1f609.png differ diff --git a/emojis/1f60a.png b/emojis/1f60a.png new file mode 100644 index 00000000..1c024ea3 Binary files /dev/null and b/emojis/1f60a.png differ diff --git a/emojis/1f60b.png b/emojis/1f60b.png new file mode 100644 index 00000000..bc78070c Binary files /dev/null and b/emojis/1f60b.png differ diff --git a/emojis/1f60c.png b/emojis/1f60c.png new file mode 100644 index 00000000..8f1bb223 Binary files /dev/null and b/emojis/1f60c.png differ diff --git a/emojis/1f60d.png b/emojis/1f60d.png new file mode 100644 index 00000000..3cc9de6c Binary files /dev/null and b/emojis/1f60d.png differ diff --git a/emojis/1f60e.png b/emojis/1f60e.png new file mode 100644 index 00000000..ffd1d387 Binary files /dev/null and b/emojis/1f60e.png differ diff --git a/emojis/1f60f.png b/emojis/1f60f.png new file mode 100644 index 00000000..1bfb23cf Binary files /dev/null and b/emojis/1f60f.png differ diff --git a/emojis/1f610.png b/emojis/1f610.png new file mode 100644 index 00000000..1cf46cd6 Binary files /dev/null and b/emojis/1f610.png differ diff --git a/emojis/1f611.png b/emojis/1f611.png new file mode 100644 index 00000000..0c716f8f Binary files /dev/null and b/emojis/1f611.png differ diff --git a/emojis/1f612.png b/emojis/1f612.png new file mode 100644 index 00000000..b93f0891 Binary files /dev/null and b/emojis/1f612.png differ diff --git a/emojis/1f613.png b/emojis/1f613.png new file mode 100644 index 00000000..5ce1c118 Binary files /dev/null and b/emojis/1f613.png differ diff --git a/emojis/1f614.png b/emojis/1f614.png new file mode 100644 index 00000000..5ab4f722 Binary files /dev/null and b/emojis/1f614.png differ diff --git a/emojis/1f615.png b/emojis/1f615.png new file mode 100644 index 00000000..ca81823b Binary files /dev/null and b/emojis/1f615.png differ diff --git a/emojis/1f616.png b/emojis/1f616.png new file mode 100644 index 00000000..18aa58f9 Binary files /dev/null and b/emojis/1f616.png differ diff --git a/emojis/1f617.png b/emojis/1f617.png new file mode 100644 index 00000000..f7cd367d Binary files /dev/null and b/emojis/1f617.png differ diff --git a/emojis/1f618.png b/emojis/1f618.png new file mode 100644 index 00000000..424d741c Binary files /dev/null and b/emojis/1f618.png differ diff --git a/emojis/1f619.png b/emojis/1f619.png new file mode 100644 index 00000000..b07b54a4 Binary files /dev/null and b/emojis/1f619.png differ diff --git a/emojis/1f61a.png b/emojis/1f61a.png new file mode 100644 index 00000000..282539f5 Binary files /dev/null and b/emojis/1f61a.png differ diff --git a/emojis/1f61b.png b/emojis/1f61b.png new file mode 100644 index 00000000..4147e12c Binary files /dev/null and b/emojis/1f61b.png differ diff --git a/emojis/1f61c.png b/emojis/1f61c.png new file mode 100644 index 00000000..1ff29700 Binary files /dev/null and b/emojis/1f61c.png differ diff --git a/emojis/1f61d.png b/emojis/1f61d.png new file mode 100644 index 00000000..0a7682d3 Binary files /dev/null and b/emojis/1f61d.png differ diff --git a/emojis/1f61e.png b/emojis/1f61e.png new file mode 100644 index 00000000..d28186e8 Binary files /dev/null and b/emojis/1f61e.png differ diff --git a/emojis/1f61f.png b/emojis/1f61f.png new file mode 100644 index 00000000..9be2ad0c Binary files /dev/null and b/emojis/1f61f.png differ diff --git a/emojis/1f620.png b/emojis/1f620.png new file mode 100644 index 00000000..9b42a9a3 Binary files /dev/null and b/emojis/1f620.png differ diff --git a/emojis/1f621.png b/emojis/1f621.png new file mode 100644 index 00000000..bf2776c6 Binary files /dev/null and b/emojis/1f621.png differ diff --git a/emojis/1f622.png b/emojis/1f622.png new file mode 100644 index 00000000..7eba3bc9 Binary files /dev/null and b/emojis/1f622.png differ diff --git a/emojis/1f623.png b/emojis/1f623.png new file mode 100644 index 00000000..e87bf439 Binary files /dev/null and b/emojis/1f623.png differ diff --git a/emojis/1f624.png b/emojis/1f624.png new file mode 100644 index 00000000..35659c7e Binary files /dev/null and b/emojis/1f624.png differ diff --git a/emojis/1f625.png b/emojis/1f625.png new file mode 100644 index 00000000..c7207755 Binary files /dev/null and b/emojis/1f625.png differ diff --git a/emojis/1f626.png b/emojis/1f626.png new file mode 100644 index 00000000..ca95721d Binary files /dev/null and b/emojis/1f626.png differ diff --git a/emojis/1f627.png b/emojis/1f627.png new file mode 100644 index 00000000..3935115d Binary files /dev/null and b/emojis/1f627.png differ diff --git a/emojis/1f628.png b/emojis/1f628.png new file mode 100644 index 00000000..62225029 Binary files /dev/null and b/emojis/1f628.png differ diff --git a/emojis/1f629.png b/emojis/1f629.png new file mode 100644 index 00000000..a7e807c8 Binary files /dev/null and b/emojis/1f629.png differ diff --git a/emojis/1f62a.png b/emojis/1f62a.png new file mode 100644 index 00000000..b37ace8d Binary files /dev/null and b/emojis/1f62a.png differ diff --git a/emojis/1f62b.png b/emojis/1f62b.png new file mode 100644 index 00000000..c11e749d Binary files /dev/null and b/emojis/1f62b.png differ diff --git a/emojis/1f62c.png b/emojis/1f62c.png new file mode 100644 index 00000000..c3498b35 Binary files /dev/null and b/emojis/1f62c.png differ diff --git a/emojis/1f62d.png b/emojis/1f62d.png new file mode 100644 index 00000000..fb8b98bf Binary files /dev/null and b/emojis/1f62d.png differ diff --git a/emojis/1f62e.png b/emojis/1f62e.png new file mode 100644 index 00000000..7a61e5de Binary files /dev/null and b/emojis/1f62e.png differ diff --git a/emojis/1f62f.png b/emojis/1f62f.png new file mode 100644 index 00000000..007a6962 Binary files /dev/null and b/emojis/1f62f.png differ diff --git a/emojis/1f630.png b/emojis/1f630.png new file mode 100644 index 00000000..890af3da Binary files /dev/null and b/emojis/1f630.png differ diff --git a/emojis/1f631.png b/emojis/1f631.png new file mode 100644 index 00000000..05beab2b Binary files /dev/null and b/emojis/1f631.png differ diff --git a/emojis/1f632.png b/emojis/1f632.png new file mode 100644 index 00000000..f72753a3 Binary files /dev/null and b/emojis/1f632.png differ diff --git a/emojis/1f633.png b/emojis/1f633.png new file mode 100644 index 00000000..f9738a66 Binary files /dev/null and b/emojis/1f633.png differ diff --git a/emojis/1f634.png b/emojis/1f634.png new file mode 100644 index 00000000..1e1a9503 Binary files /dev/null and b/emojis/1f634.png differ diff --git a/emojis/1f635.png b/emojis/1f635.png new file mode 100644 index 00000000..ea5a9c74 Binary files /dev/null and b/emojis/1f635.png differ diff --git a/emojis/1f636.png b/emojis/1f636.png new file mode 100644 index 00000000..6ec2eb78 Binary files /dev/null and b/emojis/1f636.png differ diff --git a/emojis/1f637.png b/emojis/1f637.png new file mode 100644 index 00000000..0c8585c8 Binary files /dev/null and b/emojis/1f637.png differ diff --git a/emojis/1f638.png b/emojis/1f638.png new file mode 100644 index 00000000..50467791 Binary files /dev/null and b/emojis/1f638.png differ diff --git a/emojis/1f639.png b/emojis/1f639.png new file mode 100644 index 00000000..02474150 Binary files /dev/null and b/emojis/1f639.png differ diff --git a/emojis/1f63a.png b/emojis/1f63a.png new file mode 100644 index 00000000..8417ee0b Binary files /dev/null and b/emojis/1f63a.png differ diff --git a/emojis/1f63b.png b/emojis/1f63b.png new file mode 100644 index 00000000..4e7573f2 Binary files /dev/null and b/emojis/1f63b.png differ diff --git a/emojis/1f63c.png b/emojis/1f63c.png new file mode 100644 index 00000000..ecd389d0 Binary files /dev/null and b/emojis/1f63c.png differ diff --git a/emojis/1f63d.png b/emojis/1f63d.png new file mode 100644 index 00000000..5c903ad5 Binary files /dev/null and b/emojis/1f63d.png differ diff --git a/emojis/1f63e.png b/emojis/1f63e.png new file mode 100644 index 00000000..c14793f8 Binary files /dev/null and b/emojis/1f63e.png differ diff --git a/emojis/1f63f.png b/emojis/1f63f.png new file mode 100644 index 00000000..747c0532 Binary files /dev/null and b/emojis/1f63f.png differ diff --git a/emojis/1f640.png b/emojis/1f640.png new file mode 100644 index 00000000..8b86a211 Binary files /dev/null and b/emojis/1f640.png differ diff --git a/emojis/1f641.png b/emojis/1f641.png new file mode 100644 index 00000000..7dda3cff Binary files /dev/null and b/emojis/1f641.png differ diff --git a/emojis/1f642.png b/emojis/1f642.png new file mode 100644 index 00000000..fbd559ef Binary files /dev/null and b/emojis/1f642.png differ diff --git a/emojis/1f643.png b/emojis/1f643.png new file mode 100644 index 00000000..9b8c012a Binary files /dev/null and b/emojis/1f643.png differ diff --git a/emojis/1f644.png b/emojis/1f644.png new file mode 100644 index 00000000..180664c2 Binary files /dev/null and b/emojis/1f644.png differ diff --git a/emojis/1f645.png b/emojis/1f645.png new file mode 100644 index 00000000..72158f5c Binary files /dev/null and b/emojis/1f645.png differ diff --git a/emojis/1f646.png b/emojis/1f646.png new file mode 100644 index 00000000..f30acb7a Binary files /dev/null and b/emojis/1f646.png differ diff --git a/emojis/1f647.png b/emojis/1f647.png new file mode 100644 index 00000000..232585dd Binary files /dev/null and b/emojis/1f647.png differ diff --git a/emojis/1f648.png b/emojis/1f648.png new file mode 100644 index 00000000..b45fac21 Binary files /dev/null and b/emojis/1f648.png differ diff --git a/emojis/1f649.png b/emojis/1f649.png new file mode 100644 index 00000000..1ab841bc Binary files /dev/null and b/emojis/1f649.png differ diff --git a/emojis/1f64a.png b/emojis/1f64a.png new file mode 100644 index 00000000..87db6f48 Binary files /dev/null and b/emojis/1f64a.png differ diff --git a/emojis/1f64b.png b/emojis/1f64b.png new file mode 100644 index 00000000..0d5fb91c Binary files /dev/null and b/emojis/1f64b.png differ diff --git a/emojis/1f64c.png b/emojis/1f64c.png new file mode 100644 index 00000000..591729cc Binary files /dev/null and b/emojis/1f64c.png differ diff --git a/emojis/1f64d.png b/emojis/1f64d.png new file mode 100644 index 00000000..493a28ba Binary files /dev/null and b/emojis/1f64d.png differ diff --git a/emojis/1f64e.png b/emojis/1f64e.png new file mode 100644 index 00000000..d84aed27 Binary files /dev/null and b/emojis/1f64e.png differ diff --git a/emojis/1f64f.png b/emojis/1f64f.png new file mode 100644 index 00000000..77a5639e Binary files /dev/null and b/emojis/1f64f.png differ diff --git a/emojis/1f680.png b/emojis/1f680.png new file mode 100644 index 00000000..93c1685e Binary files /dev/null and b/emojis/1f680.png differ diff --git a/emojis/1f681.png b/emojis/1f681.png new file mode 100644 index 00000000..b27b6dea Binary files /dev/null and b/emojis/1f681.png differ diff --git a/emojis/1f682.png b/emojis/1f682.png new file mode 100644 index 00000000..89f94dda Binary files /dev/null and b/emojis/1f682.png differ diff --git a/emojis/1f683.png b/emojis/1f683.png new file mode 100644 index 00000000..a33665ef Binary files /dev/null and b/emojis/1f683.png differ diff --git a/emojis/1f684.png b/emojis/1f684.png new file mode 100644 index 00000000..4b6f70ce Binary files /dev/null and b/emojis/1f684.png differ diff --git a/emojis/1f685.png b/emojis/1f685.png new file mode 100644 index 00000000..349b24ac Binary files /dev/null and b/emojis/1f685.png differ diff --git a/emojis/1f686.png b/emojis/1f686.png new file mode 100644 index 00000000..3c0e0371 Binary files /dev/null and b/emojis/1f686.png differ diff --git a/emojis/1f687.png b/emojis/1f687.png new file mode 100644 index 00000000..a1affaf5 Binary files /dev/null and b/emojis/1f687.png differ diff --git a/emojis/1f688.png b/emojis/1f688.png new file mode 100644 index 00000000..4fbd4758 Binary files /dev/null and b/emojis/1f688.png differ diff --git a/emojis/1f689.png b/emojis/1f689.png new file mode 100644 index 00000000..17254c4b Binary files /dev/null and b/emojis/1f689.png differ diff --git a/emojis/1f68a.png b/emojis/1f68a.png new file mode 100644 index 00000000..270b8068 Binary files /dev/null and b/emojis/1f68a.png differ diff --git a/emojis/1f68b.png b/emojis/1f68b.png new file mode 100644 index 00000000..0600119c Binary files /dev/null and b/emojis/1f68b.png differ diff --git a/emojis/1f68c.png b/emojis/1f68c.png new file mode 100644 index 00000000..d2d853a9 Binary files /dev/null and b/emojis/1f68c.png differ diff --git a/emojis/1f68d.png b/emojis/1f68d.png new file mode 100644 index 00000000..2cafe329 Binary files /dev/null and b/emojis/1f68d.png differ diff --git a/emojis/1f68e.png b/emojis/1f68e.png new file mode 100644 index 00000000..5b4732c5 Binary files /dev/null and b/emojis/1f68e.png differ diff --git a/emojis/1f68f.png b/emojis/1f68f.png new file mode 100644 index 00000000..639c816e Binary files /dev/null and b/emojis/1f68f.png differ diff --git a/emojis/1f690.png b/emojis/1f690.png new file mode 100644 index 00000000..d0e3dae2 Binary files /dev/null and b/emojis/1f690.png differ diff --git a/emojis/1f691.png b/emojis/1f691.png new file mode 100644 index 00000000..fdc56e56 Binary files /dev/null and b/emojis/1f691.png differ diff --git a/emojis/1f692.png b/emojis/1f692.png new file mode 100644 index 00000000..a2508a60 Binary files /dev/null and b/emojis/1f692.png differ diff --git a/emojis/1f693.png b/emojis/1f693.png new file mode 100644 index 00000000..74f6cf1c Binary files /dev/null and b/emojis/1f693.png differ diff --git a/emojis/1f694.png b/emojis/1f694.png new file mode 100644 index 00000000..3f4f8e49 Binary files /dev/null and b/emojis/1f694.png differ diff --git a/emojis/1f695.png b/emojis/1f695.png new file mode 100644 index 00000000..c6a6d9f2 Binary files /dev/null and b/emojis/1f695.png differ diff --git a/emojis/1f696.png b/emojis/1f696.png new file mode 100644 index 00000000..fa144b17 Binary files /dev/null and b/emojis/1f696.png differ diff --git a/emojis/1f697.png b/emojis/1f697.png new file mode 100644 index 00000000..9719519b Binary files /dev/null and b/emojis/1f697.png differ diff --git a/emojis/1f698.png b/emojis/1f698.png new file mode 100644 index 00000000..c6ed50d3 Binary files /dev/null and b/emojis/1f698.png differ diff --git a/emojis/1f699.png b/emojis/1f699.png new file mode 100644 index 00000000..d3d9cdb0 Binary files /dev/null and b/emojis/1f699.png differ diff --git a/emojis/1f69a.png b/emojis/1f69a.png new file mode 100644 index 00000000..0ae78b36 Binary files /dev/null and b/emojis/1f69a.png differ diff --git a/emojis/1f69b.png b/emojis/1f69b.png new file mode 100644 index 00000000..b992f86f Binary files /dev/null and b/emojis/1f69b.png differ diff --git a/emojis/1f69c.png b/emojis/1f69c.png new file mode 100644 index 00000000..aa9bd39d Binary files /dev/null and b/emojis/1f69c.png differ diff --git a/emojis/1f69d.png b/emojis/1f69d.png new file mode 100644 index 00000000..c33a78ce Binary files /dev/null and b/emojis/1f69d.png differ diff --git a/emojis/1f69e.png b/emojis/1f69e.png new file mode 100644 index 00000000..5ea872ef Binary files /dev/null and b/emojis/1f69e.png differ diff --git a/emojis/1f69f.png b/emojis/1f69f.png new file mode 100644 index 00000000..a14614f1 Binary files /dev/null and b/emojis/1f69f.png differ diff --git a/emojis/1f6a0.png b/emojis/1f6a0.png new file mode 100644 index 00000000..ae8dac81 Binary files /dev/null and b/emojis/1f6a0.png differ diff --git a/emojis/1f6a1.png b/emojis/1f6a1.png new file mode 100644 index 00000000..222e7c56 Binary files /dev/null and b/emojis/1f6a1.png differ diff --git a/emojis/1f6a2.png b/emojis/1f6a2.png new file mode 100644 index 00000000..63442976 Binary files /dev/null and b/emojis/1f6a2.png differ diff --git a/emojis/1f6a3.png b/emojis/1f6a3.png new file mode 100644 index 00000000..ef8875dd Binary files /dev/null and b/emojis/1f6a3.png differ diff --git a/emojis/1f6a4.png b/emojis/1f6a4.png new file mode 100644 index 00000000..1154a1ca Binary files /dev/null and b/emojis/1f6a4.png differ diff --git a/emojis/1f6a5.png b/emojis/1f6a5.png new file mode 100644 index 00000000..4fdf44e2 Binary files /dev/null and b/emojis/1f6a5.png differ diff --git a/emojis/1f6a6.png b/emojis/1f6a6.png new file mode 100644 index 00000000..b01c89f7 Binary files /dev/null and b/emojis/1f6a6.png differ diff --git a/emojis/1f6a7.png b/emojis/1f6a7.png new file mode 100644 index 00000000..66c45552 Binary files /dev/null and b/emojis/1f6a7.png differ diff --git a/emojis/1f6a8.png b/emojis/1f6a8.png new file mode 100644 index 00000000..04f88fd7 Binary files /dev/null and b/emojis/1f6a8.png differ diff --git a/emojis/1f6a9.png b/emojis/1f6a9.png new file mode 100644 index 00000000..af55b601 Binary files /dev/null and b/emojis/1f6a9.png differ diff --git a/emojis/1f6aa.png b/emojis/1f6aa.png new file mode 100644 index 00000000..158bd808 Binary files /dev/null and b/emojis/1f6aa.png differ diff --git a/emojis/1f6ab.png b/emojis/1f6ab.png new file mode 100644 index 00000000..c52c0871 Binary files /dev/null and b/emojis/1f6ab.png differ diff --git a/emojis/1f6ac.png b/emojis/1f6ac.png new file mode 100644 index 00000000..ab6b73dc Binary files /dev/null and b/emojis/1f6ac.png differ diff --git a/emojis/1f6ad.png b/emojis/1f6ad.png new file mode 100644 index 00000000..b20500a4 Binary files /dev/null and b/emojis/1f6ad.png differ diff --git a/emojis/1f6ae.png b/emojis/1f6ae.png new file mode 100644 index 00000000..6e09af04 Binary files /dev/null and b/emojis/1f6ae.png differ diff --git a/emojis/1f6af.png b/emojis/1f6af.png new file mode 100644 index 00000000..07d02708 Binary files /dev/null and b/emojis/1f6af.png differ diff --git a/emojis/1f6b0.png b/emojis/1f6b0.png new file mode 100644 index 00000000..833d3817 Binary files /dev/null and b/emojis/1f6b0.png differ diff --git a/emojis/1f6b1.png b/emojis/1f6b1.png new file mode 100644 index 00000000..9977beac Binary files /dev/null and b/emojis/1f6b1.png differ diff --git a/emojis/1f6b2.png b/emojis/1f6b2.png new file mode 100644 index 00000000..953ee5e3 Binary files /dev/null and b/emojis/1f6b2.png differ diff --git a/emojis/1f6b3.png b/emojis/1f6b3.png new file mode 100644 index 00000000..8ff4749e Binary files /dev/null and b/emojis/1f6b3.png differ diff --git a/emojis/1f6b4.png b/emojis/1f6b4.png new file mode 100644 index 00000000..9d298195 Binary files /dev/null and b/emojis/1f6b4.png differ diff --git a/emojis/1f6b5.png b/emojis/1f6b5.png new file mode 100644 index 00000000..2179499a Binary files /dev/null and b/emojis/1f6b5.png differ diff --git a/emojis/1f6b6.png b/emojis/1f6b6.png new file mode 100644 index 00000000..81dec26f Binary files /dev/null and b/emojis/1f6b6.png differ diff --git a/emojis/1f6b7.png b/emojis/1f6b7.png new file mode 100644 index 00000000..e03e96ad Binary files /dev/null and b/emojis/1f6b7.png differ diff --git a/emojis/1f6b8.png b/emojis/1f6b8.png new file mode 100644 index 00000000..956494ca Binary files /dev/null and b/emojis/1f6b8.png differ diff --git a/emojis/1f6b9.png b/emojis/1f6b9.png new file mode 100644 index 00000000..43d0d168 Binary files /dev/null and b/emojis/1f6b9.png differ diff --git a/emojis/1f6ba.png b/emojis/1f6ba.png new file mode 100644 index 00000000..78d91b49 Binary files /dev/null and b/emojis/1f6ba.png differ diff --git a/emojis/1f6bb.png b/emojis/1f6bb.png new file mode 100644 index 00000000..2cd688eb Binary files /dev/null and b/emojis/1f6bb.png differ diff --git a/emojis/1f6bc.png b/emojis/1f6bc.png new file mode 100644 index 00000000..4f7a700d Binary files /dev/null and b/emojis/1f6bc.png differ diff --git a/emojis/1f6bd.png b/emojis/1f6bd.png new file mode 100644 index 00000000..2171e4bc Binary files /dev/null and b/emojis/1f6bd.png differ diff --git a/emojis/1f6be.png b/emojis/1f6be.png new file mode 100644 index 00000000..03c8928d Binary files /dev/null and b/emojis/1f6be.png differ diff --git a/emojis/1f6bf.png b/emojis/1f6bf.png new file mode 100644 index 00000000..de9c3a9d Binary files /dev/null and b/emojis/1f6bf.png differ diff --git a/emojis/1f6c0.png b/emojis/1f6c0.png new file mode 100644 index 00000000..b7b884a3 Binary files /dev/null and b/emojis/1f6c0.png differ diff --git a/emojis/1f6c1.png b/emojis/1f6c1.png new file mode 100644 index 00000000..701dca1d Binary files /dev/null and b/emojis/1f6c1.png differ diff --git a/emojis/1f6c2.png b/emojis/1f6c2.png new file mode 100644 index 00000000..a5ba36c2 Binary files /dev/null and b/emojis/1f6c2.png differ diff --git a/emojis/1f6c3.png b/emojis/1f6c3.png new file mode 100644 index 00000000..fc057b9d Binary files /dev/null and b/emojis/1f6c3.png differ diff --git a/emojis/1f6c4.png b/emojis/1f6c4.png new file mode 100644 index 00000000..c668ac2b Binary files /dev/null and b/emojis/1f6c4.png differ diff --git a/emojis/1f6c5.png b/emojis/1f6c5.png new file mode 100644 index 00000000..4c0d92aa Binary files /dev/null and b/emojis/1f6c5.png differ diff --git a/emojis/1f6cb.png b/emojis/1f6cb.png new file mode 100644 index 00000000..b706ffe5 Binary files /dev/null and b/emojis/1f6cb.png differ diff --git a/emojis/1f6cc.png b/emojis/1f6cc.png new file mode 100644 index 00000000..5ff54664 Binary files /dev/null and b/emojis/1f6cc.png differ diff --git a/emojis/1f6cd.png b/emojis/1f6cd.png new file mode 100644 index 00000000..bc84c66a Binary files /dev/null and b/emojis/1f6cd.png differ diff --git a/emojis/1f6ce.png b/emojis/1f6ce.png new file mode 100644 index 00000000..d3755509 Binary files /dev/null and b/emojis/1f6ce.png differ diff --git a/emojis/1f6cf.png b/emojis/1f6cf.png new file mode 100644 index 00000000..01140e43 Binary files /dev/null and b/emojis/1f6cf.png differ diff --git a/emojis/1f6d0.png b/emojis/1f6d0.png new file mode 100644 index 00000000..31f2ee04 Binary files /dev/null and b/emojis/1f6d0.png differ diff --git a/emojis/1f6e0.png b/emojis/1f6e0.png new file mode 100644 index 00000000..5bc97f95 Binary files /dev/null and b/emojis/1f6e0.png differ diff --git a/emojis/1f6e1.png b/emojis/1f6e1.png new file mode 100644 index 00000000..3f9ea922 Binary files /dev/null and b/emojis/1f6e1.png differ diff --git a/emojis/1f6e2.png b/emojis/1f6e2.png new file mode 100644 index 00000000..98d6d769 Binary files /dev/null and b/emojis/1f6e2.png differ diff --git a/emojis/1f6e3.png b/emojis/1f6e3.png new file mode 100644 index 00000000..57f1521a Binary files /dev/null and b/emojis/1f6e3.png differ diff --git a/emojis/1f6e4.png b/emojis/1f6e4.png new file mode 100644 index 00000000..c7c848a5 Binary files /dev/null and b/emojis/1f6e4.png differ diff --git a/emojis/1f6e5.png b/emojis/1f6e5.png new file mode 100644 index 00000000..89cdda4d Binary files /dev/null and b/emojis/1f6e5.png differ diff --git a/emojis/1f6e9.png b/emojis/1f6e9.png new file mode 100644 index 00000000..30ff9bf2 Binary files /dev/null and b/emojis/1f6e9.png differ diff --git a/emojis/1f6eb.png b/emojis/1f6eb.png new file mode 100644 index 00000000..863c6bbd Binary files /dev/null and b/emojis/1f6eb.png differ diff --git a/emojis/1f6ec.png b/emojis/1f6ec.png new file mode 100644 index 00000000..8d860fe3 Binary files /dev/null and b/emojis/1f6ec.png differ diff --git a/emojis/1f6f0.png b/emojis/1f6f0.png new file mode 100644 index 00000000..19f9a1d2 Binary files /dev/null and b/emojis/1f6f0.png differ diff --git a/emojis/1f6f3.png b/emojis/1f6f3.png new file mode 100644 index 00000000..43c09dca Binary files /dev/null and b/emojis/1f6f3.png differ diff --git a/emojis/1f910.png b/emojis/1f910.png new file mode 100644 index 00000000..4c6e9459 Binary files /dev/null and b/emojis/1f910.png differ diff --git a/emojis/1f911.png b/emojis/1f911.png new file mode 100644 index 00000000..eb056616 Binary files /dev/null and b/emojis/1f911.png differ diff --git a/emojis/1f912.png b/emojis/1f912.png new file mode 100644 index 00000000..7a622063 Binary files /dev/null and b/emojis/1f912.png differ diff --git a/emojis/1f913.png b/emojis/1f913.png new file mode 100644 index 00000000..60b44c16 Binary files /dev/null and b/emojis/1f913.png differ diff --git a/emojis/1f914.png b/emojis/1f914.png new file mode 100644 index 00000000..3bcf6096 Binary files /dev/null and b/emojis/1f914.png differ diff --git a/emojis/1f915.png b/emojis/1f915.png new file mode 100644 index 00000000..edc696d1 Binary files /dev/null and b/emojis/1f915.png differ diff --git a/emojis/1f916.png b/emojis/1f916.png new file mode 100644 index 00000000..26e99159 Binary files /dev/null and b/emojis/1f916.png differ diff --git a/emojis/1f917.png b/emojis/1f917.png new file mode 100644 index 00000000..26deb1cc Binary files /dev/null and b/emojis/1f917.png differ diff --git a/emojis/1f918.png b/emojis/1f918.png new file mode 100644 index 00000000..0d386273 Binary files /dev/null and b/emojis/1f918.png differ diff --git a/emojis/1f980.png b/emojis/1f980.png new file mode 100644 index 00000000..b128f804 Binary files /dev/null and b/emojis/1f980.png differ diff --git a/emojis/1f981.png b/emojis/1f981.png new file mode 100644 index 00000000..c3a966a2 Binary files /dev/null and b/emojis/1f981.png differ diff --git a/emojis/1f982.png b/emojis/1f982.png new file mode 100644 index 00000000..cad2d3d8 Binary files /dev/null and b/emojis/1f982.png differ diff --git a/emojis/1f983.png b/emojis/1f983.png new file mode 100644 index 00000000..7a83b3eb Binary files /dev/null and b/emojis/1f983.png differ diff --git a/emojis/1f984.png b/emojis/1f984.png new file mode 100644 index 00000000..18d73fad Binary files /dev/null and b/emojis/1f984.png differ diff --git a/emojis/1f9c0.png b/emojis/1f9c0.png new file mode 100644 index 00000000..ce5e813b Binary files /dev/null and b/emojis/1f9c0.png differ diff --git a/emojis/203c.png b/emojis/203c.png new file mode 100644 index 00000000..434405b1 Binary files /dev/null and b/emojis/203c.png differ diff --git a/emojis/2049.png b/emojis/2049.png new file mode 100644 index 00000000..bbf863cf Binary files /dev/null and b/emojis/2049.png differ diff --git a/emojis/2139.png b/emojis/2139.png new file mode 100644 index 00000000..e123e25e Binary files /dev/null and b/emojis/2139.png differ diff --git a/emojis/2194.png b/emojis/2194.png new file mode 100644 index 00000000..0422ac4d Binary files /dev/null and b/emojis/2194.png differ diff --git a/emojis/2195.png b/emojis/2195.png new file mode 100644 index 00000000..5b9534d9 Binary files /dev/null and b/emojis/2195.png differ diff --git a/emojis/2196.png b/emojis/2196.png new file mode 100644 index 00000000..62e16810 Binary files /dev/null and b/emojis/2196.png differ diff --git a/emojis/2197.png b/emojis/2197.png new file mode 100644 index 00000000..ee00e481 Binary files /dev/null and b/emojis/2197.png differ diff --git a/emojis/2198.png b/emojis/2198.png new file mode 100644 index 00000000..dab5e291 Binary files /dev/null and b/emojis/2198.png differ diff --git a/emojis/2199.png b/emojis/2199.png new file mode 100644 index 00000000..08a89ec6 Binary files /dev/null and b/emojis/2199.png differ diff --git a/emojis/21a9.png b/emojis/21a9.png new file mode 100644 index 00000000..d68c9b12 Binary files /dev/null and b/emojis/21a9.png differ diff --git a/emojis/21aa.png b/emojis/21aa.png new file mode 100644 index 00000000..6a969834 Binary files /dev/null and b/emojis/21aa.png differ diff --git a/emojis/231a.png b/emojis/231a.png new file mode 100644 index 00000000..3809418c Binary files /dev/null and b/emojis/231a.png differ diff --git a/emojis/231b.png b/emojis/231b.png new file mode 100644 index 00000000..3e0e734a Binary files /dev/null and b/emojis/231b.png differ diff --git a/emojis/2328.png b/emojis/2328.png new file mode 100644 index 00000000..491d7988 Binary files /dev/null and b/emojis/2328.png differ diff --git a/emojis/23e9.png b/emojis/23e9.png new file mode 100644 index 00000000..3226696d Binary files /dev/null and b/emojis/23e9.png differ diff --git a/emojis/23ea.png b/emojis/23ea.png new file mode 100644 index 00000000..d27d2c98 Binary files /dev/null and b/emojis/23ea.png differ diff --git a/emojis/23eb.png b/emojis/23eb.png new file mode 100644 index 00000000..b5fc2d3c Binary files /dev/null and b/emojis/23eb.png differ diff --git a/emojis/23ec.png b/emojis/23ec.png new file mode 100644 index 00000000..9d1c2bbd Binary files /dev/null and b/emojis/23ec.png differ diff --git a/emojis/23ed.png b/emojis/23ed.png new file mode 100644 index 00000000..8772ba28 Binary files /dev/null and b/emojis/23ed.png differ diff --git a/emojis/23ee.png b/emojis/23ee.png new file mode 100644 index 00000000..7c820c80 Binary files /dev/null and b/emojis/23ee.png differ diff --git a/emojis/23ef.png b/emojis/23ef.png new file mode 100644 index 00000000..f3d8118e Binary files /dev/null and b/emojis/23ef.png differ diff --git a/emojis/23f0.png b/emojis/23f0.png new file mode 100644 index 00000000..fccd685a Binary files /dev/null and b/emojis/23f0.png differ diff --git a/emojis/23f1.png b/emojis/23f1.png new file mode 100644 index 00000000..b6982a27 Binary files /dev/null and b/emojis/23f1.png differ diff --git a/emojis/23f2.png b/emojis/23f2.png new file mode 100644 index 00000000..c6a7ea7a Binary files /dev/null and b/emojis/23f2.png differ diff --git a/emojis/23f3.png b/emojis/23f3.png new file mode 100644 index 00000000..b6e5675d Binary files /dev/null and b/emojis/23f3.png differ diff --git a/emojis/23f8.png b/emojis/23f8.png new file mode 100644 index 00000000..a7993a4f Binary files /dev/null and b/emojis/23f8.png differ diff --git a/emojis/23f9.png b/emojis/23f9.png new file mode 100644 index 00000000..3a34cb7f Binary files /dev/null and b/emojis/23f9.png differ diff --git a/emojis/23fa.png b/emojis/23fa.png new file mode 100644 index 00000000..72c5a709 Binary files /dev/null and b/emojis/23fa.png differ diff --git a/emojis/24c2.png b/emojis/24c2.png new file mode 100644 index 00000000..c3f38182 Binary files /dev/null and b/emojis/24c2.png differ diff --git a/emojis/25aa.png b/emojis/25aa.png new file mode 100644 index 00000000..c3373520 Binary files /dev/null and b/emojis/25aa.png differ diff --git a/emojis/25ab.png b/emojis/25ab.png new file mode 100644 index 00000000..c65f7e62 Binary files /dev/null and b/emojis/25ab.png differ diff --git a/emojis/25b6.png b/emojis/25b6.png new file mode 100644 index 00000000..4b1fb019 Binary files /dev/null and b/emojis/25b6.png differ diff --git a/emojis/25c0.png b/emojis/25c0.png new file mode 100644 index 00000000..b5db584f Binary files /dev/null and b/emojis/25c0.png differ diff --git a/emojis/25fb.png b/emojis/25fb.png new file mode 100644 index 00000000..2b0293fe Binary files /dev/null and b/emojis/25fb.png differ diff --git a/emojis/25fc.png b/emojis/25fc.png new file mode 100644 index 00000000..60bddb0b Binary files /dev/null and b/emojis/25fc.png differ diff --git a/emojis/25fd.png b/emojis/25fd.png new file mode 100644 index 00000000..b06389d5 Binary files /dev/null and b/emojis/25fd.png differ diff --git a/emojis/25fe.png b/emojis/25fe.png new file mode 100644 index 00000000..1e4af908 Binary files /dev/null and b/emojis/25fe.png differ diff --git a/emojis/2600.png b/emojis/2600.png new file mode 100644 index 00000000..9047237c Binary files /dev/null and b/emojis/2600.png differ diff --git a/emojis/2601.png b/emojis/2601.png new file mode 100644 index 00000000..8274e515 Binary files /dev/null and b/emojis/2601.png differ diff --git a/emojis/2602.png b/emojis/2602.png new file mode 100644 index 00000000..0e2d8ce2 Binary files /dev/null and b/emojis/2602.png differ diff --git a/emojis/2603.png b/emojis/2603.png new file mode 100644 index 00000000..80a03bdb Binary files /dev/null and b/emojis/2603.png differ diff --git a/emojis/2604.png b/emojis/2604.png new file mode 100644 index 00000000..7f0c3438 Binary files /dev/null and b/emojis/2604.png differ diff --git a/emojis/260e.png b/emojis/260e.png new file mode 100644 index 00000000..eaee53d6 Binary files /dev/null and b/emojis/260e.png differ diff --git a/emojis/2611.png b/emojis/2611.png new file mode 100644 index 00000000..46e861f4 Binary files /dev/null and b/emojis/2611.png differ diff --git a/emojis/2614.png b/emojis/2614.png new file mode 100644 index 00000000..8379d6fa Binary files /dev/null and b/emojis/2614.png differ diff --git a/emojis/2615.png b/emojis/2615.png new file mode 100644 index 00000000..cf9a689c Binary files /dev/null and b/emojis/2615.png differ diff --git a/emojis/2618.png b/emojis/2618.png new file mode 100644 index 00000000..0da05d4e Binary files /dev/null and b/emojis/2618.png differ diff --git a/emojis/261d.png b/emojis/261d.png new file mode 100644 index 00000000..8aabe3d0 Binary files /dev/null and b/emojis/261d.png differ diff --git a/emojis/2620.png b/emojis/2620.png new file mode 100644 index 00000000..0aa44690 Binary files /dev/null and b/emojis/2620.png differ diff --git a/emojis/2622.png b/emojis/2622.png new file mode 100644 index 00000000..e2eac944 Binary files /dev/null and b/emojis/2622.png differ diff --git a/emojis/2623.png b/emojis/2623.png new file mode 100644 index 00000000..6e0d0122 Binary files /dev/null and b/emojis/2623.png differ diff --git a/emojis/2626.png b/emojis/2626.png new file mode 100644 index 00000000..09146d5d Binary files /dev/null and b/emojis/2626.png differ diff --git a/emojis/262a.png b/emojis/262a.png new file mode 100644 index 00000000..fe83d143 Binary files /dev/null and b/emojis/262a.png differ diff --git a/emojis/262e.png b/emojis/262e.png new file mode 100644 index 00000000..d17a2512 Binary files /dev/null and b/emojis/262e.png differ diff --git a/emojis/262f.png b/emojis/262f.png new file mode 100644 index 00000000..a02c9adc Binary files /dev/null and b/emojis/262f.png differ diff --git a/emojis/2638.png b/emojis/2638.png new file mode 100644 index 00000000..53bad371 Binary files /dev/null and b/emojis/2638.png differ diff --git a/emojis/2639.png b/emojis/2639.png new file mode 100644 index 00000000..9c9221f8 Binary files /dev/null and b/emojis/2639.png differ diff --git a/emojis/263a.png b/emojis/263a.png new file mode 100644 index 00000000..8581bd29 Binary files /dev/null and b/emojis/263a.png differ diff --git a/emojis/2648.png b/emojis/2648.png new file mode 100644 index 00000000..5a84d63c Binary files /dev/null and b/emojis/2648.png differ diff --git a/emojis/2649.png b/emojis/2649.png new file mode 100644 index 00000000..1d803a61 Binary files /dev/null and b/emojis/2649.png differ diff --git a/emojis/264a.png b/emojis/264a.png new file mode 100644 index 00000000..9e16311d Binary files /dev/null and b/emojis/264a.png differ diff --git a/emojis/264b.png b/emojis/264b.png new file mode 100644 index 00000000..9c2e4546 Binary files /dev/null and b/emojis/264b.png differ diff --git a/emojis/264c.png b/emojis/264c.png new file mode 100644 index 00000000..a050b90e Binary files /dev/null and b/emojis/264c.png differ diff --git a/emojis/264d.png b/emojis/264d.png new file mode 100644 index 00000000..c3dd210b Binary files /dev/null and b/emojis/264d.png differ diff --git a/emojis/264e.png b/emojis/264e.png new file mode 100644 index 00000000..b22a4515 Binary files /dev/null and b/emojis/264e.png differ diff --git a/emojis/264f.png b/emojis/264f.png new file mode 100644 index 00000000..7ff3fe83 Binary files /dev/null and b/emojis/264f.png differ diff --git a/emojis/2650.png b/emojis/2650.png new file mode 100644 index 00000000..c2248b7e Binary files /dev/null and b/emojis/2650.png differ diff --git a/emojis/2651.png b/emojis/2651.png new file mode 100644 index 00000000..ff58cf02 Binary files /dev/null and b/emojis/2651.png differ diff --git a/emojis/2652.png b/emojis/2652.png new file mode 100644 index 00000000..22bbd85f Binary files /dev/null and b/emojis/2652.png differ diff --git a/emojis/2653.png b/emojis/2653.png new file mode 100644 index 00000000..43e0d45f Binary files /dev/null and b/emojis/2653.png differ diff --git a/emojis/2660.png b/emojis/2660.png new file mode 100644 index 00000000..c1f25a8b Binary files /dev/null and b/emojis/2660.png differ diff --git a/emojis/2663.png b/emojis/2663.png new file mode 100644 index 00000000..419f9be4 Binary files /dev/null and b/emojis/2663.png differ diff --git a/emojis/2665.png b/emojis/2665.png new file mode 100644 index 00000000..dca527bf Binary files /dev/null and b/emojis/2665.png differ diff --git a/emojis/2666.png b/emojis/2666.png new file mode 100644 index 00000000..90154935 Binary files /dev/null and b/emojis/2666.png differ diff --git a/emojis/2668.png b/emojis/2668.png new file mode 100644 index 00000000..6ddd77c9 Binary files /dev/null and b/emojis/2668.png differ diff --git a/emojis/267b.png b/emojis/267b.png new file mode 100644 index 00000000..87f432fa Binary files /dev/null and b/emojis/267b.png differ diff --git a/emojis/267f.png b/emojis/267f.png new file mode 100644 index 00000000..efc9909b Binary files /dev/null and b/emojis/267f.png differ diff --git a/emojis/2692.png b/emojis/2692.png new file mode 100644 index 00000000..579984c4 Binary files /dev/null and b/emojis/2692.png differ diff --git a/emojis/2693.png b/emojis/2693.png new file mode 100644 index 00000000..31896a55 Binary files /dev/null and b/emojis/2693.png differ diff --git a/emojis/2694.png b/emojis/2694.png new file mode 100644 index 00000000..d87a6a60 Binary files /dev/null and b/emojis/2694.png differ diff --git a/emojis/2696.png b/emojis/2696.png new file mode 100644 index 00000000..8846c875 Binary files /dev/null and b/emojis/2696.png differ diff --git a/emojis/2697.png b/emojis/2697.png new file mode 100644 index 00000000..ad4975ef Binary files /dev/null and b/emojis/2697.png differ diff --git a/emojis/2699.png b/emojis/2699.png new file mode 100644 index 00000000..9bf94aae Binary files /dev/null and b/emojis/2699.png differ diff --git a/emojis/269b.png b/emojis/269b.png new file mode 100644 index 00000000..0c70f287 Binary files /dev/null and b/emojis/269b.png differ diff --git a/emojis/269c.png b/emojis/269c.png new file mode 100644 index 00000000..19d2a828 Binary files /dev/null and b/emojis/269c.png differ diff --git a/emojis/26a0.png b/emojis/26a0.png new file mode 100644 index 00000000..ea27d15c Binary files /dev/null and b/emojis/26a0.png differ diff --git a/emojis/26a1.png b/emojis/26a1.png new file mode 100644 index 00000000..e7e7b75a Binary files /dev/null and b/emojis/26a1.png differ diff --git a/emojis/26aa.png b/emojis/26aa.png new file mode 100644 index 00000000..13e73518 Binary files /dev/null and b/emojis/26aa.png differ diff --git a/emojis/26ab.png b/emojis/26ab.png new file mode 100644 index 00000000..a20ddf6e Binary files /dev/null and b/emojis/26ab.png differ diff --git a/emojis/26b0.png b/emojis/26b0.png new file mode 100644 index 00000000..cd08d05a Binary files /dev/null and b/emojis/26b0.png differ diff --git a/emojis/26b1.png b/emojis/26b1.png new file mode 100644 index 00000000..afd6a659 Binary files /dev/null and b/emojis/26b1.png differ diff --git a/emojis/26bd.png b/emojis/26bd.png new file mode 100644 index 00000000..7e219a31 Binary files /dev/null and b/emojis/26bd.png differ diff --git a/emojis/26be.png b/emojis/26be.png new file mode 100644 index 00000000..c771cc2b Binary files /dev/null and b/emojis/26be.png differ diff --git a/emojis/26c4.png b/emojis/26c4.png new file mode 100644 index 00000000..b1835392 Binary files /dev/null and b/emojis/26c4.png differ diff --git a/emojis/26c5.png b/emojis/26c5.png new file mode 100644 index 00000000..cf4e1654 Binary files /dev/null and b/emojis/26c5.png differ diff --git a/emojis/26c8.png b/emojis/26c8.png new file mode 100644 index 00000000..ef2bd558 Binary files /dev/null and b/emojis/26c8.png differ diff --git a/emojis/26ce.png b/emojis/26ce.png new file mode 100644 index 00000000..f2fcb622 Binary files /dev/null and b/emojis/26ce.png differ diff --git a/emojis/26cf.png b/emojis/26cf.png new file mode 100644 index 00000000..9f16142a Binary files /dev/null and b/emojis/26cf.png differ diff --git a/emojis/26d1.png b/emojis/26d1.png new file mode 100644 index 00000000..3995af8f Binary files /dev/null and b/emojis/26d1.png differ diff --git a/emojis/26d3.png b/emojis/26d3.png new file mode 100644 index 00000000..9ff6397b Binary files /dev/null and b/emojis/26d3.png differ diff --git a/emojis/26d4.png b/emojis/26d4.png new file mode 100644 index 00000000..d28699ce Binary files /dev/null and b/emojis/26d4.png differ diff --git a/emojis/26e9.png b/emojis/26e9.png new file mode 100644 index 00000000..86902414 Binary files /dev/null and b/emojis/26e9.png differ diff --git a/emojis/26ea.png b/emojis/26ea.png new file mode 100644 index 00000000..e7e94332 Binary files /dev/null and b/emojis/26ea.png differ diff --git a/emojis/26f0.png b/emojis/26f0.png new file mode 100644 index 00000000..6ac65545 Binary files /dev/null and b/emojis/26f0.png differ diff --git a/emojis/26f1.png b/emojis/26f1.png new file mode 100644 index 00000000..7299fe0c Binary files /dev/null and b/emojis/26f1.png differ diff --git a/emojis/26f2.png b/emojis/26f2.png new file mode 100644 index 00000000..630fe352 Binary files /dev/null and b/emojis/26f2.png differ diff --git a/emojis/26f3.png b/emojis/26f3.png new file mode 100644 index 00000000..6f28da19 Binary files /dev/null and b/emojis/26f3.png differ diff --git a/emojis/26f4.png b/emojis/26f4.png new file mode 100644 index 00000000..e37e0b6a Binary files /dev/null and b/emojis/26f4.png differ diff --git a/emojis/26f5.png b/emojis/26f5.png new file mode 100644 index 00000000..52d88eea Binary files /dev/null and b/emojis/26f5.png differ diff --git a/emojis/26f7.png b/emojis/26f7.png new file mode 100644 index 00000000..6f5559e0 Binary files /dev/null and b/emojis/26f7.png differ diff --git a/emojis/26f8.png b/emojis/26f8.png new file mode 100644 index 00000000..c8d1fa26 Binary files /dev/null and b/emojis/26f8.png differ diff --git a/emojis/26f9.png b/emojis/26f9.png new file mode 100644 index 00000000..c1f2c3bb Binary files /dev/null and b/emojis/26f9.png differ diff --git a/emojis/26fa.png b/emojis/26fa.png new file mode 100644 index 00000000..bd778cd7 Binary files /dev/null and b/emojis/26fa.png differ diff --git a/emojis/26fd.png b/emojis/26fd.png new file mode 100644 index 00000000..f5795adc Binary files /dev/null and b/emojis/26fd.png differ diff --git a/emojis/2702.png b/emojis/2702.png new file mode 100644 index 00000000..dcb526df Binary files /dev/null and b/emojis/2702.png differ diff --git a/emojis/2705.png b/emojis/2705.png new file mode 100644 index 00000000..09db8ce1 Binary files /dev/null and b/emojis/2705.png differ diff --git a/emojis/2708.png b/emojis/2708.png new file mode 100644 index 00000000..7c83ff3c Binary files /dev/null and b/emojis/2708.png differ diff --git a/emojis/2709.png b/emojis/2709.png new file mode 100644 index 00000000..4c890f0b Binary files /dev/null and b/emojis/2709.png differ diff --git a/emojis/270a.png b/emojis/270a.png new file mode 100644 index 00000000..a7130bba Binary files /dev/null and b/emojis/270a.png differ diff --git a/emojis/270b.png b/emojis/270b.png new file mode 100644 index 00000000..2f377930 Binary files /dev/null and b/emojis/270b.png differ diff --git a/emojis/270c.png b/emojis/270c.png new file mode 100644 index 00000000..072dcbae Binary files /dev/null and b/emojis/270c.png differ diff --git a/emojis/270d.png b/emojis/270d.png new file mode 100644 index 00000000..7336de9a Binary files /dev/null and b/emojis/270d.png differ diff --git a/emojis/270f.png b/emojis/270f.png new file mode 100644 index 00000000..6d634bd1 Binary files /dev/null and b/emojis/270f.png differ diff --git a/emojis/2712.png b/emojis/2712.png new file mode 100644 index 00000000..6c70e714 Binary files /dev/null and b/emojis/2712.png differ diff --git a/emojis/2714.png b/emojis/2714.png new file mode 100644 index 00000000..ca960039 Binary files /dev/null and b/emojis/2714.png differ diff --git a/emojis/2716.png b/emojis/2716.png new file mode 100644 index 00000000..2494e066 Binary files /dev/null and b/emojis/2716.png differ diff --git a/emojis/271d.png b/emojis/271d.png new file mode 100644 index 00000000..1f98761e Binary files /dev/null and b/emojis/271d.png differ diff --git a/emojis/2721.png b/emojis/2721.png new file mode 100644 index 00000000..91ea2f87 Binary files /dev/null and b/emojis/2721.png differ diff --git a/emojis/2728.png b/emojis/2728.png new file mode 100644 index 00000000..8916b69e Binary files /dev/null and b/emojis/2728.png differ diff --git a/emojis/2733.png b/emojis/2733.png new file mode 100644 index 00000000..bcd79e20 Binary files /dev/null and b/emojis/2733.png differ diff --git a/emojis/2734.png b/emojis/2734.png new file mode 100644 index 00000000..5fe58b23 Binary files /dev/null and b/emojis/2734.png differ diff --git a/emojis/2744.png b/emojis/2744.png new file mode 100644 index 00000000..f64c2f15 Binary files /dev/null and b/emojis/2744.png differ diff --git a/emojis/2747.png b/emojis/2747.png new file mode 100644 index 00000000..e6f2395d Binary files /dev/null and b/emojis/2747.png differ diff --git a/emojis/274c.png b/emojis/274c.png new file mode 100644 index 00000000..65bbadaa Binary files /dev/null and b/emojis/274c.png differ diff --git a/emojis/274e.png b/emojis/274e.png new file mode 100644 index 00000000..d85154ff Binary files /dev/null and b/emojis/274e.png differ diff --git a/emojis/2753.png b/emojis/2753.png new file mode 100644 index 00000000..1d8cf201 Binary files /dev/null and b/emojis/2753.png differ diff --git a/emojis/2754.png b/emojis/2754.png new file mode 100644 index 00000000..0c755b3a Binary files /dev/null and b/emojis/2754.png differ diff --git a/emojis/2755.png b/emojis/2755.png new file mode 100644 index 00000000..58fdc859 Binary files /dev/null and b/emojis/2755.png differ diff --git a/emojis/2757.png b/emojis/2757.png new file mode 100644 index 00000000..7587fe50 Binary files /dev/null and b/emojis/2757.png differ diff --git a/emojis/2763.png b/emojis/2763.png new file mode 100644 index 00000000..d6a1b045 Binary files /dev/null and b/emojis/2763.png differ diff --git a/emojis/2764.png b/emojis/2764.png new file mode 100644 index 00000000..02742f1d Binary files /dev/null and b/emojis/2764.png differ diff --git a/emojis/2795.png b/emojis/2795.png new file mode 100644 index 00000000..f351ea74 Binary files /dev/null and b/emojis/2795.png differ diff --git a/emojis/2796.png b/emojis/2796.png new file mode 100644 index 00000000..c026e2f7 Binary files /dev/null and b/emojis/2796.png differ diff --git a/emojis/2797.png b/emojis/2797.png new file mode 100644 index 00000000..18964c87 Binary files /dev/null and b/emojis/2797.png differ diff --git a/emojis/27a1.png b/emojis/27a1.png new file mode 100644 index 00000000..5aa3f8c8 Binary files /dev/null and b/emojis/27a1.png differ diff --git a/emojis/27b0.png b/emojis/27b0.png new file mode 100644 index 00000000..b2ec6298 Binary files /dev/null and b/emojis/27b0.png differ diff --git a/emojis/27bf.png b/emojis/27bf.png new file mode 100644 index 00000000..1e4954c5 Binary files /dev/null and b/emojis/27bf.png differ diff --git a/emojis/2934.png b/emojis/2934.png new file mode 100644 index 00000000..b1597912 Binary files /dev/null and b/emojis/2934.png differ diff --git a/emojis/2935.png b/emojis/2935.png new file mode 100644 index 00000000..18d3b1f9 Binary files /dev/null and b/emojis/2935.png differ diff --git a/emojis/2b05.png b/emojis/2b05.png new file mode 100644 index 00000000..cdb6846e Binary files /dev/null and b/emojis/2b05.png differ diff --git a/emojis/2b06.png b/emojis/2b06.png new file mode 100644 index 00000000..c5b2804c Binary files /dev/null and b/emojis/2b06.png differ diff --git a/emojis/2b07.png b/emojis/2b07.png new file mode 100644 index 00000000..95ab6d1a Binary files /dev/null and b/emojis/2b07.png differ diff --git a/emojis/2b1b.png b/emojis/2b1b.png new file mode 100644 index 00000000..71c01487 Binary files /dev/null and b/emojis/2b1b.png differ diff --git a/emojis/2b1c.png b/emojis/2b1c.png new file mode 100644 index 00000000..8a90cda3 Binary files /dev/null and b/emojis/2b1c.png differ diff --git a/emojis/2b50.png b/emojis/2b50.png new file mode 100644 index 00000000..46bd86c1 Binary files /dev/null and b/emojis/2b50.png differ diff --git a/emojis/2b55.png b/emojis/2b55.png new file mode 100644 index 00000000..e1f9e3e3 Binary files /dev/null and b/emojis/2b55.png differ diff --git a/emojis/3030.png b/emojis/3030.png new file mode 100644 index 00000000..6fa4eaad Binary files /dev/null and b/emojis/3030.png differ diff --git a/emojis/303d.png b/emojis/303d.png new file mode 100644 index 00000000..9727d94a Binary files /dev/null and b/emojis/303d.png differ diff --git a/emojis/3297.png b/emojis/3297.png new file mode 100644 index 00000000..bdbc8b8d Binary files /dev/null and b/emojis/3297.png differ diff --git a/emojis/3299.png b/emojis/3299.png new file mode 100644 index 00000000..654c5f66 Binary files /dev/null and b/emojis/3299.png differ diff --git a/emojis/emojis-data.json b/emojis/emojis-data.json new file mode 100644 index 00000000..382e5756 --- /dev/null +++ b/emojis/emojis-data.json @@ -0,0 +1 @@ +[{"name":"+1","image":"1f44d.png","id":"1f44d"},{"name":"-1","image":"1f44e.png","id":"1f44e"},{"name":"100","image":"1f4af.png","id":"1f4af"},{"name":"1234","image":"1f522.png","id":"1f522"},{"name":"8ball","image":"1f3b1.png","id":"1f3b1"},{"name":"a","image":"1f170.png","id":"1f170"},{"name":"ab","image":"1f18e.png","id":"1f18e"},{"name":"abc","image":"1f524.png","id":"1f524"},{"name":"abcd","image":"1f521.png","id":"1f521"},{"name":"accept","image":"1f251.png","id":"1f251"},{"name":"admission_tickets","image":"1f39f.png","id":"1f39f"},{"name":"aerial_tramway","image":"1f6a1.png","id":"1f6a1"},{"name":"airplane","image":"2708.png","id":"2708"},{"name":"airplane_arriving","image":"1f6ec.png","id":"1f6ec"},{"name":"airplane_departure","image":"1f6eb.png","id":"1f6eb"},{"name":"alarm_clock","image":"23f0.png","id":"23f0"},{"name":"alembic","image":"2697.png","id":"2697"},{"name":"alien","image":"1f47d.png","id":"1f47d"},{"name":"ambulance","image":"1f691.png","id":"1f691"},{"name":"amphora","image":"1f3fa.png","id":"1f3fa"},{"name":"anchor","image":"2693.png","id":"2693"},{"name":"angel","image":"1f47c.png","id":"1f47c"},{"name":"anger","image":"1f4a2.png","id":"1f4a2"},{"name":"angry","image":"1f620.png","id":"1f620"},{"name":"anguished","image":"1f627.png","id":"1f627"},{"name":"ant","image":"1f41c.png","id":"1f41c"},{"name":"apple","image":"1f34e.png","id":"1f34e"},{"name":"aquarius","image":"2652.png","id":"2652"},{"name":"aries","image":"2648.png","id":"2648"},{"name":"arrow_backward","image":"25c0.png","id":"25c0"},{"name":"arrow_double_down","image":"23ec.png","id":"23ec"},{"name":"arrow_double_up","image":"23eb.png","id":"23eb"},{"name":"arrow_down","image":"2b07.png","id":"2b07"},{"name":"arrow_down_small","image":"1f53d.png","id":"1f53d"},{"name":"arrow_forward","image":"25b6.png","id":"25b6"},{"name":"arrow_heading_down","image":"2935.png","id":"2935"},{"name":"arrow_heading_up","image":"2934.png","id":"2934"},{"name":"arrow_left","image":"2b05.png","id":"2b05"},{"name":"arrow_lower_left","image":"2199.png","id":"2199"},{"name":"arrow_lower_right","image":"2198.png","id":"2198"},{"name":"arrow_right","image":"27a1.png","id":"27a1"},{"name":"arrow_right_hook","image":"21aa.png","id":"21aa"},{"name":"arrow_up","image":"2b06.png","id":"2b06"},{"name":"arrow_up_down","image":"2195.png","id":"2195"},{"name":"arrow_up_small","image":"1f53c.png","id":"1f53c"},{"name":"arrow_upper_left","image":"2196.png","id":"2196"},{"name":"arrow_upper_right","image":"2197.png","id":"2197"},{"name":"arrows_clockwise","image":"1f503.png","id":"1f503"},{"name":"arrows_counterclockwise","image":"1f504.png","id":"1f504"},{"name":"art","image":"1f3a8.png","id":"1f3a8"},{"name":"articulated_lorry","image":"1f69b.png","id":"1f69b"},{"name":"astonished","image":"1f632.png","id":"1f632"},{"name":"athletic_shoe","image":"1f45f.png","id":"1f45f"},{"name":"atm","image":"1f3e7.png","id":"1f3e7"},{"name":"atom_symbol","image":"269b.png","id":"269b"},{"name":"b","image":"1f171.png","id":"1f171"},{"name":"baby","image":"1f476.png","id":"1f476"},{"name":"baby_bottle","image":"1f37c.png","id":"1f37c"},{"name":"baby_chick","image":"1f424.png","id":"1f424"},{"name":"baby_symbol","image":"1f6bc.png","id":"1f6bc"},{"name":"back","image":"1f519.png","id":"1f519"},{"name":"badminton_racquet_and_shuttlecock","image":"1f3f8.png","id":"1f3f8"},{"name":"baggage_claim","image":"1f6c4.png","id":"1f6c4"},{"name":"balloon","image":"1f388.png","id":"1f388"},{"name":"ballot_box_with_ballot","image":"1f5f3.png","id":"1f5f3"},{"name":"ballot_box_with_check","image":"2611.png","id":"2611"},{"name":"bamboo","image":"1f38d.png","id":"1f38d"},{"name":"banana","image":"1f34c.png","id":"1f34c"},{"name":"bangbang","image":"203c.png","id":"203c"},{"name":"bank","image":"1f3e6.png","id":"1f3e6"},{"name":"bar_chart","image":"1f4ca.png","id":"1f4ca"},{"name":"barber","image":"1f488.png","id":"1f488"},{"name":"barely_sunny","image":"1f325.png","id":"1f325"},{"name":"baseball","image":"26be.png","id":"26be"},{"name":"basketball","image":"1f3c0.png","id":"1f3c0"},{"name":"bath","image":"1f6c0.png","id":"1f6c0"},{"name":"bathtub","image":"1f6c1.png","id":"1f6c1"},{"name":"battery","image":"1f50b.png","id":"1f50b"},{"name":"beach_with_umbrella","image":"1f3d6.png","id":"1f3d6"},{"name":"bear","image":"1f43b.png","id":"1f43b"},{"name":"bed","image":"1f6cf.png","id":"1f6cf"},{"name":"bee","image":"1f41d.png","id":"1f41d"},{"name":"beer","image":"1f37a.png","id":"1f37a"},{"name":"beers","image":"1f37b.png","id":"1f37b"},{"name":"beetle","image":"1f41e.png","id":"1f41e"},{"name":"beginner","image":"1f530.png","id":"1f530"},{"name":"bell","image":"1f514.png","id":"1f514"},{"name":"bellhop_bell","image":"1f6ce.png","id":"1f6ce"},{"name":"bento","image":"1f371.png","id":"1f371"},{"name":"bicyclist","image":"1f6b4.png","id":"1f6b4"},{"name":"bike","image":"1f6b2.png","id":"1f6b2"},{"name":"bikini","image":"1f459.png","id":"1f459"},{"name":"biohazard_sign","image":"2623.png","id":"2623"},{"name":"bird","image":"1f426.png","id":"1f426"},{"name":"birthday","image":"1f382.png","id":"1f382"},{"name":"black_circle","image":"26ab.png","id":"26ab"},{"name":"black_circle_for_record","image":"23fa.png","id":"23fa"},{"name":"black_joker","image":"1f0cf.png","id":"1f0cf"},{"name":"black_large_square","image":"2b1b.png","id":"2b1b"},{"name":"black_left_pointing_double_triangle_with_vertical_bar","image":"23ee.png","id":"23ee"},{"name":"black_medium_small_square","image":"25fe.png","id":"25fe"},{"name":"black_medium_square","image":"25fc.png","id":"25fc"},{"name":"black_nib","image":"2712.png","id":"2712"},{"name":"black_right_pointing_double_triangle_with_vertical_bar","image":"23ed.png","id":"23ed"},{"name":"black_right_pointing_triangle_with_double_vertical_bar","image":"23ef.png","id":"23ef"},{"name":"black_small_square","image":"25aa.png","id":"25aa"},{"name":"black_square_button","image":"1f532.png","id":"1f532"},{"name":"black_square_for_stop","image":"23f9.png","id":"23f9"},{"name":"blossom","image":"1f33c.png","id":"1f33c"},{"name":"blowfish","image":"1f421.png","id":"1f421"},{"name":"blue_book","image":"1f4d8.png","id":"1f4d8"},{"name":"blue_car","image":"1f699.png","id":"1f699"},{"name":"blue_heart","image":"1f499.png","id":"1f499"},{"name":"blush","image":"1f60a.png","id":"1f60a"},{"name":"boar","image":"1f417.png","id":"1f417"},{"name":"boat","image":"26f5.png","id":"26f5"},{"name":"bomb","image":"1f4a3.png","id":"1f4a3"},{"name":"book","image":"1f4d6.png","id":"1f4d6"},{"name":"bookmark","image":"1f516.png","id":"1f516"},{"name":"bookmark_tabs","image":"1f4d1.png","id":"1f4d1"},{"name":"books","image":"1f4da.png","id":"1f4da"},{"name":"boom","image":"1f4a5.png","id":"1f4a5"},{"name":"boot","image":"1f462.png","id":"1f462"},{"name":"bouquet","image":"1f490.png","id":"1f490"},{"name":"bow","image":"1f647.png","id":"1f647"},{"name":"bow_and_arrow","image":"1f3f9.png","id":"1f3f9"},{"name":"bowling","image":"1f3b3.png","id":"1f3b3"},{"name":"boy","image":"1f466.png","id":"1f466"},{"name":"bread","image":"1f35e.png","id":"1f35e"},{"name":"bride_with_veil","image":"1f470.png","id":"1f470"},{"name":"bridge_at_night","image":"1f309.png","id":"1f309"},{"name":"briefcase","image":"1f4bc.png","id":"1f4bc"},{"name":"broken_heart","image":"1f494.png","id":"1f494"},{"name":"bug","image":"1f41b.png","id":"1f41b"},{"name":"building_construction","image":"1f3d7.png","id":"1f3d7"},{"name":"bulb","image":"1f4a1.png","id":"1f4a1"},{"name":"bullettrain_front","image":"1f685.png","id":"1f685"},{"name":"bullettrain_side","image":"1f684.png","id":"1f684"},{"name":"burrito","image":"1f32f.png","id":"1f32f"},{"name":"bus","image":"1f68c.png","id":"1f68c"},{"name":"busstop","image":"1f68f.png","id":"1f68f"},{"name":"bust_in_silhouette","image":"1f464.png","id":"1f464"},{"name":"busts_in_silhouette","image":"1f465.png","id":"1f465"},{"name":"cactus","image":"1f335.png","id":"1f335"},{"name":"cake","image":"1f370.png","id":"1f370"},{"name":"calendar","image":"1f4c6.png","id":"1f4c6"},{"name":"calling","image":"1f4f2.png","id":"1f4f2"},{"name":"camel","image":"1f42b.png","id":"1f42b"},{"name":"camera","image":"1f4f7.png","id":"1f4f7"},{"name":"camera_with_flash","image":"1f4f8.png","id":"1f4f8"},{"name":"camping","image":"1f3d5.png","id":"1f3d5"},{"name":"cancer","image":"264b.png","id":"264b"},{"name":"candle","image":"1f56f.png","id":"1f56f"},{"name":"candy","image":"1f36c.png","id":"1f36c"},{"name":"capital_abcd","image":"1f520.png","id":"1f520"},{"name":"capricorn","image":"2651.png","id":"2651"},{"name":"car","image":"1f697.png","id":"1f697"},{"name":"card_file_box","image":"1f5c3.png","id":"1f5c3"},{"name":"card_index","image":"1f4c7.png","id":"1f4c7"},{"name":"card_index_dividers","image":"1f5c2.png","id":"1f5c2"},{"name":"carousel_horse","image":"1f3a0.png","id":"1f3a0"},{"name":"cat","image":"1f431.png","id":"1f431"},{"name":"cat2","image":"1f408.png","id":"1f408"},{"name":"cd","image":"1f4bf.png","id":"1f4bf"},{"name":"chains","image":"26d3.png","id":"26d3"},{"name":"champagne","image":"1f37e.png","id":"1f37e"},{"name":"chart","image":"1f4b9.png","id":"1f4b9"},{"name":"chart_with_downwards_trend","image":"1f4c9.png","id":"1f4c9"},{"name":"chart_with_upwards_trend","image":"1f4c8.png","id":"1f4c8"},{"name":"checkered_flag","image":"1f3c1.png","id":"1f3c1"},{"name":"cheese_wedge","image":"1f9c0.png","id":"1f9c0"},{"name":"cherries","image":"1f352.png","id":"1f352"},{"name":"cherry_blossom","image":"1f338.png","id":"1f338"},{"name":"chestnut","image":"1f330.png","id":"1f330"},{"name":"chicken","image":"1f414.png","id":"1f414"},{"name":"children_crossing","image":"1f6b8.png","id":"1f6b8"},{"name":"chipmunk","image":"1f43f.png","id":"1f43f"},{"name":"chocolate_bar","image":"1f36b.png","id":"1f36b"},{"name":"christmas_tree","image":"1f384.png","id":"1f384"},{"name":"church","image":"26ea.png","id":"26ea"},{"name":"cinema","image":"1f3a6.png","id":"1f3a6"},{"name":"circus_tent","image":"1f3aa.png","id":"1f3aa"},{"name":"city_sunrise","image":"1f307.png","id":"1f307"},{"name":"city_sunset","image":"1f306.png","id":"1f306"},{"name":"cityscape","image":"1f3d9.png","id":"1f3d9"},{"name":"cl","image":"1f191.png","id":"1f191"},{"name":"clap","image":"1f44f.png","id":"1f44f"},{"name":"clapper","image":"1f3ac.png","id":"1f3ac"},{"name":"classical_building","image":"1f3db.png","id":"1f3db"},{"name":"clipboard","image":"1f4cb.png","id":"1f4cb"},{"name":"clock1","image":"1f550.png","id":"1f550"},{"name":"clock10","image":"1f559.png","id":"1f559"},{"name":"clock1030","image":"1f565.png","id":"1f565"},{"name":"clock11","image":"1f55a.png","id":"1f55a"},{"name":"clock1130","image":"1f566.png","id":"1f566"},{"name":"clock12","image":"1f55b.png","id":"1f55b"},{"name":"clock1230","image":"1f567.png","id":"1f567"},{"name":"clock130","image":"1f55c.png","id":"1f55c"},{"name":"clock2","image":"1f551.png","id":"1f551"},{"name":"clock230","image":"1f55d.png","id":"1f55d"},{"name":"clock3","image":"1f552.png","id":"1f552"},{"name":"clock330","image":"1f55e.png","id":"1f55e"},{"name":"clock4","image":"1f553.png","id":"1f553"},{"name":"clock430","image":"1f55f.png","id":"1f55f"},{"name":"clock5","image":"1f554.png","id":"1f554"},{"name":"clock530","image":"1f560.png","id":"1f560"},{"name":"clock6","image":"1f555.png","id":"1f555"},{"name":"clock630","image":"1f561.png","id":"1f561"},{"name":"clock7","image":"1f556.png","id":"1f556"},{"name":"clock730","image":"1f562.png","id":"1f562"},{"name":"clock8","image":"1f557.png","id":"1f557"},{"name":"clock830","image":"1f563.png","id":"1f563"},{"name":"clock9","image":"1f558.png","id":"1f558"},{"name":"clock930","image":"1f564.png","id":"1f564"},{"name":"closed_book","image":"1f4d5.png","id":"1f4d5"},{"name":"closed_lock_with_key","image":"1f510.png","id":"1f510"},{"name":"closed_umbrella","image":"1f302.png","id":"1f302"},{"name":"cloud","image":"2601.png","id":"2601"},{"name":"clubs","image":"2663.png","id":"2663"},{"name":"cocktail","image":"1f378.png","id":"1f378"},{"name":"coffee","image":"2615.png","id":"2615"},{"name":"coffin","image":"26b0.png","id":"26b0"},{"name":"cold_sweat","image":"1f630.png","id":"1f630"},{"name":"comet","image":"2604.png","id":"2604"},{"name":"compression","image":"1f5dc.png","id":"1f5dc"},{"name":"computer","image":"1f4bb.png","id":"1f4bb"},{"name":"confetti_ball","image":"1f38a.png","id":"1f38a"},{"name":"confounded","image":"1f616.png","id":"1f616"},{"name":"confused","image":"1f615.png","id":"1f615"},{"name":"congratulations","image":"3297.png","id":"3297"},{"name":"construction","image":"1f6a7.png","id":"1f6a7"},{"name":"construction_worker","image":"1f477.png","id":"1f477"},{"name":"control_knobs","image":"1f39b.png","id":"1f39b"},{"name":"convenience_store","image":"1f3ea.png","id":"1f3ea"},{"name":"cookie","image":"1f36a.png","id":"1f36a"},{"name":"cool","image":"1f192.png","id":"1f192"},{"name":"cop","image":"1f46e.png","id":"1f46e"},{"name":"corn","image":"1f33d.png","id":"1f33d"},{"name":"couch_and_lamp","image":"1f6cb.png","id":"1f6cb"},{"name":"couple","image":"1f46b.png","id":"1f46b"},{"name":"couple_with_heart","image":"1f491.png","id":"1f491"},{"name":"couplekiss","image":"1f48f.png","id":"1f48f"},{"name":"cow","image":"1f42e.png","id":"1f42e"},{"name":"cow2","image":"1f404.png","id":"1f404"},{"name":"crab","image":"1f980.png","id":"1f980"},{"name":"credit_card","image":"1f4b3.png","id":"1f4b3"},{"name":"crescent_moon","image":"1f319.png","id":"1f319"},{"name":"cricket_bat_and_ball","image":"1f3cf.png","id":"1f3cf"},{"name":"crocodile","image":"1f40a.png","id":"1f40a"},{"name":"crossed_flags","image":"1f38c.png","id":"1f38c"},{"name":"crossed_swords","image":"2694.png","id":"2694"},{"name":"crown","image":"1f451.png","id":"1f451"},{"name":"cry","image":"1f622.png","id":"1f622"},{"name":"crying_cat_face","image":"1f63f.png","id":"1f63f"},{"name":"crystal_ball","image":"1f52e.png","id":"1f52e"},{"name":"cupid","image":"1f498.png","id":"1f498"},{"name":"curly_loop","image":"27b0.png","id":"27b0"},{"name":"currency_exchange","image":"1f4b1.png","id":"1f4b1"},{"name":"curry","image":"1f35b.png","id":"1f35b"},{"name":"custard","image":"1f36e.png","id":"1f36e"},{"name":"customs","image":"1f6c3.png","id":"1f6c3"},{"name":"cyclone","image":"1f300.png","id":"1f300"},{"name":"dagger_knife","image":"1f5e1.png","id":"1f5e1"},{"name":"dancer","image":"1f483.png","id":"1f483"},{"name":"dancers","image":"1f46f.png","id":"1f46f"},{"name":"dango","image":"1f361.png","id":"1f361"},{"name":"dark_sunglasses","image":"1f576.png","id":"1f576"},{"name":"dart","image":"1f3af.png","id":"1f3af"},{"name":"dash","image":"1f4a8.png","id":"1f4a8"},{"name":"date","image":"1f4c5.png","id":"1f4c5"},{"name":"deciduous_tree","image":"1f333.png","id":"1f333"},{"name":"department_store","image":"1f3ec.png","id":"1f3ec"},{"name":"derelict_house_building","image":"1f3da.png","id":"1f3da"},{"name":"desert","image":"1f3dc.png","id":"1f3dc"},{"name":"desert_island","image":"1f3dd.png","id":"1f3dd"},{"name":"desktop_computer","image":"1f5a5.png","id":"1f5a5"},{"name":"diamond_shape_with_a_dot_inside","image":"1f4a0.png","id":"1f4a0"},{"name":"diamonds","image":"2666.png","id":"2666"},{"name":"disappointed","image":"1f61e.png","id":"1f61e"},{"name":"disappointed_relieved","image":"1f625.png","id":"1f625"},{"name":"dizzy","image":"1f4ab.png","id":"1f4ab"},{"name":"dizzy_face","image":"1f635.png","id":"1f635"},{"name":"do_not_litter","image":"1f6af.png","id":"1f6af"},{"name":"dog","image":"1f436.png","id":"1f436"},{"name":"dog2","image":"1f415.png","id":"1f415"},{"name":"dollar","image":"1f4b5.png","id":"1f4b5"},{"name":"dolls","image":"1f38e.png","id":"1f38e"},{"name":"dolphin","image":"1f42c.png","id":"1f42c"},{"name":"door","image":"1f6aa.png","id":"1f6aa"},{"name":"double_vertical_bar","image":"23f8.png","id":"23f8"},{"name":"doughnut","image":"1f369.png","id":"1f369"},{"name":"dove_of_peace","image":"1f54a.png","id":"1f54a"},{"name":"dragon","image":"1f409.png","id":"1f409"},{"name":"dragon_face","image":"1f432.png","id":"1f432"},{"name":"dress","image":"1f457.png","id":"1f457"},{"name":"dromedary_camel","image":"1f42a.png","id":"1f42a"},{"name":"droplet","image":"1f4a7.png","id":"1f4a7"},{"name":"dvd","image":"1f4c0.png","id":"1f4c0"},{"name":"e-mail","image":"1f4e7.png","id":"1f4e7"},{"name":"ear","image":"1f442.png","id":"1f442"},{"name":"ear_of_rice","image":"1f33e.png","id":"1f33e"},{"name":"earth_africa","image":"1f30d.png","id":"1f30d"},{"name":"earth_americas","image":"1f30e.png","id":"1f30e"},{"name":"earth_asia","image":"1f30f.png","id":"1f30f"},{"name":"egg","image":"1f373.png","id":"1f373"},{"name":"eggplant","image":"1f346.png","id":"1f346"},{"name":"eight","image":"0038-20e3.png","id":"0038-20e3"},{"name":"eight_pointed_black_star","image":"2734.png","id":"2734"},{"name":"eight_spoked_asterisk","image":"2733.png","id":"2733"},{"name":"electric_plug","image":"1f50c.png","id":"1f50c"},{"name":"elephant","image":"1f418.png","id":"1f418"},{"name":"email","image":"2709.png","id":"2709"},{"name":"end","image":"1f51a.png","id":"1f51a"},{"name":"envelope_with_arrow","image":"1f4e9.png","id":"1f4e9"},{"name":"euro","image":"1f4b6.png","id":"1f4b6"},{"name":"european_castle","image":"1f3f0.png","id":"1f3f0"},{"name":"european_post_office","image":"1f3e4.png","id":"1f3e4"},{"name":"evergreen_tree","image":"1f332.png","id":"1f332"},{"name":"exclamation","image":"2757.png","id":"2757"},{"name":"expressionless","image":"1f611.png","id":"1f611"},{"name":"eye","image":"1f441.png","id":"1f441"},{"name":"eyeglasses","image":"1f453.png","id":"1f453"},{"name":"eyes","image":"1f440.png","id":"1f440"},{"name":"face_with_head_bandage","image":"1f915.png","id":"1f915"},{"name":"face_with_rolling_eyes","image":"1f644.png","id":"1f644"},{"name":"face_with_thermometer","image":"1f912.png","id":"1f912"},{"name":"facepunch","image":"1f44a.png","id":"1f44a"},{"name":"factory","image":"1f3ed.png","id":"1f3ed"},{"name":"fallen_leaf","image":"1f342.png","id":"1f342"},{"name":"family","image":"1f46a.png","id":"1f46a"},{"name":"fast_forward","image":"23e9.png","id":"23e9"},{"name":"fax","image":"1f4e0.png","id":"1f4e0"},{"name":"fearful","image":"1f628.png","id":"1f628"},{"name":"feet","image":"1f43e.png","id":"1f43e"},{"name":"ferris_wheel","image":"1f3a1.png","id":"1f3a1"},{"name":"ferry","image":"26f4.png","id":"26f4"},{"name":"field_hockey_stick_and_ball","image":"1f3d1.png","id":"1f3d1"},{"name":"file_cabinet","image":"1f5c4.png","id":"1f5c4"},{"name":"file_folder","image":"1f4c1.png","id":"1f4c1"},{"name":"film_frames","image":"1f39e.png","id":"1f39e"},{"name":"film_projector","image":"1f4fd.png","id":"1f4fd"},{"name":"fire","image":"1f525.png","id":"1f525"},{"name":"fire_engine","image":"1f692.png","id":"1f692"},{"name":"fireworks","image":"1f386.png","id":"1f386"},{"name":"first_quarter_moon","image":"1f313.png","id":"1f313"},{"name":"first_quarter_moon_with_face","image":"1f31b.png","id":"1f31b"},{"name":"fish","image":"1f41f.png","id":"1f41f"},{"name":"fish_cake","image":"1f365.png","id":"1f365"},{"name":"fishing_pole_and_fish","image":"1f3a3.png","id":"1f3a3"},{"name":"fist","image":"270a.png","id":"270a"},{"name":"five","image":"0035-20e3.png","id":"0035-20e3"},{"name":"flag-ac","image":"1f1e6-1f1e8.png","id":"1f1e6-1f1e8"},{"name":"flag-ad","image":"1f1e6-1f1e9.png","id":"1f1e6-1f1e9"},{"name":"flag-ae","image":"1f1e6-1f1ea.png","id":"1f1e6-1f1ea"},{"name":"flag-af","image":"1f1e6-1f1eb.png","id":"1f1e6-1f1eb"},{"name":"flag-ag","image":"1f1e6-1f1ec.png","id":"1f1e6-1f1ec"},{"name":"flag-ai","image":"1f1e6-1f1ee.png","id":"1f1e6-1f1ee"},{"name":"flag-al","image":"1f1e6-1f1f1.png","id":"1f1e6-1f1f1"},{"name":"flag-am","image":"1f1e6-1f1f2.png","id":"1f1e6-1f1f2"},{"name":"flag-ao","image":"1f1e6-1f1f4.png","id":"1f1e6-1f1f4"},{"name":"flag-aq","image":"1f1e6-1f1f6.png","id":"1f1e6-1f1f6"},{"name":"flag-ar","image":"1f1e6-1f1f7.png","id":"1f1e6-1f1f7"},{"name":"flag-as","image":"1f1e6-1f1f8.png","id":"1f1e6-1f1f8"},{"name":"flag-at","image":"1f1e6-1f1f9.png","id":"1f1e6-1f1f9"},{"name":"flag-au","image":"1f1e6-1f1fa.png","id":"1f1e6-1f1fa"},{"name":"flag-aw","image":"1f1e6-1f1fc.png","id":"1f1e6-1f1fc"},{"name":"flag-ax","image":"1f1e6-1f1fd.png","id":"1f1e6-1f1fd"},{"name":"flag-az","image":"1f1e6-1f1ff.png","id":"1f1e6-1f1ff"},{"name":"flag-ba","image":"1f1e7-1f1e6.png","id":"1f1e7-1f1e6"},{"name":"flag-bb","image":"1f1e7-1f1e7.png","id":"1f1e7-1f1e7"},{"name":"flag-bd","image":"1f1e7-1f1e9.png","id":"1f1e7-1f1e9"},{"name":"flag-be","image":"1f1e7-1f1ea.png","id":"1f1e7-1f1ea"},{"name":"flag-bf","image":"1f1e7-1f1eb.png","id":"1f1e7-1f1eb"},{"name":"flag-bg","image":"1f1e7-1f1ec.png","id":"1f1e7-1f1ec"},{"name":"flag-bh","image":"1f1e7-1f1ed.png","id":"1f1e7-1f1ed"},{"name":"flag-bi","image":"1f1e7-1f1ee.png","id":"1f1e7-1f1ee"},{"name":"flag-bj","image":"1f1e7-1f1ef.png","id":"1f1e7-1f1ef"},{"name":"flag-bl","image":"1f1e7-1f1f1.png","id":"1f1e7-1f1f1"},{"name":"flag-bm","image":"1f1e7-1f1f2.png","id":"1f1e7-1f1f2"},{"name":"flag-bn","image":"1f1e7-1f1f3.png","id":"1f1e7-1f1f3"},{"name":"flag-bo","image":"1f1e7-1f1f4.png","id":"1f1e7-1f1f4"},{"name":"flag-bq","image":"1f1e7-1f1f6.png","id":"1f1e7-1f1f6"},{"name":"flag-br","image":"1f1e7-1f1f7.png","id":"1f1e7-1f1f7"},{"name":"flag-bs","image":"1f1e7-1f1f8.png","id":"1f1e7-1f1f8"},{"name":"flag-bt","image":"1f1e7-1f1f9.png","id":"1f1e7-1f1f9"},{"name":"flag-bv","image":"1f1e7-1f1fb.png","id":"1f1e7-1f1fb"},{"name":"flag-bw","image":"1f1e7-1f1fc.png","id":"1f1e7-1f1fc"},{"name":"flag-by","image":"1f1e7-1f1fe.png","id":"1f1e7-1f1fe"},{"name":"flag-bz","image":"1f1e7-1f1ff.png","id":"1f1e7-1f1ff"},{"name":"flag-ca","image":"1f1e8-1f1e6.png","id":"1f1e8-1f1e6"},{"name":"flag-cc","image":"1f1e8-1f1e8.png","id":"1f1e8-1f1e8"},{"name":"flag-cd","image":"1f1e8-1f1e9.png","id":"1f1e8-1f1e9"},{"name":"flag-cf","image":"1f1e8-1f1eb.png","id":"1f1e8-1f1eb"},{"name":"flag-cg","image":"1f1e8-1f1ec.png","id":"1f1e8-1f1ec"},{"name":"flag-ch","image":"1f1e8-1f1ed.png","id":"1f1e8-1f1ed"},{"name":"flag-ci","image":"1f1e8-1f1ee.png","id":"1f1e8-1f1ee"},{"name":"flag-ck","image":"1f1e8-1f1f0.png","id":"1f1e8-1f1f0"},{"name":"flag-cl","image":"1f1e8-1f1f1.png","id":"1f1e8-1f1f1"},{"name":"flag-cm","image":"1f1e8-1f1f2.png","id":"1f1e8-1f1f2"},{"name":"flag-cn","image":"1f1e8-1f1f3.png","id":"1f1e8-1f1f3"},{"name":"flag-co","image":"1f1e8-1f1f4.png","id":"1f1e8-1f1f4"},{"name":"flag-cp","image":"1f1e8-1f1f5.png","id":"1f1e8-1f1f5"},{"name":"flag-cr","image":"1f1e8-1f1f7.png","id":"1f1e8-1f1f7"},{"name":"flag-cu","image":"1f1e8-1f1fa.png","id":"1f1e8-1f1fa"},{"name":"flag-cv","image":"1f1e8-1f1fb.png","id":"1f1e8-1f1fb"},{"name":"flag-cw","image":"1f1e8-1f1fc.png","id":"1f1e8-1f1fc"},{"name":"flag-cx","image":"1f1e8-1f1fd.png","id":"1f1e8-1f1fd"},{"name":"flag-cy","image":"1f1e8-1f1fe.png","id":"1f1e8-1f1fe"},{"name":"flag-cz","image":"1f1e8-1f1ff.png","id":"1f1e8-1f1ff"},{"name":"flag-de","image":"1f1e9-1f1ea.png","id":"1f1e9-1f1ea"},{"name":"flag-dg","image":"1f1e9-1f1ec.png","id":"1f1e9-1f1ec"},{"name":"flag-dj","image":"1f1e9-1f1ef.png","id":"1f1e9-1f1ef"},{"name":"flag-dk","image":"1f1e9-1f1f0.png","id":"1f1e9-1f1f0"},{"name":"flag-dm","image":"1f1e9-1f1f2.png","id":"1f1e9-1f1f2"},{"name":"flag-do","image":"1f1e9-1f1f4.png","id":"1f1e9-1f1f4"},{"name":"flag-dz","image":"1f1e9-1f1ff.png","id":"1f1e9-1f1ff"},{"name":"flag-ea","image":"1f1ea-1f1e6.png","id":"1f1ea-1f1e6"},{"name":"flag-ec","image":"1f1ea-1f1e8.png","id":"1f1ea-1f1e8"},{"name":"flag-ee","image":"1f1ea-1f1ea.png","id":"1f1ea-1f1ea"},{"name":"flag-eg","image":"1f1ea-1f1ec.png","id":"1f1ea-1f1ec"},{"name":"flag-eh","image":"1f1ea-1f1ed.png","id":"1f1ea-1f1ed"},{"name":"flag-er","image":"1f1ea-1f1f7.png","id":"1f1ea-1f1f7"},{"name":"flag-es","image":"1f1ea-1f1f8.png","id":"1f1ea-1f1f8"},{"name":"flag-et","image":"1f1ea-1f1f9.png","id":"1f1ea-1f1f9"},{"name":"flag-eu","image":"1f1ea-1f1fa.png","id":"1f1ea-1f1fa"},{"name":"flag-fi","image":"1f1eb-1f1ee.png","id":"1f1eb-1f1ee"},{"name":"flag-fj","image":"1f1eb-1f1ef.png","id":"1f1eb-1f1ef"},{"name":"flag-fk","image":"1f1eb-1f1f0.png","id":"1f1eb-1f1f0"},{"name":"flag-fm","image":"1f1eb-1f1f2.png","id":"1f1eb-1f1f2"},{"name":"flag-fo","image":"1f1eb-1f1f4.png","id":"1f1eb-1f1f4"},{"name":"flag-fr","image":"1f1eb-1f1f7.png","id":"1f1eb-1f1f7"},{"name":"flag-ga","image":"1f1ec-1f1e6.png","id":"1f1ec-1f1e6"},{"name":"flag-gb","image":"1f1ec-1f1e7.png","id":"1f1ec-1f1e7"},{"name":"flag-gd","image":"1f1ec-1f1e9.png","id":"1f1ec-1f1e9"},{"name":"flag-ge","image":"1f1ec-1f1ea.png","id":"1f1ec-1f1ea"},{"name":"flag-gf","image":"1f1ec-1f1eb.png","id":"1f1ec-1f1eb"},{"name":"flag-gg","image":"1f1ec-1f1ec.png","id":"1f1ec-1f1ec"},{"name":"flag-gh","image":"1f1ec-1f1ed.png","id":"1f1ec-1f1ed"},{"name":"flag-gi","image":"1f1ec-1f1ee.png","id":"1f1ec-1f1ee"},{"name":"flag-gl","image":"1f1ec-1f1f1.png","id":"1f1ec-1f1f1"},{"name":"flag-gm","image":"1f1ec-1f1f2.png","id":"1f1ec-1f1f2"},{"name":"flag-gn","image":"1f1ec-1f1f3.png","id":"1f1ec-1f1f3"},{"name":"flag-gp","image":"1f1ec-1f1f5.png","id":"1f1ec-1f1f5"},{"name":"flag-gq","image":"1f1ec-1f1f6.png","id":"1f1ec-1f1f6"},{"name":"flag-gr","image":"1f1ec-1f1f7.png","id":"1f1ec-1f1f7"},{"name":"flag-gs","image":"1f1ec-1f1f8.png","id":"1f1ec-1f1f8"},{"name":"flag-gt","image":"1f1ec-1f1f9.png","id":"1f1ec-1f1f9"},{"name":"flag-gu","image":"1f1ec-1f1fa.png","id":"1f1ec-1f1fa"},{"name":"flag-gw","image":"1f1ec-1f1fc.png","id":"1f1ec-1f1fc"},{"name":"flag-gy","image":"1f1ec-1f1fe.png","id":"1f1ec-1f1fe"},{"name":"flag-hk","image":"1f1ed-1f1f0.png","id":"1f1ed-1f1f0"},{"name":"flag-hm","image":"1f1ed-1f1f2.png","id":"1f1ed-1f1f2"},{"name":"flag-hn","image":"1f1ed-1f1f3.png","id":"1f1ed-1f1f3"},{"name":"flag-hr","image":"1f1ed-1f1f7.png","id":"1f1ed-1f1f7"},{"name":"flag-ht","image":"1f1ed-1f1f9.png","id":"1f1ed-1f1f9"},{"name":"flag-hu","image":"1f1ed-1f1fa.png","id":"1f1ed-1f1fa"},{"name":"flag-ic","image":"1f1ee-1f1e8.png","id":"1f1ee-1f1e8"},{"name":"flag-id","image":"1f1ee-1f1e9.png","id":"1f1ee-1f1e9"},{"name":"flag-ie","image":"1f1ee-1f1ea.png","id":"1f1ee-1f1ea"},{"name":"flag-il","image":"1f1ee-1f1f1.png","id":"1f1ee-1f1f1"},{"name":"flag-im","image":"1f1ee-1f1f2.png","id":"1f1ee-1f1f2"},{"name":"flag-in","image":"1f1ee-1f1f3.png","id":"1f1ee-1f1f3"},{"name":"flag-io","image":"1f1ee-1f1f4.png","id":"1f1ee-1f1f4"},{"name":"flag-iq","image":"1f1ee-1f1f6.png","id":"1f1ee-1f1f6"},{"name":"flag-ir","image":"1f1ee-1f1f7.png","id":"1f1ee-1f1f7"},{"name":"flag-is","image":"1f1ee-1f1f8.png","id":"1f1ee-1f1f8"},{"name":"flag-it","image":"1f1ee-1f1f9.png","id":"1f1ee-1f1f9"},{"name":"flag-je","image":"1f1ef-1f1ea.png","id":"1f1ef-1f1ea"},{"name":"flag-jm","image":"1f1ef-1f1f2.png","id":"1f1ef-1f1f2"},{"name":"flag-jo","image":"1f1ef-1f1f4.png","id":"1f1ef-1f1f4"},{"name":"flag-jp","image":"1f1ef-1f1f5.png","id":"1f1ef-1f1f5"},{"name":"flag-ke","image":"1f1f0-1f1ea.png","id":"1f1f0-1f1ea"},{"name":"flag-kg","image":"1f1f0-1f1ec.png","id":"1f1f0-1f1ec"},{"name":"flag-kh","image":"1f1f0-1f1ed.png","id":"1f1f0-1f1ed"},{"name":"flag-ki","image":"1f1f0-1f1ee.png","id":"1f1f0-1f1ee"},{"name":"flag-km","image":"1f1f0-1f1f2.png","id":"1f1f0-1f1f2"},{"name":"flag-kn","image":"1f1f0-1f1f3.png","id":"1f1f0-1f1f3"},{"name":"flag-kp","image":"1f1f0-1f1f5.png","id":"1f1f0-1f1f5"},{"name":"flag-kr","image":"1f1f0-1f1f7.png","id":"1f1f0-1f1f7"},{"name":"flag-kw","image":"1f1f0-1f1fc.png","id":"1f1f0-1f1fc"},{"name":"flag-ky","image":"1f1f0-1f1fe.png","id":"1f1f0-1f1fe"},{"name":"flag-kz","image":"1f1f0-1f1ff.png","id":"1f1f0-1f1ff"},{"name":"flag-la","image":"1f1f1-1f1e6.png","id":"1f1f1-1f1e6"},{"name":"flag-lb","image":"1f1f1-1f1e7.png","id":"1f1f1-1f1e7"},{"name":"flag-lc","image":"1f1f1-1f1e8.png","id":"1f1f1-1f1e8"},{"name":"flag-li","image":"1f1f1-1f1ee.png","id":"1f1f1-1f1ee"},{"name":"flag-lk","image":"1f1f1-1f1f0.png","id":"1f1f1-1f1f0"},{"name":"flag-lr","image":"1f1f1-1f1f7.png","id":"1f1f1-1f1f7"},{"name":"flag-ls","image":"1f1f1-1f1f8.png","id":"1f1f1-1f1f8"},{"name":"flag-lt","image":"1f1f1-1f1f9.png","id":"1f1f1-1f1f9"},{"name":"flag-lu","image":"1f1f1-1f1fa.png","id":"1f1f1-1f1fa"},{"name":"flag-lv","image":"1f1f1-1f1fb.png","id":"1f1f1-1f1fb"},{"name":"flag-ly","image":"1f1f1-1f1fe.png","id":"1f1f1-1f1fe"},{"name":"flag-ma","image":"1f1f2-1f1e6.png","id":"1f1f2-1f1e6"},{"name":"flag-mc","image":"1f1f2-1f1e8.png","id":"1f1f2-1f1e8"},{"name":"flag-md","image":"1f1f2-1f1e9.png","id":"1f1f2-1f1e9"},{"name":"flag-me","image":"1f1f2-1f1ea.png","id":"1f1f2-1f1ea"},{"name":"flag-mf","image":"1f1f2-1f1eb.png","id":"1f1f2-1f1eb"},{"name":"flag-mg","image":"1f1f2-1f1ec.png","id":"1f1f2-1f1ec"},{"name":"flag-mh","image":"1f1f2-1f1ed.png","id":"1f1f2-1f1ed"},{"name":"flag-mk","image":"1f1f2-1f1f0.png","id":"1f1f2-1f1f0"},{"name":"flag-ml","image":"1f1f2-1f1f1.png","id":"1f1f2-1f1f1"},{"name":"flag-mm","image":"1f1f2-1f1f2.png","id":"1f1f2-1f1f2"},{"name":"flag-mn","image":"1f1f2-1f1f3.png","id":"1f1f2-1f1f3"},{"name":"flag-mo","image":"1f1f2-1f1f4.png","id":"1f1f2-1f1f4"},{"name":"flag-mp","image":"1f1f2-1f1f5.png","id":"1f1f2-1f1f5"},{"name":"flag-mq","image":"1f1f2-1f1f6.png","id":"1f1f2-1f1f6"},{"name":"flag-mr","image":"1f1f2-1f1f7.png","id":"1f1f2-1f1f7"},{"name":"flag-ms","image":"1f1f2-1f1f8.png","id":"1f1f2-1f1f8"},{"name":"flag-mt","image":"1f1f2-1f1f9.png","id":"1f1f2-1f1f9"},{"name":"flag-mu","image":"1f1f2-1f1fa.png","id":"1f1f2-1f1fa"},{"name":"flag-mv","image":"1f1f2-1f1fb.png","id":"1f1f2-1f1fb"},{"name":"flag-mw","image":"1f1f2-1f1fc.png","id":"1f1f2-1f1fc"},{"name":"flag-mx","image":"1f1f2-1f1fd.png","id":"1f1f2-1f1fd"},{"name":"flag-my","image":"1f1f2-1f1fe.png","id":"1f1f2-1f1fe"},{"name":"flag-mz","image":"1f1f2-1f1ff.png","id":"1f1f2-1f1ff"},{"name":"flag-na","image":"1f1f3-1f1e6.png","id":"1f1f3-1f1e6"},{"name":"flag-nc","image":"1f1f3-1f1e8.png","id":"1f1f3-1f1e8"},{"name":"flag-ne","image":"1f1f3-1f1ea.png","id":"1f1f3-1f1ea"},{"name":"flag-nf","image":"1f1f3-1f1eb.png","id":"1f1f3-1f1eb"},{"name":"flag-ng","image":"1f1f3-1f1ec.png","id":"1f1f3-1f1ec"},{"name":"flag-ni","image":"1f1f3-1f1ee.png","id":"1f1f3-1f1ee"},{"name":"flag-nl","image":"1f1f3-1f1f1.png","id":"1f1f3-1f1f1"},{"name":"flag-no","image":"1f1f3-1f1f4.png","id":"1f1f3-1f1f4"},{"name":"flag-np","image":"1f1f3-1f1f5.png","id":"1f1f3-1f1f5"},{"name":"flag-nr","image":"1f1f3-1f1f7.png","id":"1f1f3-1f1f7"},{"name":"flag-nu","image":"1f1f3-1f1fa.png","id":"1f1f3-1f1fa"},{"name":"flag-nz","image":"1f1f3-1f1ff.png","id":"1f1f3-1f1ff"},{"name":"flag-om","image":"1f1f4-1f1f2.png","id":"1f1f4-1f1f2"},{"name":"flag-pa","image":"1f1f5-1f1e6.png","id":"1f1f5-1f1e6"},{"name":"flag-pe","image":"1f1f5-1f1ea.png","id":"1f1f5-1f1ea"},{"name":"flag-pf","image":"1f1f5-1f1eb.png","id":"1f1f5-1f1eb"},{"name":"flag-pg","image":"1f1f5-1f1ec.png","id":"1f1f5-1f1ec"},{"name":"flag-ph","image":"1f1f5-1f1ed.png","id":"1f1f5-1f1ed"},{"name":"flag-pk","image":"1f1f5-1f1f0.png","id":"1f1f5-1f1f0"},{"name":"flag-pl","image":"1f1f5-1f1f1.png","id":"1f1f5-1f1f1"},{"name":"flag-pm","image":"1f1f5-1f1f2.png","id":"1f1f5-1f1f2"},{"name":"flag-pn","image":"1f1f5-1f1f3.png","id":"1f1f5-1f1f3"},{"name":"flag-pr","image":"1f1f5-1f1f7.png","id":"1f1f5-1f1f7"},{"name":"flag-ps","image":"1f1f5-1f1f8.png","id":"1f1f5-1f1f8"},{"name":"flag-pt","image":"1f1f5-1f1f9.png","id":"1f1f5-1f1f9"},{"name":"flag-pw","image":"1f1f5-1f1fc.png","id":"1f1f5-1f1fc"},{"name":"flag-py","image":"1f1f5-1f1fe.png","id":"1f1f5-1f1fe"},{"name":"flag-qa","image":"1f1f6-1f1e6.png","id":"1f1f6-1f1e6"},{"name":"flag-re","image":"1f1f7-1f1ea.png","id":"1f1f7-1f1ea"},{"name":"flag-ro","image":"1f1f7-1f1f4.png","id":"1f1f7-1f1f4"},{"name":"flag-rs","image":"1f1f7-1f1f8.png","id":"1f1f7-1f1f8"},{"name":"flag-ru","image":"1f1f7-1f1fa.png","id":"1f1f7-1f1fa"},{"name":"flag-rw","image":"1f1f7-1f1fc.png","id":"1f1f7-1f1fc"},{"name":"flag-sa","image":"1f1f8-1f1e6.png","id":"1f1f8-1f1e6"},{"name":"flag-sb","image":"1f1f8-1f1e7.png","id":"1f1f8-1f1e7"},{"name":"flag-sc","image":"1f1f8-1f1e8.png","id":"1f1f8-1f1e8"},{"name":"flag-sd","image":"1f1f8-1f1e9.png","id":"1f1f8-1f1e9"},{"name":"flag-se","image":"1f1f8-1f1ea.png","id":"1f1f8-1f1ea"},{"name":"flag-sg","image":"1f1f8-1f1ec.png","id":"1f1f8-1f1ec"},{"name":"flag-sh","image":"1f1f8-1f1ed.png","id":"1f1f8-1f1ed"},{"name":"flag-si","image":"1f1f8-1f1ee.png","id":"1f1f8-1f1ee"},{"name":"flag-sj","image":"1f1f8-1f1ef.png","id":"1f1f8-1f1ef"},{"name":"flag-sk","image":"1f1f8-1f1f0.png","id":"1f1f8-1f1f0"},{"name":"flag-sl","image":"1f1f8-1f1f1.png","id":"1f1f8-1f1f1"},{"name":"flag-sm","image":"1f1f8-1f1f2.png","id":"1f1f8-1f1f2"},{"name":"flag-sn","image":"1f1f8-1f1f3.png","id":"1f1f8-1f1f3"},{"name":"flag-so","image":"1f1f8-1f1f4.png","id":"1f1f8-1f1f4"},{"name":"flag-sr","image":"1f1f8-1f1f7.png","id":"1f1f8-1f1f7"},{"name":"flag-ss","image":"1f1f8-1f1f8.png","id":"1f1f8-1f1f8"},{"name":"flag-st","image":"1f1f8-1f1f9.png","id":"1f1f8-1f1f9"},{"name":"flag-sv","image":"1f1f8-1f1fb.png","id":"1f1f8-1f1fb"},{"name":"flag-sx","image":"1f1f8-1f1fd.png","id":"1f1f8-1f1fd"},{"name":"flag-sy","image":"1f1f8-1f1fe.png","id":"1f1f8-1f1fe"},{"name":"flag-sz","image":"1f1f8-1f1ff.png","id":"1f1f8-1f1ff"},{"name":"flag-ta","image":"1f1f9-1f1e6.png","id":"1f1f9-1f1e6"},{"name":"flag-tc","image":"1f1f9-1f1e8.png","id":"1f1f9-1f1e8"},{"name":"flag-td","image":"1f1f9-1f1e9.png","id":"1f1f9-1f1e9"},{"name":"flag-tf","image":"1f1f9-1f1eb.png","id":"1f1f9-1f1eb"},{"name":"flag-tg","image":"1f1f9-1f1ec.png","id":"1f1f9-1f1ec"},{"name":"flag-th","image":"1f1f9-1f1ed.png","id":"1f1f9-1f1ed"},{"name":"flag-tj","image":"1f1f9-1f1ef.png","id":"1f1f9-1f1ef"},{"name":"flag-tk","image":"1f1f9-1f1f0.png","id":"1f1f9-1f1f0"},{"name":"flag-tl","image":"1f1f9-1f1f1.png","id":"1f1f9-1f1f1"},{"name":"flag-tm","image":"1f1f9-1f1f2.png","id":"1f1f9-1f1f2"},{"name":"flag-tn","image":"1f1f9-1f1f3.png","id":"1f1f9-1f1f3"},{"name":"flag-to","image":"1f1f9-1f1f4.png","id":"1f1f9-1f1f4"},{"name":"flag-tr","image":"1f1f9-1f1f7.png","id":"1f1f9-1f1f7"},{"name":"flag-tt","image":"1f1f9-1f1f9.png","id":"1f1f9-1f1f9"},{"name":"flag-tv","image":"1f1f9-1f1fb.png","id":"1f1f9-1f1fb"},{"name":"flag-tw","image":"1f1f9-1f1fc.png","id":"1f1f9-1f1fc"},{"name":"flag-tz","image":"1f1f9-1f1ff.png","id":"1f1f9-1f1ff"},{"name":"flag-ua","image":"1f1fa-1f1e6.png","id":"1f1fa-1f1e6"},{"name":"flag-ug","image":"1f1fa-1f1ec.png","id":"1f1fa-1f1ec"},{"name":"flag-um","image":"1f1fa-1f1f2.png","id":"1f1fa-1f1f2"},{"name":"flag-us","image":"1f1fa-1f1f8.png","id":"1f1fa-1f1f8"},{"name":"flag-uy","image":"1f1fa-1f1fe.png","id":"1f1fa-1f1fe"},{"name":"flag-uz","image":"1f1fa-1f1ff.png","id":"1f1fa-1f1ff"},{"name":"flag-va","image":"1f1fb-1f1e6.png","id":"1f1fb-1f1e6"},{"name":"flag-vc","image":"1f1fb-1f1e8.png","id":"1f1fb-1f1e8"},{"name":"flag-ve","image":"1f1fb-1f1ea.png","id":"1f1fb-1f1ea"},{"name":"flag-vg","image":"1f1fb-1f1ec.png","id":"1f1fb-1f1ec"},{"name":"flag-vi","image":"1f1fb-1f1ee.png","id":"1f1fb-1f1ee"},{"name":"flag-vn","image":"1f1fb-1f1f3.png","id":"1f1fb-1f1f3"},{"name":"flag-vu","image":"1f1fb-1f1fa.png","id":"1f1fb-1f1fa"},{"name":"flag-wf","image":"1f1fc-1f1eb.png","id":"1f1fc-1f1eb"},{"name":"flag-ws","image":"1f1fc-1f1f8.png","id":"1f1fc-1f1f8"},{"name":"flag-xk","image":"1f1fd-1f1f0.png","id":"1f1fd-1f1f0"},{"name":"flag-ye","image":"1f1fe-1f1ea.png","id":"1f1fe-1f1ea"},{"name":"flag-yt","image":"1f1fe-1f1f9.png","id":"1f1fe-1f1f9"},{"name":"flag-za","image":"1f1ff-1f1e6.png","id":"1f1ff-1f1e6"},{"name":"flag-zm","image":"1f1ff-1f1f2.png","id":"1f1ff-1f1f2"},{"name":"flag-zw","image":"1f1ff-1f1fc.png","id":"1f1ff-1f1fc"},{"name":"flags","image":"1f38f.png","id":"1f38f"},{"name":"flashlight","image":"1f526.png","id":"1f526"},{"name":"fleur_de_lis","image":"269c.png","id":"269c"},{"name":"floppy_disk","image":"1f4be.png","id":"1f4be"},{"name":"flower_playing_cards","image":"1f3b4.png","id":"1f3b4"},{"name":"flushed","image":"1f633.png","id":"1f633"},{"name":"fog","image":"1f32b.png","id":"1f32b"},{"name":"foggy","image":"1f301.png","id":"1f301"},{"name":"football","image":"1f3c8.png","id":"1f3c8"},{"name":"footprints","image":"1f463.png","id":"1f463"},{"name":"fork_and_knife","image":"1f374.png","id":"1f374"},{"name":"fountain","image":"26f2.png","id":"26f2"},{"name":"four","image":"0034-20e3.png","id":"0034-20e3"},{"name":"four_leaf_clover","image":"1f340.png","id":"1f340"},{"name":"frame_with_picture","image":"1f5bc.png","id":"1f5bc"},{"name":"free","image":"1f193.png","id":"1f193"},{"name":"fried_shrimp","image":"1f364.png","id":"1f364"},{"name":"fries","image":"1f35f.png","id":"1f35f"},{"name":"frog","image":"1f438.png","id":"1f438"},{"name":"frowning","image":"1f626.png","id":"1f626"},{"name":"fuelpump","image":"26fd.png","id":"26fd"},{"name":"full_moon","image":"1f315.png","id":"1f315"},{"name":"full_moon_with_face","image":"1f31d.png","id":"1f31d"},{"name":"funeral_urn","image":"26b1.png","id":"26b1"},{"name":"game_die","image":"1f3b2.png","id":"1f3b2"},{"name":"gear","image":"2699.png","id":"2699"},{"name":"gem","image":"1f48e.png","id":"1f48e"},{"name":"gemini","image":"264a.png","id":"264a"},{"name":"ghost","image":"1f47b.png","id":"1f47b"},{"name":"gift","image":"1f381.png","id":"1f381"},{"name":"gift_heart","image":"1f49d.png","id":"1f49d"},{"name":"girl","image":"1f467.png","id":"1f467"},{"name":"globe_with_meridians","image":"1f310.png","id":"1f310"},{"name":"goat","image":"1f410.png","id":"1f410"},{"name":"golf","image":"26f3.png","id":"26f3"},{"name":"golfer","image":"1f3cc.png","id":"1f3cc"},{"name":"grapes","image":"1f347.png","id":"1f347"},{"name":"green_apple","image":"1f34f.png","id":"1f34f"},{"name":"green_book","image":"1f4d7.png","id":"1f4d7"},{"name":"green_heart","image":"1f49a.png","id":"1f49a"},{"name":"grey_exclamation","image":"2755.png","id":"2755"},{"name":"grey_question","image":"2754.png","id":"2754"},{"name":"grimacing","image":"1f62c.png","id":"1f62c"},{"name":"grin","image":"1f601.png","id":"1f601"},{"name":"grinning","image":"1f600.png","id":"1f600"},{"name":"guardsman","image":"1f482.png","id":"1f482"},{"name":"guitar","image":"1f3b8.png","id":"1f3b8"},{"name":"gun","image":"1f52b.png","id":"1f52b"},{"name":"haircut","image":"1f487.png","id":"1f487"},{"name":"hamburger","image":"1f354.png","id":"1f354"},{"name":"hammer","image":"1f528.png","id":"1f528"},{"name":"hammer_and_pick","image":"2692.png","id":"2692"},{"name":"hammer_and_wrench","image":"1f6e0.png","id":"1f6e0"},{"name":"hamster","image":"1f439.png","id":"1f439"},{"name":"hand","image":"270b.png","id":"270b"},{"name":"handbag","image":"1f45c.png","id":"1f45c"},{"name":"hankey","image":"1f4a9.png","id":"1f4a9"},{"name":"hash","image":"0023-20e3.png","id":"0023-20e3"},{"name":"hatched_chick","image":"1f425.png","id":"1f425"},{"name":"hatching_chick","image":"1f423.png","id":"1f423"},{"name":"headphones","image":"1f3a7.png","id":"1f3a7"},{"name":"hear_no_evil","image":"1f649.png","id":"1f649"},{"name":"heart","image":"2764.png","id":"2764"},{"name":"heart_decoration","image":"1f49f.png","id":"1f49f"},{"name":"heart_eyes","image":"1f60d.png","id":"1f60d"},{"name":"heart_eyes_cat","image":"1f63b.png","id":"1f63b"},{"name":"heartbeat","image":"1f493.png","id":"1f493"},{"name":"heartpulse","image":"1f497.png","id":"1f497"},{"name":"hearts","image":"2665.png","id":"2665"},{"name":"heavy_check_mark","image":"2714.png","id":"2714"},{"name":"heavy_division_sign","image":"2797.png","id":"2797"},{"name":"heavy_dollar_sign","image":"1f4b2.png","id":"1f4b2"},{"name":"heavy_heart_exclamation_mark_ornament","image":"2763.png","id":"2763"},{"name":"heavy_minus_sign","image":"2796.png","id":"2796"},{"name":"heavy_multiplication_x","image":"2716.png","id":"2716"},{"name":"heavy_plus_sign","image":"2795.png","id":"2795"},{"name":"helicopter","image":"1f681.png","id":"1f681"},{"name":"helmet_with_white_cross","image":"26d1.png","id":"26d1"},{"name":"herb","image":"1f33f.png","id":"1f33f"},{"name":"hibiscus","image":"1f33a.png","id":"1f33a"},{"name":"high_brightness","image":"1f506.png","id":"1f506"},{"name":"high_heel","image":"1f460.png","id":"1f460"},{"name":"hocho","image":"1f52a.png","id":"1f52a"},{"name":"hole","image":"1f573.png","id":"1f573"},{"name":"honey_pot","image":"1f36f.png","id":"1f36f"},{"name":"horse","image":"1f434.png","id":"1f434"},{"name":"horse_racing","image":"1f3c7.png","id":"1f3c7"},{"name":"hospital","image":"1f3e5.png","id":"1f3e5"},{"name":"hot_pepper","image":"1f336.png","id":"1f336"},{"name":"hotdog","image":"1f32d.png","id":"1f32d"},{"name":"hotel","image":"1f3e8.png","id":"1f3e8"},{"name":"hotsprings","image":"2668.png","id":"2668"},{"name":"hourglass","image":"231b.png","id":"231b"},{"name":"hourglass_flowing_sand","image":"23f3.png","id":"23f3"},{"name":"house","image":"1f3e0.png","id":"1f3e0"},{"name":"house_buildings","image":"1f3d8.png","id":"1f3d8"},{"name":"house_with_garden","image":"1f3e1.png","id":"1f3e1"},{"name":"hugging_face","image":"1f917.png","id":"1f917"},{"name":"hushed","image":"1f62f.png","id":"1f62f"},{"name":"ice_cream","image":"1f368.png","id":"1f368"},{"name":"ice_hockey_stick_and_puck","image":"1f3d2.png","id":"1f3d2"},{"name":"ice_skate","image":"26f8.png","id":"26f8"},{"name":"icecream","image":"1f366.png","id":"1f366"},{"name":"id","image":"1f194.png","id":"1f194"},{"name":"ideograph_advantage","image":"1f250.png","id":"1f250"},{"name":"imp","image":"1f47f.png","id":"1f47f"},{"name":"inbox_tray","image":"1f4e5.png","id":"1f4e5"},{"name":"incoming_envelope","image":"1f4e8.png","id":"1f4e8"},{"name":"information_desk_person","image":"1f481.png","id":"1f481"},{"name":"information_source","image":"2139.png","id":"2139"},{"name":"innocent","image":"1f607.png","id":"1f607"},{"name":"interrobang","image":"2049.png","id":"2049"},{"name":"iphone","image":"1f4f1.png","id":"1f4f1"},{"name":"izakaya_lantern","image":"1f3ee.png","id":"1f3ee"},{"name":"jack_o_lantern","image":"1f383.png","id":"1f383"},{"name":"japan","image":"1f5fe.png","id":"1f5fe"},{"name":"japanese_castle","image":"1f3ef.png","id":"1f3ef"},{"name":"japanese_goblin","image":"1f47a.png","id":"1f47a"},{"name":"japanese_ogre","image":"1f479.png","id":"1f479"},{"name":"jeans","image":"1f456.png","id":"1f456"},{"name":"joy","image":"1f602.png","id":"1f602"},{"name":"joy_cat","image":"1f639.png","id":"1f639"},{"name":"joystick","image":"1f579.png","id":"1f579"},{"name":"kaaba","image":"1f54b.png","id":"1f54b"},{"name":"key","image":"1f511.png","id":"1f511"},{"name":"keyboard","image":"2328.png","id":"2328"},{"name":"keycap_star","image":"002a-20e3.png","id":"002a-20e3"},{"name":"keycap_ten","image":"1f51f.png","id":"1f51f"},{"name":"kimono","image":"1f458.png","id":"1f458"},{"name":"kiss","image":"1f48b.png","id":"1f48b"},{"name":"kissing","image":"1f617.png","id":"1f617"},{"name":"kissing_cat","image":"1f63d.png","id":"1f63d"},{"name":"kissing_closed_eyes","image":"1f61a.png","id":"1f61a"},{"name":"kissing_heart","image":"1f618.png","id":"1f618"},{"name":"kissing_smiling_eyes","image":"1f619.png","id":"1f619"},{"name":"knife_fork_plate","image":"1f37d.png","id":"1f37d"},{"name":"koala","image":"1f428.png","id":"1f428"},{"name":"koko","image":"1f201.png","id":"1f201"},{"name":"label","image":"1f3f7.png","id":"1f3f7"},{"name":"large_blue_circle","image":"1f535.png","id":"1f535"},{"name":"large_blue_diamond","image":"1f537.png","id":"1f537"},{"name":"large_orange_diamond","image":"1f536.png","id":"1f536"},{"name":"last_quarter_moon","image":"1f317.png","id":"1f317"},{"name":"last_quarter_moon_with_face","image":"1f31c.png","id":"1f31c"},{"name":"latin_cross","image":"271d.png","id":"271d"},{"name":"laughing","image":"1f606.png","id":"1f606"},{"name":"leaves","image":"1f343.png","id":"1f343"},{"name":"ledger","image":"1f4d2.png","id":"1f4d2"},{"name":"left_luggage","image":"1f6c5.png","id":"1f6c5"},{"name":"left_right_arrow","image":"2194.png","id":"2194"},{"name":"left_speech_bubble","image":"1f5e8.png","id":"1f5e8"},{"name":"leftwards_arrow_with_hook","image":"21a9.png","id":"21a9"},{"name":"lemon","image":"1f34b.png","id":"1f34b"},{"name":"leo","image":"264c.png","id":"264c"},{"name":"leopard","image":"1f406.png","id":"1f406"},{"name":"level_slider","image":"1f39a.png","id":"1f39a"},{"name":"libra","image":"264e.png","id":"264e"},{"name":"light_rail","image":"1f688.png","id":"1f688"},{"name":"lightning","image":"1f329.png","id":"1f329"},{"name":"link","image":"1f517.png","id":"1f517"},{"name":"linked_paperclips","image":"1f587.png","id":"1f587"},{"name":"lion_face","image":"1f981.png","id":"1f981"},{"name":"lips","image":"1f444.png","id":"1f444"},{"name":"lipstick","image":"1f484.png","id":"1f484"},{"name":"lock","image":"1f512.png","id":"1f512"},{"name":"lock_with_ink_pen","image":"1f50f.png","id":"1f50f"},{"name":"lollipop","image":"1f36d.png","id":"1f36d"},{"name":"loop","image":"27bf.png","id":"27bf"},{"name":"loud_sound","image":"1f50a.png","id":"1f50a"},{"name":"loudspeaker","image":"1f4e2.png","id":"1f4e2"},{"name":"love_hotel","image":"1f3e9.png","id":"1f3e9"},{"name":"love_letter","image":"1f48c.png","id":"1f48c"},{"name":"low_brightness","image":"1f505.png","id":"1f505"},{"name":"lower_left_ballpoint_pen","image":"1f58a.png","id":"1f58a"},{"name":"lower_left_crayon","image":"1f58d.png","id":"1f58d"},{"name":"lower_left_fountain_pen","image":"1f58b.png","id":"1f58b"},{"name":"lower_left_paintbrush","image":"1f58c.png","id":"1f58c"},{"name":"m","image":"24c2.png","id":"24c2"},{"name":"mag","image":"1f50d.png","id":"1f50d"},{"name":"mag_right","image":"1f50e.png","id":"1f50e"},{"name":"mahjong","image":"1f004.png","id":"1f004"},{"name":"mailbox","image":"1f4eb.png","id":"1f4eb"},{"name":"mailbox_closed","image":"1f4ea.png","id":"1f4ea"},{"name":"mailbox_with_mail","image":"1f4ec.png","id":"1f4ec"},{"name":"mailbox_with_no_mail","image":"1f4ed.png","id":"1f4ed"},{"name":"man","image":"1f468.png","id":"1f468"},{"name":"man-heart-man","image":"1f468-200d-2764-fe0f-200d-1f468.png","id":"1f468-200d-2764-fe0f-200d-1f468"},{"name":"man-kiss-man","image":"1f468-200d-2764-fe0f-200d-1f48b-200d-1f468.png","id":"1f468-200d-2764-fe0f-200d-1f48b-200d-1f468"},{"name":"man-man-boy","image":"1f468-200d-1f468-200d-1f466.png","id":"1f468-200d-1f468-200d-1f466"},{"name":"man-man-boy-boy","image":"1f468-200d-1f468-200d-1f466-200d-1f466.png","id":"1f468-200d-1f468-200d-1f466-200d-1f466"},{"name":"man-man-girl","image":"1f468-200d-1f468-200d-1f467.png","id":"1f468-200d-1f468-200d-1f467"},{"name":"man-man-girl-boy","image":"1f468-200d-1f468-200d-1f467-200d-1f466.png","id":"1f468-200d-1f468-200d-1f467-200d-1f466"},{"name":"man-man-girl-girl","image":"1f468-200d-1f468-200d-1f467-200d-1f467.png","id":"1f468-200d-1f468-200d-1f467-200d-1f467"},{"name":"man-woman-boy-boy","image":"1f468-200d-1f469-200d-1f466-200d-1f466.png","id":"1f468-200d-1f469-200d-1f466-200d-1f466"},{"name":"man-woman-girl","image":"1f468-200d-1f469-200d-1f467.png","id":"1f468-200d-1f469-200d-1f467"},{"name":"man-woman-girl-boy","image":"1f468-200d-1f469-200d-1f467-200d-1f466.png","id":"1f468-200d-1f469-200d-1f467-200d-1f466"},{"name":"man-woman-girl-girl","image":"1f468-200d-1f469-200d-1f467-200d-1f467.png","id":"1f468-200d-1f469-200d-1f467-200d-1f467"},{"name":"man_in_business_suit_levitating","image":"1f574.png","id":"1f574"},{"name":"man_with_gua_pi_mao","image":"1f472.png","id":"1f472"},{"name":"man_with_turban","image":"1f473.png","id":"1f473"},{"name":"mans_shoe","image":"1f45e.png","id":"1f45e"},{"name":"mantelpiece_clock","image":"1f570.png","id":"1f570"},{"name":"maple_leaf","image":"1f341.png","id":"1f341"},{"name":"mask","image":"1f637.png","id":"1f637"},{"name":"massage","image":"1f486.png","id":"1f486"},{"name":"meat_on_bone","image":"1f356.png","id":"1f356"},{"name":"medal","image":"1f396.png","id":"1f396"},{"name":"mega","image":"1f4e3.png","id":"1f4e3"},{"name":"melon","image":"1f348.png","id":"1f348"},{"name":"memo","image":"1f4dd.png","id":"1f4dd"},{"name":"menorah_with_nine_branches","image":"1f54e.png","id":"1f54e"},{"name":"mens","image":"1f6b9.png","id":"1f6b9"},{"name":"metro","image":"1f687.png","id":"1f687"},{"name":"microphone","image":"1f3a4.png","id":"1f3a4"},{"name":"microscope","image":"1f52c.png","id":"1f52c"},{"name":"middle_finger","image":"1f595.png","id":"1f595"},{"name":"milky_way","image":"1f30c.png","id":"1f30c"},{"name":"minibus","image":"1f690.png","id":"1f690"},{"name":"minidisc","image":"1f4bd.png","id":"1f4bd"},{"name":"mobile_phone_off","image":"1f4f4.png","id":"1f4f4"},{"name":"money_mouth_face","image":"1f911.png","id":"1f911"},{"name":"money_with_wings","image":"1f4b8.png","id":"1f4b8"},{"name":"moneybag","image":"1f4b0.png","id":"1f4b0"},{"name":"monkey","image":"1f412.png","id":"1f412"},{"name":"monkey_face","image":"1f435.png","id":"1f435"},{"name":"monorail","image":"1f69d.png","id":"1f69d"},{"name":"moon","image":"1f314.png","id":"1f314"},{"name":"mortar_board","image":"1f393.png","id":"1f393"},{"name":"mosque","image":"1f54c.png","id":"1f54c"},{"name":"mostly_sunny","image":"1f324.png","id":"1f324"},{"name":"motor_boat","image":"1f6e5.png","id":"1f6e5"},{"name":"motorway","image":"1f6e3.png","id":"1f6e3"},{"name":"mount_fuji","image":"1f5fb.png","id":"1f5fb"},{"name":"mountain","image":"26f0.png","id":"26f0"},{"name":"mountain_bicyclist","image":"1f6b5.png","id":"1f6b5"},{"name":"mountain_cableway","image":"1f6a0.png","id":"1f6a0"},{"name":"mountain_railway","image":"1f69e.png","id":"1f69e"},{"name":"mouse","image":"1f42d.png","id":"1f42d"},{"name":"mouse2","image":"1f401.png","id":"1f401"},{"name":"movie_camera","image":"1f3a5.png","id":"1f3a5"},{"name":"moyai","image":"1f5ff.png","id":"1f5ff"},{"name":"muscle","image":"1f4aa.png","id":"1f4aa"},{"name":"mushroom","image":"1f344.png","id":"1f344"},{"name":"musical_keyboard","image":"1f3b9.png","id":"1f3b9"},{"name":"musical_note","image":"1f3b5.png","id":"1f3b5"},{"name":"musical_score","image":"1f3bc.png","id":"1f3bc"},{"name":"mute","image":"1f507.png","id":"1f507"},{"name":"nail_care","image":"1f485.png","id":"1f485"},{"name":"name_badge","image":"1f4db.png","id":"1f4db"},{"name":"national_park","image":"1f3de.png","id":"1f3de"},{"name":"necktie","image":"1f454.png","id":"1f454"},{"name":"negative_squared_cross_mark","image":"274e.png","id":"274e"},{"name":"nerd_face","image":"1f913.png","id":"1f913"},{"name":"neutral_face","image":"1f610.png","id":"1f610"},{"name":"new","image":"1f195.png","id":"1f195"},{"name":"new_moon","image":"1f311.png","id":"1f311"},{"name":"new_moon_with_face","image":"1f31a.png","id":"1f31a"},{"name":"newspaper","image":"1f4f0.png","id":"1f4f0"},{"name":"ng","image":"1f196.png","id":"1f196"},{"name":"night_with_stars","image":"1f303.png","id":"1f303"},{"name":"nine","image":"0039-20e3.png","id":"0039-20e3"},{"name":"no_bell","image":"1f515.png","id":"1f515"},{"name":"no_bicycles","image":"1f6b3.png","id":"1f6b3"},{"name":"no_entry","image":"26d4.png","id":"26d4"},{"name":"no_entry_sign","image":"1f6ab.png","id":"1f6ab"},{"name":"no_good","image":"1f645.png","id":"1f645"},{"name":"no_mobile_phones","image":"1f4f5.png","id":"1f4f5"},{"name":"no_mouth","image":"1f636.png","id":"1f636"},{"name":"no_pedestrians","image":"1f6b7.png","id":"1f6b7"},{"name":"no_smoking","image":"1f6ad.png","id":"1f6ad"},{"name":"non-potable_water","image":"1f6b1.png","id":"1f6b1"},{"name":"nose","image":"1f443.png","id":"1f443"},{"name":"notebook","image":"1f4d3.png","id":"1f4d3"},{"name":"notebook_with_decorative_cover","image":"1f4d4.png","id":"1f4d4"},{"name":"notes","image":"1f3b6.png","id":"1f3b6"},{"name":"nut_and_bolt","image":"1f529.png","id":"1f529"},{"name":"o","image":"2b55.png","id":"2b55"},{"name":"o2","image":"1f17e.png","id":"1f17e"},{"name":"ocean","image":"1f30a.png","id":"1f30a"},{"name":"octopus","image":"1f419.png","id":"1f419"},{"name":"oden","image":"1f362.png","id":"1f362"},{"name":"office","image":"1f3e2.png","id":"1f3e2"},{"name":"oil_drum","image":"1f6e2.png","id":"1f6e2"},{"name":"ok","image":"1f197.png","id":"1f197"},{"name":"ok_hand","image":"1f44c.png","id":"1f44c"},{"name":"ok_woman","image":"1f646.png","id":"1f646"},{"name":"old_key","image":"1f5dd.png","id":"1f5dd"},{"name":"older_man","image":"1f474.png","id":"1f474"},{"name":"older_woman","image":"1f475.png","id":"1f475"},{"name":"om_symbol","image":"1f549.png","id":"1f549"},{"name":"on","image":"1f51b.png","id":"1f51b"},{"name":"oncoming_automobile","image":"1f698.png","id":"1f698"},{"name":"oncoming_bus","image":"1f68d.png","id":"1f68d"},{"name":"oncoming_police_car","image":"1f694.png","id":"1f694"},{"name":"oncoming_taxi","image":"1f696.png","id":"1f696"},{"name":"one","image":"0031-20e3.png","id":"0031-20e3"},{"name":"open_file_folder","image":"1f4c2.png","id":"1f4c2"},{"name":"open_hands","image":"1f450.png","id":"1f450"},{"name":"open_mouth","image":"1f62e.png","id":"1f62e"},{"name":"ophiuchus","image":"26ce.png","id":"26ce"},{"name":"orange_book","image":"1f4d9.png","id":"1f4d9"},{"name":"orthodox_cross","image":"2626.png","id":"2626"},{"name":"outbox_tray","image":"1f4e4.png","id":"1f4e4"},{"name":"ox","image":"1f402.png","id":"1f402"},{"name":"package","image":"1f4e6.png","id":"1f4e6"},{"name":"page_facing_up","image":"1f4c4.png","id":"1f4c4"},{"name":"page_with_curl","image":"1f4c3.png","id":"1f4c3"},{"name":"pager","image":"1f4df.png","id":"1f4df"},{"name":"palm_tree","image":"1f334.png","id":"1f334"},{"name":"panda_face","image":"1f43c.png","id":"1f43c"},{"name":"paperclip","image":"1f4ce.png","id":"1f4ce"},{"name":"parking","image":"1f17f.png","id":"1f17f"},{"name":"part_alternation_mark","image":"303d.png","id":"303d"},{"name":"partly_sunny","image":"26c5.png","id":"26c5"},{"name":"partly_sunny_rain","image":"1f326.png","id":"1f326"},{"name":"passenger_ship","image":"1f6f3.png","id":"1f6f3"},{"name":"passport_control","image":"1f6c2.png","id":"1f6c2"},{"name":"peace_symbol","image":"262e.png","id":"262e"},{"name":"peach","image":"1f351.png","id":"1f351"},{"name":"pear","image":"1f350.png","id":"1f350"},{"name":"pencil2","image":"270f.png","id":"270f"},{"name":"penguin","image":"1f427.png","id":"1f427"},{"name":"pensive","image":"1f614.png","id":"1f614"},{"name":"performing_arts","image":"1f3ad.png","id":"1f3ad"},{"name":"persevere","image":"1f623.png","id":"1f623"},{"name":"person_frowning","image":"1f64d.png","id":"1f64d"},{"name":"person_with_ball","image":"26f9.png","id":"26f9"},{"name":"person_with_blond_hair","image":"1f471.png","id":"1f471"},{"name":"person_with_pouting_face","image":"1f64e.png","id":"1f64e"},{"name":"phone","image":"260e.png","id":"260e"},{"name":"pick","image":"26cf.png","id":"26cf"},{"name":"pig","image":"1f437.png","id":"1f437"},{"name":"pig2","image":"1f416.png","id":"1f416"},{"name":"pig_nose","image":"1f43d.png","id":"1f43d"},{"name":"pill","image":"1f48a.png","id":"1f48a"},{"name":"pineapple","image":"1f34d.png","id":"1f34d"},{"name":"pisces","image":"2653.png","id":"2653"},{"name":"pizza","image":"1f355.png","id":"1f355"},{"name":"place_of_worship","image":"1f6d0.png","id":"1f6d0"},{"name":"point_down","image":"1f447.png","id":"1f447"},{"name":"point_left","image":"1f448.png","id":"1f448"},{"name":"point_right","image":"1f449.png","id":"1f449"},{"name":"point_up","image":"261d.png","id":"261d"},{"name":"point_up_2","image":"1f446.png","id":"1f446"},{"name":"police_car","image":"1f693.png","id":"1f693"},{"name":"poodle","image":"1f429.png","id":"1f429"},{"name":"popcorn","image":"1f37f.png","id":"1f37f"},{"name":"post_office","image":"1f3e3.png","id":"1f3e3"},{"name":"postal_horn","image":"1f4ef.png","id":"1f4ef"},{"name":"postbox","image":"1f4ee.png","id":"1f4ee"},{"name":"potable_water","image":"1f6b0.png","id":"1f6b0"},{"name":"pouch","image":"1f45d.png","id":"1f45d"},{"name":"poultry_leg","image":"1f357.png","id":"1f357"},{"name":"pound","image":"1f4b7.png","id":"1f4b7"},{"name":"pouting_cat","image":"1f63e.png","id":"1f63e"},{"name":"pray","image":"1f64f.png","id":"1f64f"},{"name":"prayer_beads","image":"1f4ff.png","id":"1f4ff"},{"name":"princess","image":"1f478.png","id":"1f478"},{"name":"printer","image":"1f5a8.png","id":"1f5a8"},{"name":"purple_heart","image":"1f49c.png","id":"1f49c"},{"name":"purse","image":"1f45b.png","id":"1f45b"},{"name":"pushpin","image":"1f4cc.png","id":"1f4cc"},{"name":"put_litter_in_its_place","image":"1f6ae.png","id":"1f6ae"},{"name":"question","image":"2753.png","id":"2753"},{"name":"rabbit","image":"1f430.png","id":"1f430"},{"name":"rabbit2","image":"1f407.png","id":"1f407"},{"name":"racehorse","image":"1f40e.png","id":"1f40e"},{"name":"racing_car","image":"1f3ce.png","id":"1f3ce"},{"name":"racing_motorcycle","image":"1f3cd.png","id":"1f3cd"},{"name":"radio","image":"1f4fb.png","id":"1f4fb"},{"name":"radio_button","image":"1f518.png","id":"1f518"},{"name":"radioactive_sign","image":"2622.png","id":"2622"},{"name":"rage","image":"1f621.png","id":"1f621"},{"name":"railway_car","image":"1f683.png","id":"1f683"},{"name":"railway_track","image":"1f6e4.png","id":"1f6e4"},{"name":"rain_cloud","image":"1f327.png","id":"1f327"},{"name":"rainbow","image":"1f308.png","id":"1f308"},{"name":"raised_hand_with_fingers_splayed","image":"1f590.png","id":"1f590"},{"name":"raised_hands","image":"1f64c.png","id":"1f64c"},{"name":"raising_hand","image":"1f64b.png","id":"1f64b"},{"name":"ram","image":"1f40f.png","id":"1f40f"},{"name":"ramen","image":"1f35c.png","id":"1f35c"},{"name":"rat","image":"1f400.png","id":"1f400"},{"name":"recycle","image":"267b.png","id":"267b"},{"name":"red_circle","image":"1f534.png","id":"1f534"},{"name":"relaxed","image":"263a.png","id":"263a"},{"name":"relieved","image":"1f60c.png","id":"1f60c"},{"name":"reminder_ribbon","image":"1f397.png","id":"1f397"},{"name":"repeat","image":"1f501.png","id":"1f501"},{"name":"repeat_one","image":"1f502.png","id":"1f502"},{"name":"restroom","image":"1f6bb.png","id":"1f6bb"},{"name":"revolving_hearts","image":"1f49e.png","id":"1f49e"},{"name":"rewind","image":"23ea.png","id":"23ea"},{"name":"ribbon","image":"1f380.png","id":"1f380"},{"name":"rice","image":"1f35a.png","id":"1f35a"},{"name":"rice_ball","image":"1f359.png","id":"1f359"},{"name":"rice_cracker","image":"1f358.png","id":"1f358"},{"name":"rice_scene","image":"1f391.png","id":"1f391"},{"name":"right_anger_bubble","image":"1f5ef.png","id":"1f5ef"},{"name":"ring","image":"1f48d.png","id":"1f48d"},{"name":"robot_face","image":"1f916.png","id":"1f916"},{"name":"rocket","image":"1f680.png","id":"1f680"},{"name":"rolled_up_newspaper","image":"1f5de.png","id":"1f5de"},{"name":"roller_coaster","image":"1f3a2.png","id":"1f3a2"},{"name":"rooster","image":"1f413.png","id":"1f413"},{"name":"rose","image":"1f339.png","id":"1f339"},{"name":"rosette","image":"1f3f5.png","id":"1f3f5"},{"name":"rotating_light","image":"1f6a8.png","id":"1f6a8"},{"name":"round_pushpin","image":"1f4cd.png","id":"1f4cd"},{"name":"rowboat","image":"1f6a3.png","id":"1f6a3"},{"name":"rugby_football","image":"1f3c9.png","id":"1f3c9"},{"name":"runner","image":"1f3c3.png","id":"1f3c3"},{"name":"running_shirt_with_sash","image":"1f3bd.png","id":"1f3bd"},{"name":"sa","image":"1f202.png","id":"1f202"},{"name":"sagittarius","image":"2650.png","id":"2650"},{"name":"sake","image":"1f376.png","id":"1f376"},{"name":"sandal","image":"1f461.png","id":"1f461"},{"name":"santa","image":"1f385.png","id":"1f385"},{"name":"satellite","image":"1f6f0.png","id":"1f6f0"},{"name":"satellite_antenna","image":"1f4e1.png","id":"1f4e1"},{"name":"saxophone","image":"1f3b7.png","id":"1f3b7"},{"name":"scales","image":"2696.png","id":"2696"},{"name":"school","image":"1f3eb.png","id":"1f3eb"},{"name":"school_satchel","image":"1f392.png","id":"1f392"},{"name":"scissors","image":"2702.png","id":"2702"},{"name":"scorpion","image":"1f982.png","id":"1f982"},{"name":"scorpius","image":"264f.png","id":"264f"},{"name":"scream","image":"1f631.png","id":"1f631"},{"name":"scream_cat","image":"1f640.png","id":"1f640"},{"name":"scroll","image":"1f4dc.png","id":"1f4dc"},{"name":"seat","image":"1f4ba.png","id":"1f4ba"},{"name":"secret","image":"3299.png","id":"3299"},{"name":"see_no_evil","image":"1f648.png","id":"1f648"},{"name":"seedling","image":"1f331.png","id":"1f331"},{"name":"seven","image":"0037-20e3.png","id":"0037-20e3"},{"name":"shamrock","image":"2618.png","id":"2618"},{"name":"shaved_ice","image":"1f367.png","id":"1f367"},{"name":"sheep","image":"1f411.png","id":"1f411"},{"name":"shell","image":"1f41a.png","id":"1f41a"},{"name":"shield","image":"1f6e1.png","id":"1f6e1"},{"name":"shinto_shrine","image":"26e9.png","id":"26e9"},{"name":"ship","image":"1f6a2.png","id":"1f6a2"},{"name":"shirt","image":"1f455.png","id":"1f455"},{"name":"shopping_bags","image":"1f6cd.png","id":"1f6cd"},{"name":"shower","image":"1f6bf.png","id":"1f6bf"},{"name":"signal_strength","image":"1f4f6.png","id":"1f4f6"},{"name":"six","image":"0036-20e3.png","id":"0036-20e3"},{"name":"six_pointed_star","image":"1f52f.png","id":"1f52f"},{"name":"ski","image":"1f3bf.png","id":"1f3bf"},{"name":"skier","image":"26f7.png","id":"26f7"},{"name":"skin-tone-2","image":"1f3fb.png","id":"1f3fb"},{"name":"skin-tone-3","image":"1f3fc.png","id":"1f3fc"},{"name":"skin-tone-4","image":"1f3fd.png","id":"1f3fd"},{"name":"skin-tone-5","image":"1f3fe.png","id":"1f3fe"},{"name":"skin-tone-6","image":"1f3ff.png","id":"1f3ff"},{"name":"skull","image":"1f480.png","id":"1f480"},{"name":"skull_and_crossbones","image":"2620.png","id":"2620"},{"name":"sleeping","image":"1f634.png","id":"1f634"},{"name":"sleeping_accommodation","image":"1f6cc.png","id":"1f6cc"},{"name":"sleepy","image":"1f62a.png","id":"1f62a"},{"name":"sleuth_or_spy","image":"1f575.png","id":"1f575"},{"name":"slightly_frowning_face","image":"1f641.png","id":"1f641"},{"name":"slightly_smiling_face","image":"1f642.png","id":"1f642"},{"name":"slot_machine","image":"1f3b0.png","id":"1f3b0"},{"name":"small_airplane","image":"1f6e9.png","id":"1f6e9"},{"name":"small_blue_diamond","image":"1f539.png","id":"1f539"},{"name":"small_orange_diamond","image":"1f538.png","id":"1f538"},{"name":"small_red_triangle","image":"1f53a.png","id":"1f53a"},{"name":"small_red_triangle_down","image":"1f53b.png","id":"1f53b"},{"name":"smile","image":"1f604.png","id":"1f604"},{"name":"smile_cat","image":"1f638.png","id":"1f638"},{"name":"smiley","image":"1f603.png","id":"1f603"},{"name":"smiley_cat","image":"1f63a.png","id":"1f63a"},{"name":"smiling_imp","image":"1f608.png","id":"1f608"},{"name":"smirk","image":"1f60f.png","id":"1f60f"},{"name":"smirk_cat","image":"1f63c.png","id":"1f63c"},{"name":"smoking","image":"1f6ac.png","id":"1f6ac"},{"name":"snail","image":"1f40c.png","id":"1f40c"},{"name":"snake","image":"1f40d.png","id":"1f40d"},{"name":"snow_capped_mountain","image":"1f3d4.png","id":"1f3d4"},{"name":"snow_cloud","image":"1f328.png","id":"1f328"},{"name":"snowboarder","image":"1f3c2.png","id":"1f3c2"},{"name":"snowflake","image":"2744.png","id":"2744"},{"name":"snowman","image":"2603.png","id":"2603"},{"name":"snowman_without_snow","image":"26c4.png","id":"26c4"},{"name":"sob","image":"1f62d.png","id":"1f62d"},{"name":"soccer","image":"26bd.png","id":"26bd"},{"name":"soon","image":"1f51c.png","id":"1f51c"},{"name":"sos","image":"1f198.png","id":"1f198"},{"name":"sound","image":"1f509.png","id":"1f509"},{"name":"space_invader","image":"1f47e.png","id":"1f47e"},{"name":"spades","image":"2660.png","id":"2660"},{"name":"spaghetti","image":"1f35d.png","id":"1f35d"},{"name":"sparkle","image":"2747.png","id":"2747"},{"name":"sparkler","image":"1f387.png","id":"1f387"},{"name":"sparkles","image":"2728.png","id":"2728"},{"name":"sparkling_heart","image":"1f496.png","id":"1f496"},{"name":"speak_no_evil","image":"1f64a.png","id":"1f64a"},{"name":"speaker","image":"1f508.png","id":"1f508"},{"name":"speaking_head_in_silhouette","image":"1f5e3.png","id":"1f5e3"},{"name":"speech_balloon","image":"1f4ac.png","id":"1f4ac"},{"name":"speedboat","image":"1f6a4.png","id":"1f6a4"},{"name":"spider","image":"1f577.png","id":"1f577"},{"name":"spider_web","image":"1f578.png","id":"1f578"},{"name":"spiral_calendar_pad","image":"1f5d3.png","id":"1f5d3"},{"name":"spiral_note_pad","image":"1f5d2.png","id":"1f5d2"},{"name":"spock-hand","image":"1f596.png","id":"1f596"},{"name":"sports_medal","image":"1f3c5.png","id":"1f3c5"},{"name":"stadium","image":"1f3df.png","id":"1f3df"},{"name":"star","image":"2b50.png","id":"2b50"},{"name":"star2","image":"1f31f.png","id":"1f31f"},{"name":"star_and_crescent","image":"262a.png","id":"262a"},{"name":"star_of_david","image":"2721.png","id":"2721"},{"name":"stars","image":"1f320.png","id":"1f320"},{"name":"station","image":"1f689.png","id":"1f689"},{"name":"statue_of_liberty","image":"1f5fd.png","id":"1f5fd"},{"name":"steam_locomotive","image":"1f682.png","id":"1f682"},{"name":"stew","image":"1f372.png","id":"1f372"},{"name":"stopwatch","image":"23f1.png","id":"23f1"},{"name":"straight_ruler","image":"1f4cf.png","id":"1f4cf"},{"name":"strawberry","image":"1f353.png","id":"1f353"},{"name":"stuck_out_tongue","image":"1f61b.png","id":"1f61b"},{"name":"stuck_out_tongue_closed_eyes","image":"1f61d.png","id":"1f61d"},{"name":"stuck_out_tongue_winking_eye","image":"1f61c.png","id":"1f61c"},{"name":"studio_microphone","image":"1f399.png","id":"1f399"},{"name":"sun_with_face","image":"1f31e.png","id":"1f31e"},{"name":"sunflower","image":"1f33b.png","id":"1f33b"},{"name":"sunglasses","image":"1f60e.png","id":"1f60e"},{"name":"sunny","image":"2600.png","id":"2600"},{"name":"sunrise","image":"1f305.png","id":"1f305"},{"name":"sunrise_over_mountains","image":"1f304.png","id":"1f304"},{"name":"surfer","image":"1f3c4.png","id":"1f3c4"},{"name":"sushi","image":"1f363.png","id":"1f363"},{"name":"suspension_railway","image":"1f69f.png","id":"1f69f"},{"name":"sweat","image":"1f613.png","id":"1f613"},{"name":"sweat_drops","image":"1f4a6.png","id":"1f4a6"},{"name":"sweat_smile","image":"1f605.png","id":"1f605"},{"name":"sweet_potato","image":"1f360.png","id":"1f360"},{"name":"swimmer","image":"1f3ca.png","id":"1f3ca"},{"name":"symbols","image":"1f523.png","id":"1f523"},{"name":"synagogue","image":"1f54d.png","id":"1f54d"},{"name":"syringe","image":"1f489.png","id":"1f489"},{"name":"table_tennis_paddle_and_ball","image":"1f3d3.png","id":"1f3d3"},{"name":"taco","image":"1f32e.png","id":"1f32e"},{"name":"tada","image":"1f389.png","id":"1f389"},{"name":"tanabata_tree","image":"1f38b.png","id":"1f38b"},{"name":"tangerine","image":"1f34a.png","id":"1f34a"},{"name":"taurus","image":"2649.png","id":"2649"},{"name":"taxi","image":"1f695.png","id":"1f695"},{"name":"tea","image":"1f375.png","id":"1f375"},{"name":"telephone_receiver","image":"1f4de.png","id":"1f4de"},{"name":"telescope","image":"1f52d.png","id":"1f52d"},{"name":"tennis","image":"1f3be.png","id":"1f3be"},{"name":"tent","image":"26fa.png","id":"26fa"},{"name":"the_horns","image":"1f918.png","id":"1f918"},{"name":"thermometer","image":"1f321.png","id":"1f321"},{"name":"thinking_face","image":"1f914.png","id":"1f914"},{"name":"thought_balloon","image":"1f4ad.png","id":"1f4ad"},{"name":"three","image":"0033-20e3.png","id":"0033-20e3"},{"name":"three_button_mouse","image":"1f5b1.png","id":"1f5b1"},{"name":"thunder_cloud_and_rain","image":"26c8.png","id":"26c8"},{"name":"ticket","image":"1f3ab.png","id":"1f3ab"},{"name":"tiger","image":"1f42f.png","id":"1f42f"},{"name":"tiger2","image":"1f405.png","id":"1f405"},{"name":"timer_clock","image":"23f2.png","id":"23f2"},{"name":"tired_face","image":"1f62b.png","id":"1f62b"},{"name":"toilet","image":"1f6bd.png","id":"1f6bd"},{"name":"tokyo_tower","image":"1f5fc.png","id":"1f5fc"},{"name":"tomato","image":"1f345.png","id":"1f345"},{"name":"tongue","image":"1f445.png","id":"1f445"},{"name":"top","image":"1f51d.png","id":"1f51d"},{"name":"tophat","image":"1f3a9.png","id":"1f3a9"},{"name":"tornado","image":"1f32a.png","id":"1f32a"},{"name":"trackball","image":"1f5b2.png","id":"1f5b2"},{"name":"tractor","image":"1f69c.png","id":"1f69c"},{"name":"traffic_light","image":"1f6a5.png","id":"1f6a5"},{"name":"train","image":"1f68b.png","id":"1f68b"},{"name":"train2","image":"1f686.png","id":"1f686"},{"name":"tram","image":"1f68a.png","id":"1f68a"},{"name":"triangular_flag_on_post","image":"1f6a9.png","id":"1f6a9"},{"name":"triangular_ruler","image":"1f4d0.png","id":"1f4d0"},{"name":"trident","image":"1f531.png","id":"1f531"},{"name":"triumph","image":"1f624.png","id":"1f624"},{"name":"trolleybus","image":"1f68e.png","id":"1f68e"},{"name":"trophy","image":"1f3c6.png","id":"1f3c6"},{"name":"tropical_drink","image":"1f379.png","id":"1f379"},{"name":"tropical_fish","image":"1f420.png","id":"1f420"},{"name":"truck","image":"1f69a.png","id":"1f69a"},{"name":"trumpet","image":"1f3ba.png","id":"1f3ba"},{"name":"tulip","image":"1f337.png","id":"1f337"},{"name":"turkey","image":"1f983.png","id":"1f983"},{"name":"turtle","image":"1f422.png","id":"1f422"},{"name":"tv","image":"1f4fa.png","id":"1f4fa"},{"name":"twisted_rightwards_arrows","image":"1f500.png","id":"1f500"},{"name":"two","image":"0032-20e3.png","id":"0032-20e3"},{"name":"two_hearts","image":"1f495.png","id":"1f495"},{"name":"two_men_holding_hands","image":"1f46c.png","id":"1f46c"},{"name":"two_women_holding_hands","image":"1f46d.png","id":"1f46d"},{"name":"u5272","image":"1f239.png","id":"1f239"},{"name":"u5408","image":"1f234.png","id":"1f234"},{"name":"u55b6","image":"1f23a.png","id":"1f23a"},{"name":"u6307","image":"1f22f.png","id":"1f22f"},{"name":"u6708","image":"1f237.png","id":"1f237"},{"name":"u6709","image":"1f236.png","id":"1f236"},{"name":"u6e80","image":"1f235.png","id":"1f235"},{"name":"u7121","image":"1f21a.png","id":"1f21a"},{"name":"u7533","image":"1f238.png","id":"1f238"},{"name":"u7981","image":"1f232.png","id":"1f232"},{"name":"u7a7a","image":"1f233.png","id":"1f233"},{"name":"umbrella","image":"2602.png","id":"2602"},{"name":"umbrella_on_ground","image":"26f1.png","id":"26f1"},{"name":"umbrella_with_rain_drops","image":"2614.png","id":"2614"},{"name":"unamused","image":"1f612.png","id":"1f612"},{"name":"underage","image":"1f51e.png","id":"1f51e"},{"name":"unicorn_face","image":"1f984.png","id":"1f984"},{"name":"unlock","image":"1f513.png","id":"1f513"},{"name":"up","image":"1f199.png","id":"1f199"},{"name":"upside_down_face","image":"1f643.png","id":"1f643"},{"name":"v","image":"270c.png","id":"270c"},{"name":"vertical_traffic_light","image":"1f6a6.png","id":"1f6a6"},{"name":"vhs","image":"1f4fc.png","id":"1f4fc"},{"name":"vibration_mode","image":"1f4f3.png","id":"1f4f3"},{"name":"video_camera","image":"1f4f9.png","id":"1f4f9"},{"name":"video_game","image":"1f3ae.png","id":"1f3ae"},{"name":"violin","image":"1f3bb.png","id":"1f3bb"},{"name":"virgo","image":"264d.png","id":"264d"},{"name":"volcano","image":"1f30b.png","id":"1f30b"},{"name":"volleyball","image":"1f3d0.png","id":"1f3d0"},{"name":"vs","image":"1f19a.png","id":"1f19a"},{"name":"walking","image":"1f6b6.png","id":"1f6b6"},{"name":"waning_crescent_moon","image":"1f318.png","id":"1f318"},{"name":"waning_gibbous_moon","image":"1f316.png","id":"1f316"},{"name":"warning","image":"26a0.png","id":"26a0"},{"name":"wastebasket","image":"1f5d1.png","id":"1f5d1"},{"name":"watch","image":"231a.png","id":"231a"},{"name":"water_buffalo","image":"1f403.png","id":"1f403"},{"name":"watermelon","image":"1f349.png","id":"1f349"},{"name":"wave","image":"1f44b.png","id":"1f44b"},{"name":"waving_black_flag","image":"1f3f4.png","id":"1f3f4"},{"name":"waving_white_flag","image":"1f3f3.png","id":"1f3f3"},{"name":"wavy_dash","image":"3030.png","id":"3030"},{"name":"waxing_crescent_moon","image":"1f312.png","id":"1f312"},{"name":"wc","image":"1f6be.png","id":"1f6be"},{"name":"weary","image":"1f629.png","id":"1f629"},{"name":"wedding","image":"1f492.png","id":"1f492"},{"name":"weight_lifter","image":"1f3cb.png","id":"1f3cb"},{"name":"whale","image":"1f433.png","id":"1f433"},{"name":"whale2","image":"1f40b.png","id":"1f40b"},{"name":"wheel_of_dharma","image":"2638.png","id":"2638"},{"name":"wheelchair","image":"267f.png","id":"267f"},{"name":"white_check_mark","image":"2705.png","id":"2705"},{"name":"white_circle","image":"26aa.png","id":"26aa"},{"name":"white_flower","image":"1f4ae.png","id":"1f4ae"},{"name":"white_frowning_face","image":"2639.png","id":"2639"},{"name":"white_large_square","image":"2b1c.png","id":"2b1c"},{"name":"white_medium_small_square","image":"25fd.png","id":"25fd"},{"name":"white_medium_square","image":"25fb.png","id":"25fb"},{"name":"white_small_square","image":"25ab.png","id":"25ab"},{"name":"white_square_button","image":"1f533.png","id":"1f533"},{"name":"wind_blowing_face","image":"1f32c.png","id":"1f32c"},{"name":"wind_chime","image":"1f390.png","id":"1f390"},{"name":"wine_glass","image":"1f377.png","id":"1f377"},{"name":"wink","image":"1f609.png","id":"1f609"},{"name":"wolf","image":"1f43a.png","id":"1f43a"},{"name":"woman","image":"1f469.png","id":"1f469"},{"name":"woman-heart-woman","image":"1f469-200d-2764-fe0f-200d-1f469.png","id":"1f469-200d-2764-fe0f-200d-1f469"},{"name":"woman-kiss-woman","image":"1f469-200d-2764-fe0f-200d-1f48b-200d-1f469.png","id":"1f469-200d-2764-fe0f-200d-1f48b-200d-1f469"},{"name":"woman-woman-boy","image":"1f469-200d-1f469-200d-1f466.png","id":"1f469-200d-1f469-200d-1f466"},{"name":"woman-woman-boy-boy","image":"1f469-200d-1f469-200d-1f466-200d-1f466.png","id":"1f469-200d-1f469-200d-1f466-200d-1f466"},{"name":"woman-woman-girl","image":"1f469-200d-1f469-200d-1f467.png","id":"1f469-200d-1f469-200d-1f467"},{"name":"woman-woman-girl-boy","image":"1f469-200d-1f469-200d-1f467-200d-1f466.png","id":"1f469-200d-1f469-200d-1f467-200d-1f466"},{"name":"woman-woman-girl-girl","image":"1f469-200d-1f469-200d-1f467-200d-1f467.png","id":"1f469-200d-1f469-200d-1f467-200d-1f467"},{"name":"womans_clothes","image":"1f45a.png","id":"1f45a"},{"name":"womans_hat","image":"1f452.png","id":"1f452"},{"name":"womens","image":"1f6ba.png","id":"1f6ba"},{"name":"world_map","image":"1f5fa.png","id":"1f5fa"},{"name":"worried","image":"1f61f.png","id":"1f61f"},{"name":"wrench","image":"1f527.png","id":"1f527"},{"name":"writing_hand","image":"270d.png","id":"270d"},{"name":"x","image":"274c.png","id":"274c"},{"name":"yellow_heart","image":"1f49b.png","id":"1f49b"},{"name":"yen","image":"1f4b4.png","id":"1f4b4"},{"name":"yin_yang","image":"262f.png","id":"262f"},{"name":"yum","image":"1f60b.png","id":"1f60b"},{"name":"zap","image":"26a1.png","id":"26a1"},{"name":"zero","image":"0030-20e3.png","id":"0030-20e3"},{"name":"zipper_mouth_face","image":"1f910.png","id":"1f910"},{"name":"zzz","image":"1f4a4.png","id":"1f4a4"}] \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js index 00ad4fbd..f141184e 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,4 +1,5 @@ var gulp = require("gulp"), + fs = require('fs'), imagemin = require("gulp-imagemin"), jade = require("gulp-jade"), coffee = require("gulp-coffee"), @@ -51,7 +52,6 @@ paths.dist = "dist/"; paths.distVersion = paths.dist + version + "/"; paths.tmp = "tmp/"; paths.extras = "extras/"; -paths.vendor = "vendor/"; paths.modules = "node_modules/"; paths.jade = [ @@ -68,10 +68,14 @@ paths.htmlPartials = [ paths.images = paths.app + "images/**/*"; paths.svg = paths.app + "svg/**/*"; paths.css_vendor = [ - paths.vendor + "intro.js/introjs.css", - paths.vendor + "dragula.js/dist/dragula.css", + paths.modules + "intro.js/introjs.css", + paths.modules + "dragula/dist/dragula.css", paths.modules + "awesomplete/awesomplete.css", - paths.app + "styles/vendor/*.css" + paths.app + "styles/vendor/*.css", + paths.modules + "medium-editor/dist/css/medium-editor.css", + paths.modules + "medium-editor/dist/css/themes/default.css", + paths.modules + "highlight.js/styles/default.css", + paths.modules + "prismjs/themes/prism-okaidia.css" ]; paths.locales = paths.app + "locales/**/*.json"; paths.modulesLocales = paths.app + "modules/**/locales/*.json"; @@ -149,45 +153,58 @@ paths.coffee_order = [ ]; paths.libs = [ - paths.vendor + "bluebird/js/browser/bluebird.js", - paths.vendor + "jquery/dist/jquery.js", - paths.vendor + "lodash/lodash.js", - paths.vendor + "emoticons/lib/emoticons.js", - paths.vendor + "messageformat/messageformat.js", - paths.vendor + "angular/angular.js", - paths.vendor + "angular-route/angular-route.js", - paths.vendor + "angular-sanitize/angular-sanitize.js", - paths.vendor + "angular-animate/angular-animate.js", - paths.vendor + "angular-aria/angular-aria.js", - paths.vendor + "angular-translate/angular-translate.js", - paths.vendor + "angular-translate-loader-partial/angular-translate-loader-partial.js", - paths.vendor + "angular-translate-loader-static-files/angular-translate-loader-static-files.js", - paths.vendor + "angular-translate-interpolation-messageformat/angular-translate-interpolation-messageformat.js", - paths.vendor + "moment/moment.js", - paths.vendor + "checksley/checksley.js", - paths.vendor + "pikaday/pikaday.js", - paths.vendor + "jquery-flot/jquery.flot.js", - paths.vendor + "jquery-flot/jquery.flot.pie.js", - paths.vendor + "jquery-flot/jquery.flot.time.js", - paths.vendor + "flot-axislabels/jquery.flot.axislabels.js", - paths.vendor + "flot.tooltip/js/jquery.flot.tooltip.js", - paths.vendor + "jquery-textcomplete/dist/jquery.textcomplete.js", - paths.vendor + "markitup-1x/markitup/jquery.markitup.js", - paths.vendor + "raven-js/dist/raven.js", - paths.vendor + "l.js/l.js", - paths.vendor + "messageformat/locale/*.js", - paths.vendor + "ng-infinite-scroll-npm-is-better-than-bower/build/ng-infinite-scroll.js", - paths.vendor + "immutable/dist/immutable.js", - paths.vendor + "intro.js/intro.js", - paths.vendor + "dragula.js/dist/dragula.js", + paths.modules + "bluebird/js/browser/bluebird.js", + paths.modules + "jquery/dist/jquery.js", + paths.modules + "lodash/lodash.js", + paths.modules + "messageformat/messageformat.js", + paths.modules + "angular/angular.js", + paths.modules + "angular-route/angular-route.js", + paths.modules + "angular-sanitize/angular-sanitize.js", + paths.modules + "angular-animate/angular-animate.js", + paths.modules + "angular-aria/angular-aria.js", + paths.modules + "angular-translate/dist/angular-translate.js", + paths.modules + "angular-translate-loader-partial/angular-translate-loader-partial.js", + paths.modules + "angular-translate-loader-static-files/angular-translate-loader-static-files.js", + paths.modules + "angular-translate-interpolation-messageformat/angular-translate-interpolation-messageformat.js", + paths.modules + "moment/moment.js", + paths.modules + "checksley/checksley.js", + paths.modules + "pikaday/pikaday.js", + paths.modules + "Flot/jquery.flot.js", + paths.modules + "Flot/jquery.flot.pie.js", + paths.modules + "Flot/jquery.flot.time.js", + paths.modules + "flot-axislabels/jquery.flot.axislabels.js", + paths.modules + "jquery.flot.tooltip/js/jquery.flot.tooltip.js", + paths.modules + "raven-js/dist/raven.js", + paths.modules + "l.js/l.js", + paths.modules + "ng-infinite-scroll/build/ng-infinite-scroll.js", + paths.modules + "immutable/dist/immutable.js", + paths.modules + "intro.js/intro.js", + paths.modules + "dragula/dist/dragula.js", + paths.modules + "awesomplete/awesomplete.js", + paths.modules + "medium-editor/dist/js/medium-editor.js", + paths.modules + "to-markdown/dist/to-markdown.js", + paths.modules + "markdown-it/dist/markdown-it.js", + paths.modules + "highlight.js/lib/highlight.js", + paths.modules + "prismjs/prism.js", + paths.modules + "medium-editor-autolist/dist/autolist.js", paths.app + "js/dom-autoscroller.js", paths.app + "js/dragula-drag-multiple.js", paths.app + "js/tg-repeat.js", paths.app + "js/sha1-custom.js", paths.app + "js/murmurhash3_gc.js", - paths.modules + "awesomplete/awesomplete.js" + paths.app + "js/medium-mention.js" ]; +paths.libs.forEach(function(file) { + try { + // Query the entry + stats = fs.lstatSync(file); + } + catch (e) { + console.log(file); + } +}); + var isDeploy = argv["_"].indexOf("deploy") !== -1; /* @@ -246,7 +263,6 @@ gulp.task("jade-watch", function(cb) { gulp.task("scss-lint", [], function() { var ignore = [ "!" + paths.app + "/styles/shame/**/*.scss", - "!" + paths.app + "/styles/components/markitup.scss" ]; var fail = process.argv.indexOf("--fail") !== -1; @@ -254,7 +270,7 @@ gulp.task("scss-lint", [], function() { var sassFiles = paths.sass.concat(themes.current.customScss, ignore); return gulp.src(sassFiles) - .pipe(gulpif(!isDeploy, cache(scsslint({endless: true, sync: true, config: "scsslint.yml"}), { + .pipe(gulpif(!isDeploy, cache(scsslint({endless: true, sync: true, config: ".scss-lint.yml"}), { success: function(scsslintFile) { return scsslintFile.scsslint.success; }, @@ -388,6 +404,76 @@ gulp.task("styles-dependencies", function(cb) { # JS Related tasks ############################################################################## */ + +gulp.task("prism-languages", function(cb) { + var files = fs.readdirSync(paths.modules + "prismjs/components"); + + files = files.filter(function(file) { + return file.indexOf('.min.js') != -1; + }); + + files = files.map(function(file) { + return { + file: file, + name: /prism-(.*)\.min\.js/g.exec(file)[1] + }; + }); + + var filesStr = JSON.stringify(files); + + fs.writeFileSync(__dirname + '/prism-languages.json', filesStr, { + flag: 'w+' + }); + + cb(); +}); + +gulp.task("emoji", function(cb) { + // don't add to package.json + var Jimp = require("jimp"); + + //var emojiFolder = ""; + var emojiPath = "../emoji-data/"; + + var emojis = require(emojiPath + "emoji.json"); + + emojis = emojis.filter(function(emoji) { + return emoji.has_img_twitter; + }); + + emojis = emojis.map(function(emoji) { + return { + name: emoji.short_name, + image: emoji.image, + id: emoji.unified.toLowerCase() + }; + }); + + emojis = emojis.sort(function(a, b) { + if(a.name < b.name) return -1; + if(a.name > b.name) return 1; + return 0; + }); + + emojis.forEach(function(emoji) { + Jimp.read(emojiPath + "img-twitter-64/" + emoji.image, function (err, lenna) { + if (err) throw err; + + lenna + .resize(16, 16) + .quality(100) + .write(__dirname + '/emojis/' + emoji.image); + }); + }); + + var emojisStr = JSON.stringify(emojis); + fs.writeFileSync(__dirname + '/emojis/emojis-data.json', emojisStr, { + flag: 'w+' + }); + + cb(); +}); + gulp.task("conf", function() { return gulp.src(["conf/conf.example.json"]) .pipe(gulp.dest(paths.dist)); @@ -460,7 +546,7 @@ gulp.task("coffee", function() { }); gulp.task("moment-locales", function() { - return gulp.src(paths.vendor + "moment/locale/*") + return gulp.src(paths.modules + "moment/locale/*") .pipe(gulpif(isDeploy, uglify())) .pipe(gulp.dest(paths.distVersion + "locales/moment-locales/")); }); @@ -528,6 +614,22 @@ gulp.task("copy-images", function() { .pipe(gulp.dest(paths.distVersion + "/images/")); }); +gulp.task("copy-emojis", function() { + return gulp.src([__dirname + "/emojis/*"]) + .pipe(gulp.dest(paths.distVersion + "/emojis/")); +}); + +gulp.task("copy-prism", ["prism-languages"], function() { + var prismLanguages = require(__dirname + '/prism-languages.json'); + + prismLanguages = prismLanguages.map(function(it) { + return paths.modules + "prismjs/components/" + it.file; + }); + + return gulp.src(prismLanguages.concat(__dirname + '/prism-languages.json')) + .pipe(gulp.dest(paths.distVersion + "/prism/")); +}); + gulp.task("copy-theme-images", function() { return gulp.src(themes.current.path + "/images/**/*") .pipe(gulpif(isDeploy, imagemin({progressive: true}))) @@ -543,6 +645,8 @@ gulp.task("copy", [ "copy-fonts", "copy-theme-fonts", "copy-images", + "copy-emojis", + "copy-prism", "copy-theme-images", "copy-svg", "copy-theme-svg", @@ -578,11 +682,13 @@ gulp.task("express", function() { app.use("/" + version + "/js", express.static(__dirname + "/dist/" + version + "/js")); app.use("/" + version + "/styles", express.static(__dirname + "/dist/" + version + "/styles")); app.use("/" + version + "/images", express.static(__dirname + "/dist/" + version + "/images")); + app.use("/" + version + "/emojis", express.static(__dirname + "/dist/" + version + "/emojis")); app.use("/" + version + "/svg", express.static(__dirname + "/dist/" + version + "/svg")); app.use("/" + version + "/partials", express.static(__dirname + "/dist/" + version + "/partials")); app.use("/" + version + "/fonts", express.static(__dirname + "/dist/" + version + "/fonts")); app.use("/" + version + "/locales", express.static(__dirname + "/dist/" + version + "/locales")); app.use("/" + version + "/maps", express.static(__dirname + "/dist/" + version + "/maps")); + app.use("/" + version + "/prism", express.static(__dirname + "/dist/" + version + "/prism")); app.use("/plugins", express.static(__dirname + "/dist/plugins")); app.use("/conf.json", express.static(__dirname + "/dist/conf.json")); app.use(require('connect-livereload')({ diff --git a/karma.conf.js b/karma.conf.js index 4e24c1ec..edde0e8f 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -19,11 +19,7 @@ module.exports = function(config) { 'karma.app.conf.js', 'dist/**/js/libs.js', 'node_modules/angular-mocks/angular-mocks.js', - 'vendor/bluebird/js/browser/bluebird.js', 'node_modules/chai-jquery/chai-jquery.js', - 'node_modules/chai-jquery/chai-jquery.js', - 'vendor/lodash/dist/lodash.js', - 'vendor/underscore.string/lib/underscore.string.js', 'test-utils.js', 'dist/**/js/app.js', 'dist/**/js/templates.js', diff --git a/locales.js b/locales.js index 76cec254..4357803d 100644 --- a/locales.js +++ b/locales.js @@ -1,4 +1,4 @@ -var glob = require('glob') +var glob = require('glob'); var inquirer = require('inquirer'); var fs = require('fs'); var _ = require('lodash'); @@ -28,13 +28,14 @@ inquirer.prompt([question], function( answer ) { if (answer.command === 'find-duplicates') findDuplicates(); }); +findDuplicates(); + function replaceKeys() { question() .then(searchKey) .then(printFiles) .then(confirm) - .then(replace) - + .then(replace); function question() { return new Promise(function (resolve, reject) { @@ -120,7 +121,8 @@ function replaceKeys() { function findDuplicates() { - glob(app + 'locales/*.json', {}, function (er, files) { + glob(app + 'locales/taiga/*.json', {}, function (er, files) { + console.log(files); files.forEach(duplicates); }); diff --git a/package.json b/package.json index 2849caf4..a0ccf7d2 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ }, "devDependencies": { "angular-mocks": "1.5.5", - "babel-cli": "^6.6.5", + "babel-cli": "^6.23.0", "babel-polyfill": "^6.7.4", "babel-preset-es2015": "^6.6.0", "babel-preset-stage-0": "^6.5.0", @@ -73,7 +73,7 @@ "gulp-util": "^3.0.7", "gulp-wrap": "^0.12.0", "image-size": "^0.5.0", - "inquirer": "^1.0.2", + "inquirer": "^3.0.1", "jade": "^1.11.0", "karma": "^0.13.10", "karma-chai-plugins": "^0.7.0", @@ -99,7 +99,42 @@ "scss-lint" ], "dependencies": { + "Flot": "git+https://github.com/flot/flot.git", + "angular": "1.5.5", + "angular-animate": "1.5.5", + "angular-aria": "1.5.5", + "angular-route": "1.5.5", + "angular-sanitize": "1.5.5", + "angular-translate": "2.10.0", + "angular-translate-interpolation-messageformat": "2.10.0", + "angular-translate-loader-partial": "2.10.0", + "angular-translate-loader-static-files": "2.10.0", "awesomplete": "^1.0.0", - "dom-autoscroller": "^1.3.1" + "bluebird": "^3.4.6", + "bourbon": "git+https://github.com/thoughtbot/bourbon.git", + "checksley": "git+https://github.com/jespino/checksley-bower.git", + "dom-autoscroller": "^1.3.1", + "dragula": "^3.7.2", + "flot-axislabels": "git+https://git@github.com/juanfran/flot-axislabels.git", + "highlight.js": "^9.7.0", + "immutable": "^3.8.1", + "intro.js": "^2.3.0", + "jquery": "^2.2.3", + "jquery.flot.tooltip": "git+https://git@github.com/krzysu/flot.tooltip.git", + "l.js": "git+https://git@github.com/juanfran/l.js.git", + "lodash": "^4.16.4", + "markdown-it": "^8.0.1", + "markdown-it-task-lists": "^1.4.1", + "medium-editor": "^5.22.2", + "medium-editor-autolist": "git+https://github.com/gruberro/medium-editor-autolist.git#add-package-json", + "medium-editor-tc-mention": "^2.2.4", + "messageformat": "^1.0.2", + "moment": "^2.15.1", + "ng-infinite-scroll": "^1.3.0", + "pikaday": "^1.4.0", + "prismjs": "^1.6.0", + "raven-js": "^3.7.0", + "showdown": "^1.4.3", + "to-markdown": "^3.0.1" } } diff --git a/prism-languages.json b/prism-languages.json new file mode 100644 index 00000000..6d79b676 --- /dev/null +++ b/prism-languages.json @@ -0,0 +1 @@ +[{"file":"prism-abap.min.js","name":"abap"},{"file":"prism-actionscript.min.js","name":"actionscript"},{"file":"prism-ada.min.js","name":"ada"},{"file":"prism-apacheconf.min.js","name":"apacheconf"},{"file":"prism-apl.min.js","name":"apl"},{"file":"prism-applescript.min.js","name":"applescript"},{"file":"prism-asciidoc.min.js","name":"asciidoc"},{"file":"prism-aspnet.min.js","name":"aspnet"},{"file":"prism-autohotkey.min.js","name":"autohotkey"},{"file":"prism-autoit.min.js","name":"autoit"},{"file":"prism-bash.min.js","name":"bash"},{"file":"prism-basic.min.js","name":"basic"},{"file":"prism-batch.min.js","name":"batch"},{"file":"prism-bison.min.js","name":"bison"},{"file":"prism-brainfuck.min.js","name":"brainfuck"},{"file":"prism-bro.min.js","name":"bro"},{"file":"prism-c.min.js","name":"c"},{"file":"prism-clike.min.js","name":"clike"},{"file":"prism-coffeescript.min.js","name":"coffeescript"},{"file":"prism-core.min.js","name":"core"},{"file":"prism-cpp.min.js","name":"cpp"},{"file":"prism-crystal.min.js","name":"crystal"},{"file":"prism-csharp.min.js","name":"csharp"},{"file":"prism-css-extras.min.js","name":"css-extras"},{"file":"prism-css.min.js","name":"css"},{"file":"prism-d.min.js","name":"d"},{"file":"prism-dart.min.js","name":"dart"},{"file":"prism-diff.min.js","name":"diff"},{"file":"prism-docker.min.js","name":"docker"},{"file":"prism-eiffel.min.js","name":"eiffel"},{"file":"prism-elixir.min.js","name":"elixir"},{"file":"prism-erlang.min.js","name":"erlang"},{"file":"prism-fortran.min.js","name":"fortran"},{"file":"prism-fsharp.min.js","name":"fsharp"},{"file":"prism-gherkin.min.js","name":"gherkin"},{"file":"prism-git.min.js","name":"git"},{"file":"prism-glsl.min.js","name":"glsl"},{"file":"prism-go.min.js","name":"go"},{"file":"prism-graphql.min.js","name":"graphql"},{"file":"prism-groovy.min.js","name":"groovy"},{"file":"prism-haml.min.js","name":"haml"},{"file":"prism-handlebars.min.js","name":"handlebars"},{"file":"prism-haskell.min.js","name":"haskell"},{"file":"prism-haxe.min.js","name":"haxe"},{"file":"prism-http.min.js","name":"http"},{"file":"prism-icon.min.js","name":"icon"},{"file":"prism-inform7.min.js","name":"inform7"},{"file":"prism-ini.min.js","name":"ini"},{"file":"prism-j.min.js","name":"j"},{"file":"prism-jade.min.js","name":"jade"},{"file":"prism-java.min.js","name":"java"},{"file":"prism-javascript.min.js","name":"javascript"},{"file":"prism-jolie.min.js","name":"jolie"},{"file":"prism-json.min.js","name":"json"},{"file":"prism-jsx.min.js","name":"jsx"},{"file":"prism-julia.min.js","name":"julia"},{"file":"prism-keyman.min.js","name":"keyman"},{"file":"prism-kotlin.min.js","name":"kotlin"},{"file":"prism-latex.min.js","name":"latex"},{"file":"prism-less.min.js","name":"less"},{"file":"prism-livescript.min.js","name":"livescript"},{"file":"prism-lolcode.min.js","name":"lolcode"},{"file":"prism-lua.min.js","name":"lua"},{"file":"prism-makefile.min.js","name":"makefile"},{"file":"prism-markdown.min.js","name":"markdown"},{"file":"prism-markup.min.js","name":"markup"},{"file":"prism-matlab.min.js","name":"matlab"},{"file":"prism-mel.min.js","name":"mel"},{"file":"prism-mizar.min.js","name":"mizar"},{"file":"prism-monkey.min.js","name":"monkey"},{"file":"prism-nasm.min.js","name":"nasm"},{"file":"prism-nginx.min.js","name":"nginx"},{"file":"prism-nim.min.js","name":"nim"},{"file":"prism-nix.min.js","name":"nix"},{"file":"prism-nsis.min.js","name":"nsis"},{"file":"prism-objectivec.min.js","name":"objectivec"},{"file":"prism-ocaml.min.js","name":"ocaml"},{"file":"prism-oz.min.js","name":"oz"},{"file":"prism-parigp.min.js","name":"parigp"},{"file":"prism-parser.min.js","name":"parser"},{"file":"prism-pascal.min.js","name":"pascal"},{"file":"prism-perl.min.js","name":"perl"},{"file":"prism-php-extras.min.js","name":"php-extras"},{"file":"prism-php.min.js","name":"php"},{"file":"prism-powershell.min.js","name":"powershell"},{"file":"prism-processing.min.js","name":"processing"},{"file":"prism-prolog.min.js","name":"prolog"},{"file":"prism-properties.min.js","name":"properties"},{"file":"prism-protobuf.min.js","name":"protobuf"},{"file":"prism-puppet.min.js","name":"puppet"},{"file":"prism-pure.min.js","name":"pure"},{"file":"prism-python.min.js","name":"python"},{"file":"prism-q.min.js","name":"q"},{"file":"prism-qore.min.js","name":"qore"},{"file":"prism-r.min.js","name":"r"},{"file":"prism-reason.min.js","name":"reason"},{"file":"prism-rest.min.js","name":"rest"},{"file":"prism-rip.min.js","name":"rip"},{"file":"prism-roboconf.min.js","name":"roboconf"},{"file":"prism-ruby.min.js","name":"ruby"},{"file":"prism-rust.min.js","name":"rust"},{"file":"prism-sas.min.js","name":"sas"},{"file":"prism-sass.min.js","name":"sass"},{"file":"prism-scala.min.js","name":"scala"},{"file":"prism-scheme.min.js","name":"scheme"},{"file":"prism-scss.min.js","name":"scss"},{"file":"prism-smalltalk.min.js","name":"smalltalk"},{"file":"prism-smarty.min.js","name":"smarty"},{"file":"prism-sql.min.js","name":"sql"},{"file":"prism-stylus.min.js","name":"stylus"},{"file":"prism-swift.min.js","name":"swift"},{"file":"prism-tcl.min.js","name":"tcl"},{"file":"prism-textile.min.js","name":"textile"},{"file":"prism-twig.min.js","name":"twig"},{"file":"prism-typescript.min.js","name":"typescript"},{"file":"prism-verilog.min.js","name":"verilog"},{"file":"prism-vhdl.min.js","name":"vhdl"},{"file":"prism-vim.min.js","name":"vim"},{"file":"prism-wiki.min.js","name":"wiki"},{"file":"prism-xojo.min.js","name":"xojo"},{"file":"prism-yaml.min.js","name":"yaml"}] \ No newline at end of file diff --git a/scripts/add_licanse_to_coffee_files.py b/scripts/add_licanse_to_coffee_files.py index 4c8c2a55..8dc3fd40 100644 --- a/scripts/add_licanse_to_coffee_files.py +++ b/scripts/add_licanse_to_coffee_files.py @@ -1,7 +1,7 @@ import os, sys LICENSE = """### -# Copyright (C) 2014-2016 Taiga Agile LLC +# Copyright (C) 2014-2017 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as diff --git a/scripts/manage_translations.py b/scripts/manage_translations.py old mode 100644 new mode 100755 index b756efbd..92fb9ca6 --- a/scripts/manage_translations.py +++ b/scripts/manage_translations.py @@ -84,7 +84,7 @@ You need transifex-client, install it. 1. Install transifex-client, use - $ pip install --upgrade transifex-client==0.11.1.beta + $ pip install --upgrade transifex-client==0.12.2 2. Create ~/.transifexrc file: diff --git a/scripts/search-for-similar-strings.py b/scripts/search-for-similar-strings.py new file mode 100755 index 00000000..c02c4c37 --- /dev/null +++ b/scripts/search-for-similar-strings.py @@ -0,0 +1,62 @@ +import json +import os +import click +from difflib import SequenceMatcher + +ROOT_PATH = os.path.dirname(os.path.dirname(__file__)) +DEFAULT_LOCALE_PATH = os.path.join(ROOT_PATH, "app/locales/taiga/locale-en.json") + + +def keywords(key, value): + if key is not None and not isinstance(value, dict): + return [(".".join(key), value)] + + if key is not None and isinstance(value, dict): + kws = [] + for item_key in value.keys(): + kws += keywords(key+[item_key], value[item_key]) + return kws + + if key is None and isinstance(value, dict): + kws = [] + for item_key in value.keys(): + kws += keywords([item_key], value[item_key]) + return kws + + +@click.command() +@click.option('--threshold', default=1.0, help='Minimun similarity to show') +@click.option('--min-length', default=10, help='Minimun size of the string to show') +@click.option('--omit-identical', default=False, is_flag=True, help='Omit identical strings') +def verify_similarity(threshold, min_length, omit_identical): + locales = json.load(open(DEFAULT_LOCALE_PATH)) + all_keywords = keywords(None, locales) + already_shown_keys = set() + + for key1, value1 in all_keywords: + for key2, value2 in all_keywords: + if key1 == key2: + continue + if len(value1) < min_length and len(value2) < min_length: + continue + + similarity = SequenceMatcher(None, value1, value2).ratio() + if omit_identical and similarity == 1.0: + continue + + if similarity >= threshold: + if (key1, key2) not in already_shown_keys: + already_shown_keys.add((key1, key2)) + already_shown_keys.add((key2, key1)) + click.echo( + "The keys {} and {} has a similarity of {}\n - {}\n - {}".format( + key1, + key2, + similarity, + value1, + value2 + ) + ) + +if __name__ == "__main__": + verify_similarity() diff --git a/scripts/verify-locale-keys-usage.py b/scripts/verify-locale-keys-usage.py new file mode 100755 index 00000000..67379c64 --- /dev/null +++ b/scripts/verify-locale-keys-usage.py @@ -0,0 +1,69 @@ +import json +import os + +ROOT_PATH = os.path.dirname(os.path.dirname(__file__)) +DEFAULT_LOCALE_PATH = os.path.join(ROOT_PATH, "app/locales/taiga/locale-en.json") +WHITELIST = [ + 'ADMIN.PROJECT_VALUES_PRIORITIES.ACTION_ADD', + 'ADMIN.PROJECT_VALUES_SEVERITIES.ACTION_ADD', + 'ADMIN.PROJECT_VALUES_TYPES.ACTION_ADD', + 'HINTS.HINT1_TITLE', + 'HINTS.HINT1_TEXT', + 'HINTS.HINT2_TITLE', + 'HINTS.HINT2_TEXT', + 'HINTS.HINT3_TITLE', + 'HINTS.HINT3_TEXT', + 'HINTS.HINT4_TITLE', + 'HINTS.HINT4_TEXT', +] + + +def keywords(key, value): + if key is not None and not isinstance(value, dict): + return [".".join(key)] + + if key is not None and isinstance(value, dict): + kws = [] + for item_key in value.keys(): + kws += keywords(key+[item_key], value[item_key]) + return kws + + if key is None and isinstance(value, dict): + kws = [] + for item_key in value.keys(): + kws += keywords([item_key], value[item_key]) + return kws + + +def read_file(path): + with open(path) as fd: + return fd.read() + + +def check_keyword(keyword, files_text): + if keyword in WHITELIST: + return True + for text in files_text: + if text.find(keyword) != -1: + return True + return False + + +def verify_keywords_usage(): + locales = json.load(open(DEFAULT_LOCALE_PATH)) + + all_files = [] + for root, dirs, files in os.walk(os.path.join(ROOT_PATH, 'app')): + json_and_jade_files = list(filter(lambda x: x.endswith('.coffee') or x.endswith('.jade'), files)) + json_and_jade_files = map(lambda x: os.path.join(root, x), json_and_jade_files) + all_files += json_and_jade_files + + all_files_text = list(map(read_file, all_files)) + + for keyword in keywords(None, locales): + if not check_keyword(keyword, all_files_text): + print("Keyword unused: {}".format(keyword)) + + +if __name__ == "__main__": + verify_keywords_usage()