diff --git a/.babelrc b/.babelrc new file mode 100644 index 00000000..7b893c5f --- /dev/null +++ b/.babelrc @@ -0,0 +1 @@ +{ "presets": ["es2015", "stage-0"] } diff --git a/.gitignore b/.gitignore index 9fe650a7..ec0af232 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ tmp/ app/config/main.coffee scss-lint.log e2e/screenshots/ +app/modules/compile-modules/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 4adf2c47..930a76fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,22 @@ # Changelog # +## 2.0.0 Pulsatilla Patens (2016-04-04) + +### Features +- Ability to create url custom fields. (thanks to [@astagi](https://github.com/astagi)). +- Blocked projects support +- Moved from iconfont to SVG sprite icon system and redesign. +- Redesign 'Admin > Project > Modules' panel. +- Add badge to project owners +- Limit of user per project. +- Redesign of the create project wizard +- Transfer project ownership + +### Misc +- Lots of small and not so small bugfixes. + + ## 1.10.0 Dryas Octopetala (2016-01-30) ### Features diff --git a/README.md b/README.md index dc390dcf..14d6d7c0 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ Please read carefully [our license](https://github.com/taigaio/taiga-front/blob/ #### Bug reports, enhancements and support #### -If you **need help to setup Taiga**, want to **talk about some cool enhancemnt** or you have **some questions**, please write us to our [mailing list](http://groups.google.com/d/forum/taigaio). +If you **need help to setup Taiga**, want to **talk about some cool enhancement** or you have **some questions**, please write us to our [mailing list](http://groups.google.com/d/forum/taigaio). If you **find a bug** in Taiga you can always report it: @@ -127,7 +127,7 @@ Complete process for all OS at: http://sass-lang.com/install **Node + Bower + Gulp** -We recommend using [nvm](https://github.com/creationix/nvm) to manage diferent node versions +We recommend using [nvm](https://github.com/creationix/nvm) to manage different node versions ``` npm install -g gulp npm install -g bower diff --git a/app-loader/app-loader.coffee b/app-loader/app-loader.coffee index 310f6df5..6cbe2f03 100644 --- a/app-loader/app-loader.coffee +++ b/app-loader/app-loader.coffee @@ -53,7 +53,10 @@ loadPlugins = (plugins) -> promise = $.getJSON "/conf.json" promise.done (data) -> - window.taigaConfig = _.extend({}, window.taigaConfig, data) + window.taigaConfig = _.assign({}, window.taigaConfig, data) + +promise.fail () -> + console.error "Your conf.json file is not a valid json file, please review it." promise.always -> if window.taigaConfig.contribPlugins.length > 0 diff --git a/app/coffee/app.coffee b/app/coffee/app.coffee index 54ff9b5d..8d0b88de 100644 --- a/app/coffee/app.coffee +++ b/app/coffee/app.coffee @@ -111,6 +111,16 @@ configure = ($routeProvider, $locationProvider, $httpProvider, $provide, $tgEven } ) + + $routeProvider.when("/blocked-project/:pslug/", + { + templateUrl: "projects/project/blocked-project.html", + loader: true, + controller: "Project", + controllerAs: "vm" + } + ) + $routeProvider.when("/project/:pslug/", { templateUrl: "projects/project/project.html", @@ -323,6 +333,16 @@ configure = ($routeProvider, $locationProvider, $httpProvider, $provide, $tgEven $routeProvider.when("/project/:pslug/admin/contrib/:plugin", {templateUrl: "contrib/main.html"}) + # Transfer project + $routeProvider.when("/project/:pslug/transfer/:token", + { + templateUrl: "projects/transfer/transfer-page.html", + loader: true, + controller: "Project", + controllerAs: "vm" + } + ) + # User settings $routeProvider.when("/user-settings/user-profile", {templateUrl: "user/user-profile.html"}) @@ -335,6 +355,10 @@ configure = ($routeProvider, $locationProvider, $httpProvider, $provide, $tgEven $routeProvider.when("/cancel-account/:cancel_token", {templateUrl: "user/cancel-account.html"}) + # UserSettings - Contrib Plugins + $routeProvider.when("/user-settings/contrib/:plugin", + {templateUrl: "contrib/user-settings.html"}) + # User profile $routeProvider.when("/profile", { @@ -363,7 +387,8 @@ configure = ($routeProvider, $locationProvider, $httpProvider, $provide, $tgEven templateUrl: "auth/login.html", title: "LOGIN.PAGE_TITLE", description: "LOGIN.PAGE_DESCRIPTION", - disableHeader: true + disableHeader: true, + controller: "LoginPage", } ) $routeProvider.when("/register", @@ -510,15 +535,41 @@ configure = ($routeProvider, $locationProvider, $httpProvider, $provide, $tgEven $httpProvider.interceptors.push("versionCheckHttpIntercept") - window.checksley.updateValidators({ - linewidth: (val, width) -> - lines = taiga.nl2br(val).split("
") - valid = _.every lines, (line) -> - line.length < width + blockingIntercept = ($q, $routeParams, $location, $navUrls) -> + # API calls can return blocked elements and in that situation the user will be redirected + # to the blocked project page + # This can happens in two scenarios + # - An ok response containing a blocked_code in the data + # - An error reponse when updating/creating/deleting including a 451 error code + redirectToBlockedPage = -> + pslug = $routeParams.pslug + blockedUrl = $navUrls.resolve("blocked-project", {project: pslug}) + currentUrl = $location.url() + if currentUrl.indexOf(blockedUrl) == -1 + $location.replace().path(blockedUrl) + + responseOk = (response) -> + if response.data.blocked_code + redirectToBlockedPage() + + return response + + responseError = (response) -> + if response.status == 451 + redirectToBlockedPage() + + return $q.reject(response) + + return { + response: responseOk + responseError: responseError + } + + $provide.factory("blockingIntercept", ["$q", "$routeParams", "$location", "$tgNavUrls", blockingIntercept]) + + $httpProvider.interceptors.push("blockingIntercept") - return valid - }) $compileProvider.debugInfoEnabled(window.taigaConfig.debugInfo || false) @@ -577,6 +628,8 @@ i18nInit = (lang, $translate) -> maxcheck: $translate.instant("COMMON.FORM_ERRORS.MAX_CHECK") rangecheck: $translate.instant("COMMON.FORM_ERRORS.RANGE_CHECK") equalto: $translate.instant("COMMON.FORM_ERRORS.EQUAL_TO") + linewidth: $translate.instant("COMMON.FORM_ERRORS.LINEWIDTH") # Extra validator + pikaday: $translate.instant("COMMON.FORM_ERRORS.PIKADAY") # Extra validator } checksley.updateMessages('default', messages) @@ -584,9 +637,28 @@ i18nInit = (lang, $translate) -> init = ($log, $rootscope, $auth, $events, $analytics, $translate, $location, $navUrls, appMetaService, projectService, loaderService, navigationBarService) -> $log.debug("Initialize application") + $rootscope.$on '$translatePartialLoaderStructureChanged', () -> + $translate.refresh() + + # Checksley - Extra validators + validators = { + linewidth: (val, width) -> + lines = taiga.nl2br(val).split("
") + + valid = _.every lines, (line) -> + line.length < width + + return valid + pikaday: (val) -> + prettyDate = $translate.instant("COMMON.PICKERDATE.FORMAT") + return moment(val, prettyDate).isValid() + } + checksley.updateValidators(validators) + # Taiga Plugins $rootscope.contribPlugins = @.taigaContribPlugins - $rootscope.adminPlugins = _.where(@.taigaContribPlugins, {"type": "admin"}) + $rootscope.adminPlugins = _.filter(@.taigaContribPlugins, {"type": "admin"}) + $rootscope.userSettingsPlugins = _.filter(@.taigaContribPlugins, {"type": "userSettings"}) $rootscope.$on "$translateChangeEnd", (e, ctx) -> lang = ctx.language diff --git a/app/coffee/modules/admin/lightboxes.coffee b/app/coffee/modules/admin/lightboxes.coffee index c625f007..2aa762d5 100644 --- a/app/coffee/modules/admin/lightboxes.coffee +++ b/app/coffee/modules/admin/lightboxes.coffee @@ -27,141 +27,256 @@ debounce = @.taiga.debounce module = angular.module("taigaKanban") -MAX_MEMBERSHIP_FIELDSETS = 4 - ############################################################################# ## Create Members Lightbox Directive ############################################################################# -CreateMembersDirective = ($rs, $rootScope, $confirm, $loading, lightboxService, $compile) -> - extraTextTemplate = """ -
- -
- """ +class LightboxAddMembersController + @.$inject = [ + "$scope", + "lightboxService", + "tgLoader", + "$tgConfirm", + "$tgResources", + "$rootScope", + ] - template = _.template(""" -
-
- data-required="true" <% } %> data-type="email" /> -
-
- - -
-
- """) + constructor: (@scope, @lightboxService, @tgLoader, @confirm, @rs, @rootScope) -> + @._defaultMaxInvites = 4 + @._defaultRole = @.project.roles[0].id + @.form = null + @.submitInvites = false + @.canAddUsers = true + @.memberInvites = [] - link = ($scope, $el, $attrs) -> - createFieldSet = (required = true)-> - ctx = {roleList: $scope.project.roles, required: required} - return $compile(template(ctx))($scope) + if @.project.max_memberships == null + @.membersLimit = @._defaultMaxInvites + else + pendingMembersCount = Math.max(@.project.max_memberships - @.project.total_memberships, 0) + @.membersLimit = Math.min(pendingMembersCount, @._defaultMaxInvites) - resetForm = -> - $el.find("form textarea").remove() - $el.find("form .add-member-wrapper").remove() + @.addSingleMember() - invitations = $el.find(".add-member-forms") - invitations.html($compile(extraTextTemplate)($scope)) + addSingleMember: () -> + @.memberInvites.push({email:'', role_id: @._defaultRole}) - fieldSet = createFieldSet() - invitations.prepend(fieldSet) + if @.memberInvites.length >= @.membersLimit + @.canAddUsers = false + @.showWarningMessage = (!@.canAddUsers && + @.project.total_memberships + @.memberInvites.length == @.project.max_memberships) - $scope.$on "membersform:new", -> - resetForm() - lightboxService.open($el) + removeSingleMember: (index) -> + @.memberInvites.splice(index, 1) - $scope.$on "$destroy", -> - $el.off() + @.canAddUsers = true + @.showWarningMessage = @.membersLimit == 1 - $el.on "click", ".delete-fieldset", (event) -> - event.preventDefault() - target = angular.element(event.currentTarget) - fieldSet = target.closest('.add-member-wrapper') + submit: () -> + # Need to reset the form constrains + @.form.initializeFields() + @.form.reset() + return if not @.form.validate() - fieldSet.remove() + @.memberInvites = _.filter(@.memberInvites, (invites) -> + invites.email != "") - lastActionButton = $el.find(".add-member-wrapper fieldset:last > a") - if lastActionButton.hasClass("icon-delete delete-fieldset") - lastActionButton.removeClass("icon-delete delete-fieldset") - .addClass("icon-plus add-fieldset") + @.submitInvites = true + promise = @rs.memberships.bulkCreateMemberships( + @.project.id, + @.memberInvites, + @.invitationText + ) + promise.then( + @._onSuccessInvite.bind(this), + @._onErrorInvite.bind(this) + ) - $el.on "click", ".add-fieldset", (event) -> - event.preventDefault() - target = angular.element(event.currentTarget) - fieldSet = target.closest('.add-member-wrapper') + _onSuccessInvite: () -> + @.submitInvites = false + @rootScope.$broadcast("membersform:new:success") + @lightboxService.closeAll() + @confirm.notify("success") - target.removeClass("icon-plus add-fieldset") - .addClass("icon-delete delete-fieldset") + _onErrorInvite: (response) -> + @.submitInvites = false + @.form.setErrors(response.data) + if response.data._error_message + @confirm.notify("error", response.data._error_message) - newFieldSet = createFieldSet(false) - fieldSet.after(newFieldSet) +module.controller("LbAddMembersController", LightboxAddMembersController) - $scope.$digest() # To compile newFieldSet and translate text - if $el.find(".add-member-wrapper").length == MAX_MEMBERSHIP_FIELDSETS - $el.find(".add-member-wrapper fieldset:last > a").removeClass("icon-plus add-fieldset") - .addClass("icon-delete delete-fieldset") - submit = debounce 2000, (event) => - event.preventDefault() +LightboxAddMembersDirective = (lightboxService) -> + link = (scope, el, attrs, ctrl) -> + lightboxService.open(el) + ctrl.form = el.find("form").checksley() - currentLoading = $loading() - .target(submitButton) - .start() + return { + scope: {}, + bindToController: { + project: '=', + }, + controller: 'LbAddMembersController', + controllerAs: 'vm', + templateUrl: 'admin/lightbox-add-members.html', + link: link + } - onSuccess = (data) -> - currentLoading.finish() - lightboxService.close($el) - $confirm.notify("success") - $rootScope.$broadcast("membersform:new:success") +module.directive("tgLbAddMembers", ["lightboxService", LightboxAddMembersDirective]) - onError = (data) -> - currentLoading.finish() - lightboxService.close($el) - $confirm.notify("error") - $rootScope.$broadcast("membersform:new:error") - form = $el.find("form").checksley() +############################################################################# +## Warning message directive +############################################################################# - #checksley find new fields - form.destroy() - form.initialize() - if not form.validate() - return +LightboxAddMembersWarningMessageDirective = () -> + return { + templateUrl: "admin/lightbox-add-members-no-more=memberships-warning-message.html" + scope: { + project: "=" + } + } - memberWrappers = $el.find("form .add-member-wrapper") - memberWrappers = _.filter memberWrappers, (mw) -> - angular.element(mw).find("input").hasClass('checksley-ok') +module.directive("tgLightboxAddMembersWarningMessage", [LightboxAddMembersWarningMessageDirective]) - invitations = _.map memberWrappers, (mw) -> - memberWrapper = angular.element(mw) - email = memberWrapper.find("input") - role = memberWrapper.find("select") - return { - email: email.val() - role_id: role.val() - } +############################################################################# +## Transfer project ownership +############################################################################# - if invitations.length - invitation_extra_text = $el.find("form textarea").val() +LbRequestOwnershipDirective = (lightboxService, rs, confirmService, $translate) -> + return { + link: (scope, el) -> + lightboxService.open(el) - promise = $rs.memberships.bulkCreateMemberships($scope.project.id, - invitations, invitation_extra_text) - promise.then(onSuccess, onError) + scope.request = () -> + scope.loading = true - submitButton = $el.find(".submit-button") + rs.projects.transferRequest(scope.projectId).then () -> + scope.loading = false - $el.on "submit", "form", submit + lightboxService.close(el) - return {link: link} + confirmService.notify("success", $translate.instant("ADMIN.PROJECT_PROFILE.REQUEST_OWNERSHIP_SUCCESS")) -module.directive("tgLbCreateMembers", ["$tgResources", "$rootScope", "$tgConfirm", "$tgLoading", - "lightboxService", "$compile", CreateMembersDirective]) + templateUrl: "common/lightbox/lightbox-request-ownership.html" + } + +module.directive('tgLbRequestOwnership', [ + "lightboxService", + "tgResources", + "$tgConfirm", + "$translate", + LbRequestOwnershipDirective]) + +class ChangeOwnerLightboxController + constructor: (@rs, @lightboxService, @confirm, @translate) -> + @.users = [] + @.q = "" + @.commentOpen = false + + limit: 3 + + normalizeString: (normalizedString) -> + normalizedString = normalizedString.replace("Á", "A").replace("Ä", "A").replace("À", "A") + normalizedString = normalizedString.replace("É", "E").replace("Ë", "E").replace("È", "E") + normalizedString = normalizedString.replace("Í", "I").replace("Ï", "I").replace("Ì", "I") + normalizedString = normalizedString.replace("Ó", "O").replace("Ö", "O").replace("Ò", "O") + normalizedString = normalizedString.replace("Ú", "U").replace("Ü", "U").replace("Ù", "U") + return normalizedString + + filterUsers: (user) -> + username = user.full_name_display.toUpperCase() + username = @.normalizeString(username) + text = @.q.toUpperCase() + text = @.normalizeString(text) + + return _.includes(username, text) + + getUsers: () -> + if !@.users.length && !@.q.length + users = @.activeUsers + else + users = @.users + + users = users.slice(0, @.limit) + users = _.reject(users, {"selected": true}) + + return _.reject(users, {"id": @.currentOwnerId}) + + userSearch: () -> + @.users = @.activeUsers + + @.selected = _.find(@.users, {"selected": true}) + + @.users = _.filter(@.users, @.filterUsers.bind(this)) if @.q + + selectUser: (user) -> + @.activeUsers = _.map @.activeUsers, (user) -> + user.selected = false + + return user + + user.selected = true + + @.userSearch() + + submit: () -> + @.loading = true + @rs.projects.transferStart(@.projectId, @.selected.id, @.comment) + .then () => + @.loading = false + @lightboxService.closeAll() + + title = @translate.instant("ADMIN.PROJECT_PROFILE.CHANGE_OWNER_SUCCESS_TITLE") + desc = @translate.instant("ADMIN.PROJECT_PROFILE.CHANGE_OWNER_SUCCESS_DESC") + + @confirm.success(title, desc, { + type: "svg", + name: "icon-speak-up" + }) + +ChangeOwnerLightboxController.$inject = [ + "tgResources", + "lightboxService", + "$tgConfirm", + "$translate" +] + +module.controller('ChangeOwnerLightbox', ChangeOwnerLightboxController) + +ChangeOwnerLightboxDirective = (lightboxService, lightboxKeyboardNavigationService, $template, $compile) -> + link = (scope, el) -> + lightboxService.open(el) + + return { + scope: true, + controller: "ChangeOwnerLightbox", + controllerAs: "vm", + bindToController: { + currentOwnerId: "=", + projectId: "=", + activeUsers: "=" + }, + templateUrl: "common/lightbox/lightbox-change-owner.html" + link:link + } + + +module.directive("tgLbChangeOwner", ["lightboxService", "lightboxKeyboardNavigationService", "$tgTemplate", "$compile", ChangeOwnerLightboxDirective]) + +TransferProjectStartSuccessDirective = (lightboxService) -> + link = (scope, el) -> + scope.close = () -> + lightboxService.close(el) + + lightboxService.open(el) + + return { + templateUrl: "common/lightbox/lightbox-transfer-project-start-success.html" + link:link + } + + +module.directive("tgLbTransferProjectStartSuccess", ["lightboxService", TransferProjectStartSuccessDirective]) diff --git a/app/coffee/modules/admin/memberships.coffee b/app/coffee/modules/admin/memberships.coffee index 84ff8071..4a1da796 100644 --- a/app/coffee/modules/admin/memberships.coffee +++ b/app/coffee/modules/admin/memberships.coffee @@ -47,11 +47,13 @@ class MembershipsController extends mixOf(taiga.Controller, taiga.PageMixin, tai "$tgNavUrls", "$tgAnalytics", "tgAppMetaService", - "$translate" + "$translate", + "$tgAuth" + "tgLightboxFactory" ] constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, @navUrls, @analytics, - @appMetaService, @translate) -> + @appMetaService, @translate, @auth, @lightboxFactory) -> bindMethods(@) @scope.project = {} @@ -67,21 +69,25 @@ class MembershipsController extends mixOf(taiga.Controller, taiga.PageMixin, tai promise.then null, @.onInitialDataError.bind(@) @scope.$on "membersform:new:success", => - @.loadMembers() + @.loadInitialData() @analytics.trackEvent("membership", "create", "create memberships on admin", 1) loadProject: -> return @rs.projects.getBySlug(@params.pslug).then (project) => - if not project.i_am_owner + if not project.i_am_admin @location.path(@navUrls.resolve("permission-denied")) @scope.projectId = project.id @scope.project = project + + @scope.canAddUsers = project.max_memberships == null || project.max_memberships > project.total_memberships + @scope.$emit('project:loaded', project) return project loadMembers: -> httpFilters = @.getUrlFilters() + return @rs.memberships.list(@scope.projectId, httpFilters).then (data) => @scope.memberships = _.filter(data.models, (membership) -> membership.user == null or membership.is_user_active) @@ -92,20 +98,41 @@ class MembershipsController extends mixOf(taiga.Controller, taiga.PageMixin, tai return data loadInitialData: -> - promise = @.loadProject() - promise.then => - @.loadMembers() - - return promise + return @.loadProject().then () => + return @q.all([ + @.loadMembers(), + @auth.refresh() + ]) getUrlFilters: -> filters = _.pick(@location.search(), "page") filters.page = 1 if not filters.page return filters - addNewMembers: -> - @rootscope.$broadcast("membersform:new") + # Actions + addNewMembers: -> + @lightboxFactory.create( + 'tg-lb-add-members', + { + "class": "lightbox lightbox-add-member", + "project": "project" + }, + { + "project": @scope.project + } + ) + + showLimitUsersWarningMessage: -> + title = @translate.instant("ADMIN.MEMBERSHIPS.LIMIT_USERS_WARNING") + message = @translate.instant("ADMIN.MEMBERSHIPS.LIMIT_USERS_WARNING_MESSAGE", { + members: @scope.project.max_memberships + }) + icon = "/" + window._version + "/svg/icons/team-question.svg" + @confirm.success(title, message, { + name: icon, + type: "img" + }) module.controller("MembershipsController", MembershipsController) @@ -224,6 +251,7 @@ MembershipsRowAvatarDirective = ($log, $template, $translate) -> email: if member.user_email then member.user_email else member.email imgurl: if member.photo then member.photo else "/" + window._version + "/images/unnamed.png" pending: if !member.is_user_active then pending else "" + isOwner: member.is_owner } html = template(ctx) @@ -252,6 +280,18 @@ MembershipsRowAdminCheckboxDirective = ($log, $repo, $confirm, $template, $compi template = $template.get("admin/admin-memberships-row-checkbox.html", true) link = ($scope, $el, $attrs) -> + $scope.$on "$destroy", -> + $el.off() + + if not $attrs.tgMembershipsRowAdminCheckbox? + return $log.error "MembershipsRowAdminCheckboxDirective: the directive need a member" + + member = $scope.$eval($attrs.tgMembershipsRowAdminCheckbox) + + if member.is_owner + $el.find(".js-check").remove() + return + render = (member) -> ctx = {inputId: "is-admin-#{member.id}"} @@ -260,30 +300,23 @@ MembershipsRowAdminCheckboxDirective = ($log, $repo, $confirm, $template, $compi $el.html(html) - if not $attrs.tgMembershipsRowAdminCheckbox? - return $log.error "MembershipsRowAdminCheckboxDirective: the directive need a member" - - member = $scope.$eval($attrs.tgMembershipsRowAdminCheckbox) - html = render(member) - - if member.is_owner - $el.find(":checkbox").prop("checked", true) - $el.on "click", ":checkbox", (event) => onSuccess = -> $confirm.notify("success") onError = (data) -> member.revert() - $el.find(":checkbox").prop("checked", member.is_owner) - $confirm.notify("error", data.is_owner[0]) + $el.find(":checkbox").prop("checked", member.is_admin) + $confirm.notify("error", data.is_admin[0]) target = angular.element(event.currentTarget) - member.is_owner = target.prop("checked") + member.is_admin = target.prop("checked") $repo.save(member).then(onSuccess, onError) - $scope.$on "$destroy", -> - $el.off() + html = render(member) + + if member.is_admin + $el.find(":checkbox").prop("checked", true) return {link: link} @@ -352,14 +385,17 @@ module.directive("tgMembershipsRowRoleSelector", ["$log", "$tgRepo", "$tgConfirm ## Member Actions Directive ############################################################################# -MembershipsRowActionsDirective = ($log, $repo, $rs, $confirm, $compile, $translate) -> +MembershipsRowActionsDirective = ($log, $repo, $rs, $confirm, $compile, $translate, $location, + $navUrls, lightboxFactory) -> activedTemplate = """
- + + + """ @@ -370,7 +406,9 @@ MembershipsRowActionsDirective = ($log, $repo, $rs, $confirm, $compile, $transla - + + + """ @@ -403,9 +441,7 @@ MembershipsRowActionsDirective = ($log, $repo, $rs, $confirm, $compile, $transla $rs.memberships.resendInvitation($scope.member.id).then(onSuccess, onError) - $el.on "click", ".delete", (event) -> - event.preventDefault() - + leaveConfirm = () -> title = $translate.instant("ADMIN.MEMBERSHIP.DELETE_MEMBER") defaultMsg = $translate.instant("ADMIN.MEMBERSHIP.DEFAULT_DELETE_MESSAGE", {email: member.email}) message = if member.user then member.full_name else defaultMsg @@ -413,28 +449,60 @@ MembershipsRowActionsDirective = ($log, $repo, $rs, $confirm, $compile, $transla $confirm.askOnDelete(title, message).then (askResponse) -> onSuccess = => askResponse.finish() + if member.user != $scope.user.id + if $scope.page > 1 && ($scope.count - 1) <= $scope.paginatedBy + $ctrl.selectFilter("page", $scope.page - 1) - if $scope.page > 1 && ($scope.count - 1) <= $scope.paginatedBy - $ctrl.selectFilter("page", $scope.page - 1) + $ctrl.loadInitialData() + else + $location.path($navUrls.resolve("home")) - $ctrl.loadMembers() - - text = $translate.instant("ADMIN.MEMBERSHIP.SUCCESS_DELETE") - $confirm.notify("success", null, text) + text = $translate.instant("ADMIN.MEMBERSHIP.SUCCESS_DELETE", {message: message}) + $confirm.notify("success", text, null, 5000) onError = => askResponse.finish(false) text = $translate.instant("ADMIN.MEMBERSHIP.ERROR_DELETE", {message: message}) - $confirm.notify("error", null, text) + $confirm.notify("error", text) $repo.remove(member).then(onSuccess, onError) + $el.on "click", ".delete", (event) -> + event.preventDefault() + + if $scope.project.owner.id == member.user + isCurrentUser = $scope.user.id == member.user + + lightboxFactory.create("tg-lightbox-leave-project-warning", { + class: "lightbox lightbox-leave-project-warning" + }, { + isCurrentUser: isCurrentUser, + project: $scope.project + }) + else + leaveConfirm() + $scope.$on "$destroy", -> $el.off() return {link: link} - module.directive("tgMembershipsRowActions", ["$log", "$tgRepo", "$tgResources", "$tgConfirm", "$compile", - "$translate", MembershipsRowActionsDirective]) + "$translate", "$tgLocation", "$tgNavUrls", "tgLightboxFactory", + MembershipsRowActionsDirective]) + + +############################################################################# +## No more memberships explanation directive +############################################################################# + +NoMoreMembershipsExplanationDirective = () -> + return { + templateUrl: "admin/no-more-memberships-explanation.html" + scope: { + project: "=" + } + } + +module.directive("tgNoMoreMembershipsExplanation", [NoMoreMembershipsExplanationDirective]) diff --git a/app/coffee/modules/admin/project-profile.coffee b/app/coffee/modules/admin/project-profile.coffee index 4a6bee65..5959330f 100644 --- a/app/coffee/modules/admin/project-profile.coffee +++ b/app/coffee/modules/admin/project-profile.coffee @@ -51,11 +51,13 @@ class ProjectProfileController extends mixOf(taiga.Controller, taiga.PageMixin) "$tgLocation", "$tgNavUrls", "tgAppMetaService", - "$translate" + "$translate", + "$tgAuth", + "tgCurrentUserService" ] constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, @navUrls, - @appMetaService, @translate) -> + @appMetaService, @translate, @tgAuth, @currentUserService) -> @scope.project = {} promise = @.loadInitialData() @@ -67,6 +69,8 @@ class ProjectProfileController extends mixOf(taiga.Controller, taiga.PageMixin) description = @scope.project.description @appMetaService.setAll(title, description) + @.fillUsersAndRoles(@scope.project.members, @scope.project.roles) + promise.then null, @.onInitialDataError.bind(@) @scope.$on "project:loaded", => @@ -78,7 +82,7 @@ class ProjectProfileController extends mixOf(taiga.Controller, taiga.PageMixin) loadProject: -> return @rs.projects.getBySlug(@params.pslug).then (project) => - if not project.i_am_owner + if not project.i_am_admin @location.path(@navUrls.resolve("permission-denied")) @scope.projectId = project.id @@ -94,8 +98,10 @@ class ProjectProfileController extends mixOf(taiga.Controller, taiga.PageMixin) return project loadInitialData: -> - promise = @.loadProject() - return promise + return @q.all([ + @.loadProject(), + @tgAuth.refresh() + ]) openDeleteLightbox: -> @rootscope.$broadcast("deletelightbox:new", @scope.project) @@ -198,41 +204,51 @@ ProjectModulesDirective = ($repo, $confirm, $loading, projectService) -> link = ($scope, $el, $attrs) -> submit = => form = $el.find("form").checksley() + form.initializeFields() # Need to reset the form constrains + form.reset() # Need to reset the form constrains return if not form.validate() - target = angular.element(".admin-functionalities .submit-button") - currentLoading = $loading() - .target(target) - .start() - promise = $repo.save($scope.project) promise.then -> - currentLoading.finish() - $confirm.notify("success") $scope.$emit("project:loaded", $scope.project) + $confirm.notify("success") projectService.fetchProject() promise.then null, (data) -> - currentLoading.finish() - $confirm.notify("error", data._error_message) + form.setErrors(data) + if data._error_message + $confirm.notify("error", data._error_message) + + $el.on "change", ".module-activation.module-direct-active input", (event) -> + event.preventDefault() + submit() $el.on "submit", "form", (event) -> event.preventDefault() submit() - $el.on "click", ".admin-functionalities a.button-green", (event) -> + $el.on "click", ".icon-save", (event) -> event.preventDefault() submit() - $scope.$watch "isVideoconferenceActivated", (isVideoconferenceActivated) -> - if isVideoconferenceActivated - $el.find(".videoconference-attributes").removeClass("hidden") - else - $el.find(".videoconference-attributes").addClass("hidden") + $el.on "keydown", ".videoconference-attributes input", (e) -> + return e.which != 32 + + $scope.$watch "project.videoconferences", (newVal, oldVal) -> + # Reset videoconferences_extra_data if videoconference system change + if newVal? and oldVal? and newVal != oldVal + $scope.project.videoconferences_extra_data = "" + + $scope.$watch "isVideoconferenceActivated", (newValue, oldValue) -> + if newValue == false + # Reset videoconference attributes $scope.project.videoconferences = null $scope.project.videoconferences_extra_data = "" + # Save when videoconference is desactivated + submit() if oldValue == true + $scope.$watch "project", (project) -> if project.videoconferences? $scope.isVideoconferenceActivated = true @@ -510,3 +526,60 @@ ProjectLogoModelDirective = ($parse) -> return {link:link} module.directive('tgProjectLogoModel', ['$parse', ProjectLogoModelDirective]) + + +AdminProjectRestrictionsDirective = () -> + return { + scope: { + "project": "=" + }, + templateUrl: "admin/admin-project-restrictions.html" + } + +module.directive('tgAdminProjectRestrictions', [AdminProjectRestrictionsDirective]) + +AdminProjectRequestOwnershipDirective = (lightboxFactory) -> + return { + link: (scope) -> + scope.requestOwnership = () -> + lightboxFactory.create("tg-lb-request-ownership", { + "class": "lightbox lightbox-request-ownership" + }, { + projectId: scope.projectId + }) + + scope: { + "projectId": "=", + "owner": "=" + }, + templateUrl: "admin/admin-project-request-ownership.html" + } + +module.directive('tgAdminProjectRequestOwnership', ["tgLightboxFactory", AdminProjectRequestOwnershipDirective]) + +AdminProjectChangeOwnerDirective = (lightboxFactory) -> + return { + link: (scope) -> + scope.changeOwner = () -> + lightboxFactory.create("tg-lb-change-owner", { + "class": "lightbox lightbox-select-user", + "project-id": "projectId", + "active-users": "activeUsers", + "current-owner-id": "currentOwnerId" + }, { + projectId: scope.projectId, + activeUsers: scope.activeUsers, + currentOwnerId: scope.owner.id, + members: scope.members + }) + + scope: { + "activeUsers": "=" + "projectId": "=" + "owner": "=" + "members": "=" + }, + templateUrl: "admin/admin-project-change-owner.html" + } + +module.directive('tgAdminProjectChangeOwner', ["tgLightboxFactory", AdminProjectChangeOwnerDirective]) diff --git a/app/coffee/modules/admin/project-values.coffee b/app/coffee/modules/admin/project-values.coffee index 2fb76093..e4bef2be 100644 --- a/app/coffee/modules/admin/project-values.coffee +++ b/app/coffee/modules/admin/project-values.coffee @@ -73,7 +73,7 @@ class ProjectValuesSectionController extends mixOf(taiga.Controller, taiga.PageM loadProject: -> return @rs.projects.getBySlug(@params.pslug).then (project) => - if not project.i_am_owner + if not project.i_am_admin @location.path(@navUrls.resolve("permission-denied")) @scope.projectId = project.id @@ -108,7 +108,7 @@ class ProjectValuesController extends taiga.Controller loadValues: => return @rs[@scope.resource].listValues(@scope.projectId, @scope.type).then (values) => @scope.values = values - @scope.maxValueOrder = _.max(values, "order").order + @scope.maxValueOrder = _.maxBy(values, "order").order return values moveValue: (ctx, itemValue, itemIndex) => @@ -381,6 +381,7 @@ module.directive("tgColorSelection", ColorSelectionDirective) TEXT_TYPE = "text" MULTILINE_TYPE = "multiline" DATE_TYPE = "date" +URL_TYPE = "url" TYPE_CHOICES = [ @@ -395,6 +396,10 @@ TYPE_CHOICES = [ { key: DATE_TYPE, name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_DATE" + }, + { + key: URL_TYPE, + name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_URL" } ] @@ -436,7 +441,7 @@ class ProjectCustomAttributesController extends mixOf(taiga.Controller, taiga.Pa loadCustomAttributes: => return @rs.customAttributes[@scope.type].list(@scope.projectId).then (customAttributes) => @scope.customAttributes = customAttributes - @scope.maxOrder = _.max(customAttributes, "order").order + @scope.maxOrder = _.maxBy(customAttributes, "order").order return customAttributes createCustomAttribute: (attrValues) => @@ -555,7 +560,6 @@ ProjectCustomAttributesDirective = ($log, $confirm, animationFrame, $translate) $el.on "click", ".js-add-custom-field-button", (event) -> event.preventDefault() - showCreateForm() $el.on "click", ".js-create-custom-field-button", debounce 2000, (event) -> @@ -567,7 +571,6 @@ ProjectCustomAttributesDirective = ($log, $confirm, animationFrame, $translate) $el.on "click", ".js-cancel-new-custom-field-button", (event) -> event.preventDefault() - cancelCreate() $el.on "keyup", ".js-new-custom-field input", (event) -> diff --git a/app/coffee/modules/admin/roles.coffee b/app/coffee/modules/admin/roles.coffee index 59072640..f6d3ecff 100644 --- a/app/coffee/modules/admin/roles.coffee +++ b/app/coffee/modules/admin/roles.coffee @@ -70,7 +70,7 @@ class RolesController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fil loadProject: -> return @rs.projects.getBySlug(@params.pslug).then (project) => - if not project.i_am_owner + if not project.i_am_admin @location.path(@navUrls.resolve("permission-denied")) @scope.projectId = project.id @@ -193,7 +193,7 @@ EditRoleDirective = ($repo, $confirm) -> toggleView() - $el.on "click", "a.icon-edit", -> + $el.on "click", ".edit-value", -> toggleView() $el.find("input").focus() $el.find("input").val($scope.role.name) @@ -251,7 +251,7 @@ NewRoleDirective = ($tgrepo, $confirm) -> project: $scope.projectId name: target.val() permissions: DEFAULT_PERMISSIONS - order: _.max($scope.roles, (r) -> r.order).order + 1 + order: _.maxBy($scope.roles, (r) -> r.order).order + 1 computable: false } @@ -292,7 +292,9 @@ RolePermissionsDirective = ($rootscope, $repo, $confirm, $compile) -> title="{{ '<%- permission.name %>' | translate }}"> <% }) %> -
+ + + """) categoryTemplate = _.template(""" @@ -431,6 +433,7 @@ RolePermissionsDirective = ($rootscope, $repo, $confirm, $compile) -> $el.on "click", ".resume", (event) -> event.preventDefault() target = angular.element(event.currentTarget) + target.toggleClass("open-drawer") target.next().toggleClass("open") $el.on "change", ".category-item input", (event) -> diff --git a/app/coffee/modules/admin/third-parties.coffee b/app/coffee/modules/admin/third-parties.coffee index f3a7d6a5..9cc4eaf6 100644 --- a/app/coffee/modules/admin/third-parties.coffee +++ b/app/coffee/modules/admin/third-parties.coffee @@ -71,7 +71,7 @@ class WebhooksController extends mixOf(taiga.Controller, taiga.PageMixin, taiga. loadProject: -> return @rs.projects.getBySlug(@params.pslug).then (project) => - if not project.i_am_owner + if not project.i_am_admin @location.path(@navUrls.resolve("permission-denied")) @scope.projectId = project.id @@ -103,7 +103,7 @@ WebhookDirective = ($rs, $repo, $confirm, $loading, $translate) -> $rs.webhooklogs.list(webhook.id).then (webhooklogs) => for log in webhooklogs log.validStatus = 200 <= log.status < 300 - log.prettySentHeaders = _.map(_.pairs(log.request_headers), ([header, value]) -> "#{header}: #{value}").join("\n") + log.prettySentHeaders = _.map(_.toPairs(log.request_headers), ([header, value]) -> "#{header}: #{value}").join("\n") log.prettySentData = JSON.stringify(log.request_data) log.prettyDate = moment(log.created).format(prettyDate) diff --git a/app/coffee/modules/auth.coffee b/app/coffee/modules/auth.coffee index 9a040fff..5267c509 100644 --- a/app/coffee/modules/auth.coffee +++ b/app/coffee/modules/auth.coffee @@ -27,6 +27,26 @@ debounce = @.taiga.debounce module = angular.module("taigaAuth", ["taigaResources"]) +class LoginPage + @.$inject = [ + 'tgCurrentUserService', + '$location', + '$tgNavUrls', + '$routeParams' + ] + + constructor: (currentUserService, $location, $navUrls, $routeParams) -> + if currentUserService.isAuthenticated() + url = $navUrls.resolve("home") + if $routeParams['next'] + url = $routeParams['next'] + $location.search('next', null) + + $location.path(url) + + +module.controller('LoginPage', LoginPage) + ############################################################################# ## Authentication Service ############################################################################# @@ -122,6 +142,17 @@ class AuthService extends taiga.Service return false ## Http interface + refresh: () -> + url = @urls.resolve("user-me") + + return @http.get(url).then (data, status) => + user = data.data + user.token = @.getUser().auth_token + + user = @model.make_model("users", user) + + @.setUser(user) + return user login: (data, type) -> url = @urls.resolve("auth") @@ -214,7 +245,6 @@ PublicRegisterMessageDirective = ($config, $navUrls, $routeParams, templates) -> url = $navUrls.resolve("register") if $routeParams['next'] and $routeParams['next'] != $navUrls.resolve("register") nextUrl = encodeURIComponent($routeParams['next']) - console.log "-----", nextUrl url += "?next=#{nextUrl}" return template({url:url}) @@ -287,16 +317,11 @@ RegisterDirective = ($auth, $confirm, $location, $navUrls, $config, $routeParams $scope.data = {} form = $el.find("form").checksley({onlyOneErrorElement: true}) - if $routeParams['next'] and $routeParams['next'] != $navUrls.resolve("register") - $scope.nextUrl = decodeURIComponent($routeParams['next']) - else - $scope.nextUrl = $navUrls.resolve("home") + $scope.nextUrl = $navUrls.resolve("home") onSuccessSubmit = (response) -> $analytics.trackEvent("auth", "register", "user registration", 1) - $confirm.notify("success", $translate.instant("LOGIN_FORM.SUCCESS")) - $location.url($scope.nextUrl) onErrorSubmit = (response) -> @@ -340,8 +365,10 @@ ForgotPasswordDirective = ($auth, $confirm, $location, $navUrls, $translate) -> onSuccessSubmit = (response) -> $location.path($navUrls.resolve("login")) - text = $translate.instant("FORGOT_PASSWORD_FORM.SUCCESS") - $confirm.success(text) + title = $translate.instant("FORGOT_PASSWORD_FORM.SUCCESS_TITLE") + message = $translate.instant("FORGOT_PASSWORD_FORM.SUCCESS_TEXT") + + $confirm.success(title, message) onErrorSubmit = (response) -> text = $translate.instant("FORGOT_PASSWORD_FORM.ERROR") diff --git a/app/coffee/modules/backlog/lightboxes.coffee b/app/coffee/modules/backlog/lightboxes.coffee index 72cd04e5..d26ca64d 100644 --- a/app/coffee/modules/backlog/lightboxes.coffee +++ b/app/coffee/modules/backlog/lightboxes.coffee @@ -36,8 +36,11 @@ CreateEditSprint = ($repo, $confirm, $rs, $rootscope, lightboxService, $loading, link = ($scope, $el, attrs) -> hasErrors = false createSprint = true + form = null resetSprint = () -> + form.reset() if form + $scope.sprint = { project: null name: null @@ -201,7 +204,7 @@ CreateEditSprint = ($repo, $confirm, $rs, $rootscope, lightboxService, $loading, $el.on "submit", "form", submit - $el.on "click", ".delete-sprint .icon-delete", (event) -> + $el.on "click", ".delete-sprint", (event) -> event.preventDefault() remove() diff --git a/app/coffee/modules/backlog/main.coffee b/app/coffee/modules/backlog/main.coffee index d2ea8d2a..f56a0b9c 100644 --- a/app/coffee/modules/backlog/main.coffee +++ b/app/coffee/modules/backlog/main.coffee @@ -563,7 +563,7 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F currentLoading = @loading() .target(target) - .removeClasses("icon-edit") + .removeClasses("edit-story") .timeout(200) .start() @@ -959,7 +959,7 @@ UsPointsDirective = ($tgEstimationsService, $repo, $tgTemplate) -> $el.find(".pop-role").popover().open(() -> $(this).remove()) bindClickElements = () -> - $el.on "click", "a.us-points span", (event) -> + $el.on "click", "a.us-points", (event) -> event.preventDefault() event.stopPropagation() us = $scope.$eval($attrs.tgBacklogUsPoints) diff --git a/app/coffee/modules/backlog/sprints.coffee b/app/coffee/modules/backlog/sprints.coffee index 218da013..2ea49705 100644 --- a/app/coffee/modules/backlog/sprints.coffee +++ b/app/coffee/modules/backlog/sprints.coffee @@ -40,7 +40,7 @@ BacklogSprintDirective = ($repo, $rootscope) -> toggleSprint = ($el) => sprintTable = $el.find(".sprint-table") - sprintArrow = $el.find(".icon-arrow-up") + sprintArrow = $el.find(".compact-sprint") sprintArrow.toggleClass('active') sprintTable.toggleClass('open') @@ -55,7 +55,7 @@ BacklogSprintDirective = ($repo, $rootscope) -> toggleSprint($el) # Event Handlers - $el.on "click", ".sprint-name > .icon-arrow-up", (event) -> + $el.on "click", ".sprint-name > .compact-sprint", (event) -> event.preventDefault() toggleSprint($el) diff --git a/app/coffee/modules/base.coffee b/app/coffee/modules/base.coffee index feeb02f8..2806d182 100644 --- a/app/coffee/modules/base.coffee +++ b/app/coffee/modules/base.coffee @@ -67,6 +67,7 @@ urls = { "profile": "/profile" "user-profile": "/profile/:username" + "blocked-project": "/blocked-project/:project" "project": "/project/:project" "project-backlog": "/project/:project/backlog" "project-taskboard": "/project/:project/taskboard/:sprint" @@ -112,6 +113,7 @@ urls = { "user-settings-user-change-password": "/user-settings/user-change-password" "user-settings-user-avatar": "/user-settings/user-avatar" "user-settings-mail-notifications": "/user-settings/mail-notifications" + "user-settings-contrib": "/user-settings/contrib/:plugin" } diff --git a/app/coffee/modules/base/contrib.coffee b/app/coffee/modules/base/contrib.coffee index 9c66492f..e8607fef 100644 --- a/app/coffee/modules/base/contrib.coffee +++ b/app/coffee/modules/base/contrib.coffee @@ -36,7 +36,7 @@ class ContribController extends taiga.Controller ] constructor: (@rootScope, @scope, @params, @repo, @rs, @confirm) -> - @scope.currentPlugin = _.first(_.where(@rootScope.adminPlugins, {"slug": @params.plugin})) + @scope.currentPlugin = _.head(_.filter(@rootScope.adminPlugins, {"slug": @params.plugin})) @scope.projectSlug = @params.pslug promise = @.loadInitialData() @@ -56,3 +56,16 @@ class ContribController extends taiga.Controller return @.loadProject() module.controller("ContribController", ContribController) + + +class ContribUserSettingsController extends taiga.Controller + @.$inject = [ + "$rootScope", + "$scope", + "$routeParams" + ] + + constructor: (@rootScope, @scope, @params) -> + @scope.currentPlugin = _.head(_.filter(@rootScope.userSettingsPlugins, {"slug": @params.plugin})) + +module.controller("ContribUserSettingsController", ContribUserSettingsController) diff --git a/app/coffee/modules/base/http.coffee b/app/coffee/modules/base/http.coffee index 2144e3fb..0c425720 100644 --- a/app/coffee/modules/base/http.coffee +++ b/app/coffee/modules/base/http.coffee @@ -47,12 +47,12 @@ class HttpService extends taiga.Service return headers request: (options) -> - options.headers = _.merge({}, options.headers or {}, @.headers()) + options.headers = _.assign({}, options.headers or {}, @.headers()) return @http(options) get: (url, params, options) -> - options = _.merge({method: "GET", url: url}, options) + options = _.assign({method: "GET", url: url}, options) options.params = params if params # prevent duplicated http request @@ -62,25 +62,27 @@ class HttpService extends taiga.Service @.cache.removeAll() post: (url, data, params, options) -> - options = _.merge({method: "POST", url: url}, options) + options = _.assign({method: "POST", url: url}, options) + options.data = data if data options.params = params if params + return @.request(options) put: (url, data, params, options) -> - options = _.merge({method: "PUT", url: url}, options) + options = _.assign({method: "PUT", url: url}, options) options.data = data if data options.params = params if params return @.request(options) patch: (url, data, params, options) -> - options = _.merge({method: "PATCH", url: url}, options) + options = _.assign({method: "PATCH", url: url}, options) options.data = data if data options.params = params if params return @.request(options) delete: (url, data, params, options) -> - options = _.merge({method: "DELETE", url: url}, options) + options = _.assign({method: "DELETE", url: url}, options) options.data = data if data options.params = params if params return @.request(options) diff --git a/app/coffee/modules/base/navurls.coffee b/app/coffee/modules/base/navurls.coffee index 85fee430..28fa20de 100644 --- a/app/coffee/modules/base/navurls.coffee +++ b/app/coffee/modules/base/navurls.coffee @@ -59,7 +59,7 @@ module.service("$tgNavUrls", NavigationUrlsService) ## Navigation Urls Directive ############################################################################# -NavigationUrlsDirective = ($navurls, $auth, $q, $location) -> +NavigationUrlsDirective = ($navurls, $auth, $q, $location, lightboxService) -> # Example: # link(tg-nav="project-backlog:project='sss',") @@ -157,9 +157,11 @@ NavigationUrlsDirective = ($navurls, $auth, $q, $location) -> when 2 window.open fullUrl + lightboxService.closeAll() + $scope.$on "$destroy", -> $el.off() return {link: link} -module.directive("tgNav", ["$tgNavUrls", "$tgAuth", "$q", "$tgLocation", NavigationUrlsDirective]) +module.directive("tgNav", ["$tgNavUrls", "$tgAuth", "$q", "$tgLocation", "lightboxService", NavigationUrlsDirective]) diff --git a/app/coffee/modules/base/urls.coffee b/app/coffee/modules/base/urls.coffee index 44fdfaf6..e275390a 100644 --- a/app/coffee/modules/base/urls.coffee +++ b/app/coffee/modules/base/urls.coffee @@ -48,8 +48,8 @@ class UrlsService extends taiga.Service url = format(@.urls[name], args.slice(1)) return format("%s/%s", [ - _.str.rtrim(@.mainUrl, "/"), - _.str.ltrim(url, "/") + _.trimEnd(@.mainUrl, "/"), + _.trimStart(url, "/") ]) resolveAbsolute: -> diff --git a/app/coffee/modules/common.coffee b/app/coffee/modules/common.coffee index 955861d0..f8f9f237 100644 --- a/app/coffee/modules/common.coffee +++ b/app/coffee/modules/common.coffee @@ -234,26 +234,6 @@ ProjectUrl = ($navurls) -> module.factory("$projectUrl", ["$tgNavUrls", ProjectUrl]) -############################################################################# -## Limite line size in a text area -############################################################################# - -LimitLineLengthDirective = () -> - link = ($scope, $el, $attrs) -> - maxColsPerLine = parseInt($el.attr("cols")) - $el.on "keyup", (event) -> - code = event.keyCode - lines = $el.val().split("\n") - - _.each lines, (line, index) -> - lines[index] = line.substring(0, maxColsPerLine - 2) - - $el.val(lines.join("\n")) - - return {link:link} - -module.directive("tgLimitLineLength", LimitLineLengthDirective) - ############################################################################# ## Queue Q promises ############################################################################# @@ -308,13 +288,11 @@ Capslock = ($translate) -> link = ($scope, $el, $attrs) -> open = false - warningIcon = $('
') - .addClass('icon') - .addClass('icon-capslock') - .attr('title', $translate.instant('COMMON.CAPSLOCK_WARNING')) + + warningIcon = ""; hideIcon = () -> - warningIcon.fadeOut () -> + $('.icon-capslock').fadeOut () -> open = false $(this).remove() diff --git a/app/coffee/modules/common/components.coffee b/app/coffee/modules/common/components.coffee index dece6008..325c2524 100644 --- a/app/coffee/modules/common/components.coffee +++ b/app/coffee/modules/common/components.coffee @@ -321,7 +321,7 @@ AssignedToDirective = ($rootscope, $confirm, $repo, $loading, $qqueue, $template $model.$modelValue.assigned_to = $currentUserService.getUser().get('id') save($currentUserService.getUser().get('id')) - $el.on "click", ".icon-delete", (event) -> + $el.on "click", ".remove-user", (event) -> event.preventDefault() return if not isEditable() title = $translate.instant("COMMON.ASSIGNED_TO.CONFIRM_UNASSIGNED") @@ -498,11 +498,10 @@ EditableSubjectDirective = ($rootscope, $repo, $confirm, $loading, $qqueue, $tem else if event.keyCode == 27 $scope.$apply () => $model.$modelValue.revert() - $el.find('div.edit-subject').hide() - $el.find('div.view-subject').show() + $el.find('.edit-subject').hide() + $el.find('.view-subject').show() - $el.find('div.edit-subject').hide() - $el.find('div.view-subject span.edit').hide() + $el.find('.edit-subject').hide() $scope.$watch $attrs.ngModel, (value) -> return if not value diff --git a/app/coffee/modules/common/confirm.coffee b/app/coffee/modules/common/confirm.coffee index be7452cc..bb62cb60 100644 --- a/app/coffee/modules/common/confirm.coffee +++ b/app/coffee/modules/common/confirm.coffee @@ -59,12 +59,12 @@ class ConfirmService extends taiga.Service el = angular.element(lightboxSelector) # Render content - el.find("h2.title").text(title) - el.find("span.subtitle").text(subtitle) - el.find("span.message").text(message) + el.find(".title").text(title) + el.find(".subtitle").text(subtitle) + el.find(".message").text(message) # Assign event handlers - el.on "click.confirm-dialog", "a.button-green", debounce 2000, (event) => + el.on "click.confirm-dialog", ".button-green", debounce 2000, (event) => event.preventDefault() target = angular.element(event.currentTarget) currentLoading = @loading() @@ -77,7 +77,7 @@ class ConfirmService extends taiga.Service @.hide(el) } - el.on "click.confirm-dialog", "a.button-red", (event) => + el.on "click.confirm-dialog", ".button-red", (event) => event.preventDefault() defered.reject() @.hide(el) @@ -129,7 +129,7 @@ class ConfirmService extends taiga.Service @.hide(el) } - el.on "click.confirm-dialog", "a.button-red", (event) => + el.on "click.confirm-dialog", ".button-red", (event) => event.preventDefault() defered.reject() @.hide(el) @@ -144,15 +144,15 @@ class ConfirmService extends taiga.Service el = angular.element(".lightbox-generic-error") # Render content - el.find("h2.title").html(message) + el.find(".title").html(message) # Assign event handlers - el.on "click.confirm-dialog", "a.button-green", (event) => + el.on "click.confirm-dialog", ".button-green", (event) => event.preventDefault() defered.resolve() @.hide(el) - el.on "click.confirm-dialog", "a.close", (event) => + el.on "click.confirm-dialog", ".close", (event) => event.preventDefault() defered.resolve() @.hide(el) @@ -161,22 +161,41 @@ class ConfirmService extends taiga.Service return defered.promise - success: (title, message) -> + success: (title, message, icon) -> defered = @q.defer() el = angular.element(".lightbox-generic-success") + el.find("img").remove() + el.find("svg").remove() + + if icon + if icon.type == "img" + detailImage = $('').addClass('lb-icon').attr('src', icon.name) + else if icon.type == "svg" + useSVG = document.createElementNS('http://www.w3.org/2000/svg', 'use') + useSVG.setAttributeNS('http://www.w3.org/1999/xlink','href', '#' + icon.name) + + detailImage = document.createElementNS("http://www.w3.org/2000/svg", "svg") + detailImage.classList.add("icon") + detailImage.classList.add("lb-icon") + detailImage.classList.add(icon.name) + detailImage.appendChild(useSVG) + + if detailImage + el.find('section').prepend(detailImage) + # Render content - el.find("h2.title").html(title) if title - el.find("p.message").html(message) if message + el.find(".title").html(title) if title + el.find(".message").html(message) if message # Assign event handlers - el.on "click.confirm-dialog", "a.button-green", (event) => + el.on "click.confirm-dialog", ".button-green", (event) => event.preventDefault() defered.resolve() @.hide(el) - el.on "click.confirm-dialog", "a.close", (event) => + el.on "click.confirm-dialog", ".close", (event) => event.preventDefault() defered.resolve() @.hide(el) @@ -189,15 +208,15 @@ class ConfirmService extends taiga.Service el = angular.element(".lightbox-generic-loading") # Render content - el.find("h2.title").html(title) if title - el.find("p.message").html(message) if message + el.find(".title").html(title) if title + el.find(".message").html(message) if message return { start: => @lightboxService.open(el) stop: => @lightboxService.close(el) update: (status, title, message, percent) => - el.find("h2.title").html(title) if title - el.find("p.message").html(message) if message + el.find(".title").html(title) if title + el.find(".message").html(message) if message if percent el.find(".spin").addClass("hidden") @@ -248,10 +267,11 @@ class ConfirmService extends taiga.Service body.find(selector) .removeClass('active') .addClass('inactive') + .one 'animationend', () -> $(this).removeClass('inactive') delete @.tsem - el.on "click", ".icon-delete, .close", (event) => + el.on "click", ".icon-close, .close", (event) => body.find(selector) .removeClass('active') .addClass('inactive') diff --git a/app/coffee/modules/common/custom-field-values.coffee b/app/coffee/modules/common/custom-field-values.coffee index ad748350..897cfe24 100644 --- a/app/coffee/modules/common/custom-field-values.coffee +++ b/app/coffee/modules/common/custom-field-values.coffee @@ -34,6 +34,7 @@ module = angular.module("taigaCommon") TEXT_TYPE = "text" MULTILINE_TYPE = "multiline" DATE_TYPE = "date" +URL_TYPE = "url" TYPE_CHOICES = [ @@ -48,6 +49,10 @@ TYPE_CHOICES = [ { key: DATE_TYPE, name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_DATE" + }, + { + key: URL_TYPE, + name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_URL" } ] @@ -100,6 +105,7 @@ class CustomAttributesValuesController extends taiga.Controller CustomAttributesValuesDirective = ($templates, $storage) -> template = $templates.get("custom-attributes/custom-attributes-values.html", true) + collapsedHash = (type) -> return generateHash(["custom-attributes-collapsed", type]) @@ -111,15 +117,15 @@ CustomAttributesValuesDirective = ($templates, $storage) -> $ctrl.initialize($attrs.type, value.id) $ctrl.loadCustomAttributesValues() - $el.on "click", ".custom-fields-header a", -> + $el.on "click", ".custom-fields-header .icon", -> hash = collapsedHash($attrs.type) collapsed = not($storage.get(hash) or false) $storage.set(hash, collapsed) if collapsed - $el.find(".custom-fields-header a").removeClass("open") + $el.find(".custom-fields-header .icon").removeClass("open") $el.find(".custom-fields-body").removeClass("open") else - $el.find(".custom-fields-header a").addClass("open") + $el.find(".custom-fields-header .icon").addClass("open") $el.find(".custom-fields-body").addClass("open") $scope.$on "$destroy", -> @@ -198,12 +204,14 @@ CustomAttributeValueDirective = ($template, $selectedText, $compile, $translate, submit = debounce 2000, (event) => event.preventDefault() - attributeValue.value = $el.find("input[name=value], textarea[name='value']").val() + form = $el.find("form").checksley() + return if not form.validate() + + input = $el.find("input[name=value], textarea[name='value']") + attributeValue.value = input.val() if attributeValue.type is DATE_TYPE if moment(attributeValue.value, prettyDate).isValid() attributeValue.value = moment(attributeValue.value, prettyDate).format("YYYY-MM-DD") - else - attributeValue.value = "" $scope.$apply -> $ctrl.updateAttributeValue(attributeValue).then -> @@ -217,13 +225,17 @@ CustomAttributeValueDirective = ($template, $selectedText, $compile, $translate, render(attributeValue) ## Actions (on view mode) + + $el.on "click", ".js-value-view-mode span a", (event) -> + event.stopPropagation() + $el.on "click", ".js-value-view-mode", -> return if not isEditable() return if $selectedText.get().length render(attributeValue, true) setFocusAndSelectOnInputField() - $el.on "click", "a.icon-edit", (event) -> + $el.on "click", ".js-edit-description", (event) -> event.preventDefault() render(attributeValue, true) setFocusAndSelectOnInputField() @@ -237,7 +249,7 @@ CustomAttributeValueDirective = ($template, $selectedText, $compile, $translate, $el.on "submit", "form", submit - $el.on "click", "a.icon-floppy", submit + $el.on "click", ".js-save-description", submit $scope.$on "$destroy", -> $el.off() diff --git a/app/coffee/modules/common/history.coffee b/app/coffee/modules/common/history.coffee index c650b092..bbc1beb4 100644 --- a/app/coffee/modules/common/history.coffee +++ b/app/coffee/modules/common/history.coffee @@ -370,10 +370,12 @@ HistoryDirective = ($log, $loading, $qqueue, $template, $confirm, $translate, $c renderComments = -> comments = $scope.comments or [] totalComments = comments.length - if not showAllComments - comments = _.last(comments, 4) - comments = _.map(comments, (x) -> renderComment(x)) + if not showAllComments + comments = _.takeRight(comments, 4) + + comments = _.map comments, (x) -> renderComment(x) + html = renderHistory(comments, totalComments) $el.find(".comments-list").html(html) @@ -381,7 +383,7 @@ HistoryDirective = ($log, $loading, $qqueue, $template, $confirm, $translate, $c changes = $scope.history or [] totalChanges = changes.length if not showAllActivity - changes = _.last(changes, 4) + changes = _.takeRight(changes, 4) changes = _.map(changes, (x) -> renderChange(x)) html = renderHistory(changes, totalChanges) diff --git a/app/coffee/modules/common/importer.coffee b/app/coffee/modules/common/importer.coffee index de61ce3f..4ff587c1 100644 --- a/app/coffee/modules/common/importer.coffee +++ b/app/coffee/modules/common/importer.coffee @@ -25,8 +25,60 @@ module = angular.module("taigaCommon") -ImportProjectButtonDirective = ($rs, $confirm, $location, $navUrls, $translate) -> +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("") @@ -40,32 +92,62 @@ ImportProjectButtonDirective = ($rs, $confirm, $location, $navUrls, $translate) loader = $confirm.loader($translate.instant("PROJECT.IMPORT.UPLOADING_FILE")) onSuccess = (result) -> - 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) + currentUserService.loadProjects().then () -> + loader.stop() - 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) + 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) -> - loader.stop() - errorMsg = $translate.instant("PROJECT.IMPORT.ERROR") + $tgAuth.refresh().then () -> + restrictionError = getRestrictionError(result) - 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.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", +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 57f688b7..00a1c86e 100644 --- a/app/coffee/modules/common/lightboxes.coffee +++ b/app/coffee/modules/common/lightboxes.coffee @@ -38,6 +38,8 @@ class LightboxService extends taiga.Service constructor: (@animationFrame, @q) -> open: ($el) -> + if _.isString($el) + $el = $($el) defered = @q.defer() lightboxContent = $el.children().not(".close") @@ -63,6 +65,8 @@ class LightboxService extends taiga.Service return defered.promise close: ($el) -> + if _.isString($el) + $el = $($el) docEl = angular.element(document) docEl.off(".lightbox") docEl.off(".keyboard-navigation") # Hack: to fix problems in the WYSIWYG textareas when press ENTER @@ -70,7 +74,8 @@ class LightboxService extends taiga.Service $el.removeAttr('style') $el.removeClass("open").removeClass('close') - $el.addClass('close') + @animationFrame.add -> + $el.addClass('close') if $el.hasClass("remove-on-close") scope = $el.data("scope") @@ -268,6 +273,7 @@ module.directive("tgBlockingMessageInput", ["$log", "$tgTemplate", "$compile", B CreateEditUserstoryDirective = ($repo, $model, $rs, $rootScope, lightboxService, $loading, $translate, $confirm, $q, attachmentsService) -> link = ($scope, $el, attrs) -> + form = null $scope.createEditUs = {} $scope.isNew = true @@ -285,6 +291,7 @@ CreateEditUserstoryDirective = ($repo, $model, $rs, $rootScope, lightboxService, attachmentsToDelete = attachmentsToDelete.push(attachment) $scope.$on "usform:new", (ctx, projectId, status, statusList) -> + form.reset() if form $scope.isNew = true $scope.usStatusList = statusList $scope.attachments = Immutable.List() @@ -312,6 +319,8 @@ CreateEditUserstoryDirective = ($repo, $model, $rs, $rootScope, lightboxService, lightboxService.open($el) $scope.$on "usform:edit", (ctx, us, attachments) -> + form.reset() if form + $scope.us = us $scope.attachments = Immutable.fromJS(attachments) $scope.isNew = false @@ -431,7 +440,11 @@ module.directive("tgLbCreateEditUserstory", [ CreateBulkUserstoriesDirective = ($repo, $rs, $rootscope, lightboxService, $loading) -> link = ($scope, $el, attrs) -> + form = null + $scope.$on "usform:bulk", (ctx, projectId, status) -> + form.reset() if form + $scope.new = { projectId: projectId statusId: status @@ -505,7 +518,7 @@ AssignedToLightboxDirective = (lightboxService, lightboxKeyboardNavigationServic username = normalizeString(username) text = text.toUpperCase() text = normalizeString(text) - return _.contains(username, text) + return _.includes(username, text) render = (selected, text) -> users = _.clone($scope.activeUsers, true) @@ -514,7 +527,7 @@ AssignedToLightboxDirective = (lightboxService, lightboxKeyboardNavigationServic ctx = { selected: selected - users: _.first(users, 5) + users: _.slice(users, 0, 5) showMore: users.length > 5 } @@ -600,7 +613,7 @@ WatchersLightboxDirective = ($repo, lightboxService, lightboxKeyboardNavigationS username = user.full_name_display.toUpperCase() text = text.toUpperCase() - return _.contains(username, text) + return _.includes(username, text) users = _.clone($scope.activeUsers, true) users = _.filter(users, _.partial(_filterUsers, text)) @@ -610,7 +623,7 @@ WatchersLightboxDirective = ($repo, lightboxService, lightboxKeyboardNavigationS render = (users) -> ctx = { selected: false - users: _.first(users, 5) + users: _.slice(users, 0, 5) showMore: users.length > 5 } @@ -684,3 +697,15 @@ AttachmentPreviewLightboxDirective = (lightboxService, $template, $compile) -> } module.directive("tgLbAttachmentPreview", ["lightboxService", "$tgTemplate", "$compile", AttachmentPreviewLightboxDirective]) + +LightboxLeaveProjectWarningDirective = (lightboxService, $template, $compile) -> + link = ($scope, $el, attrs) -> + lightboxService.open($el) + + return { + templateUrl: 'common/lightbox/lightbox-leave-project-warning.html', + link: link, + scope: true + } + +module.directive("tgLightboxLeaveProjectWarning", ["lightboxService", LightboxLeaveProjectWarningDirective]) diff --git a/app/coffee/modules/common/tags.coffee b/app/coffee/modules/common/tags.coffee index 0b8c8dfb..271d1e54 100644 --- a/app/coffee/modules/common/tags.coffee +++ b/app/coffee/modules/common/tags.coffee @@ -38,7 +38,7 @@ TagsDirective = -> parser = (v) -> return [] if not v - result = _(v.split(",")).map((x) -> _.str.trim(x)) + result = _(v.split(",")).map((x) -> _.trim(x)) return result.value() @@ -120,10 +120,13 @@ LbTagLineDirective = ($rs, $template, $compile) -> tag.style = "border-left: 5px solid #{tag.color}" html = $compile(templateTags(ctx))($scope) - $el.find("div.tags-container").html(html) + $el.find(".tags-container").html(html) - showSaveButton = -> $el.find(".save").removeClass("hidden") - hideSaveButton = -> $el.find(".save").addClass("hidden") + showSaveButton = -> + $el.find(".save").removeClass("hidden") + + hideSaveButton = -> + $el.find(".save").addClass("hidden") resetInput = -> $el.find("input").val("") @@ -179,7 +182,7 @@ LbTagLineDirective = ($rs, $template, $compile) -> event.preventDefault() saveInputTag() - $el.on "click", ".icon-delete", (event) -> + $el.on "click", ".remove-tag", (event) -> event.preventDefault() target = angular.element(event.currentTarget) @@ -348,7 +351,7 @@ TagLineDirective = ($rootScope, $repo, $rs, $confirm, $qqueue, $template, $compi hideAddTagButton() showInput() - $el.on "click", ".icon-delete", (event) -> + $el.on "click", ".remove-tag", (event) -> event.preventDefault() target = angular.element(event.currentTarget) diff --git a/app/coffee/modules/common/wisiwyg.coffee b/app/coffee/modules/common/wisiwyg.coffee index 98871836..e6fe3b0c 100644 --- a/app/coffee/modules/common/wisiwyg.coffee +++ b/app/coffee/modules/common/wisiwyg.coffee @@ -73,10 +73,16 @@ MarkitupDirective = ($rootscope, $rs, $selectedText, $template, $compile, $trans closePreviewMode() cancelablePromise = null + previewInProgress = false preview = -> + return if previewInProgress + + previewInProgress = true + markdownDomNode = element.parents(".markdown") markItUpDomNode = element.parents(".markItUp") + $rs.mdrender.render($scope.projectId, $model.$modelValue).then (data) -> html = previewTemplate({data: data.data}) html = $compile(html)($scope) @@ -84,6 +90,8 @@ MarkitupDirective = ($rootscope, $rs, $selectedText, $template, $compile, $trans markdownDomNode.append(html) markItUpDomNode.hide() + previewInProgress = false + markdown = element.closest(".markdown") markdown.on "mouseup.preview", ".preview", (event) -> diff --git a/app/coffee/modules/controllerMixins.coffee b/app/coffee/modules/controllerMixins.coffee index 4bfda2d1..18724b4b 100644 --- a/app/coffee/modules/controllerMixins.coffee +++ b/app/coffee/modules/controllerMixins.coffee @@ -46,7 +46,7 @@ class PageMixin @scope.roles = _.sortBy(roles, "order") computableRoles = _(@scope.project.members).map("role").uniq().value() @scope.computableRoles = _(roles).filter("computable") - .filter((x) -> _.contains(computableRoles, x.id)) + .filter((x) -> _.includes(computableRoles, x.id)) .value() loadUsersAndRoles: -> promise = @q.all([ diff --git a/app/coffee/modules/events.coffee b/app/coffee/modules/events.coffee index aed298b8..ef0bb491 100644 --- a/app/coffee/modules/events.coffee +++ b/app/coffee/modules/events.coffee @@ -59,7 +59,7 @@ class EventsService if not startswith(url, "ws:") and not startswith(url, "wss:") loc = @win.location scheme = if loc.protocol == "https:" then "wss:" else "ws:" - path = _.str.ltrim(url, "/") + path = _.trimStart(url, "/") url = "#{scheme}//#{loc.host}/#{path}" @.ws = new @win.WebSocket(url) diff --git a/app/coffee/modules/issues/lightboxes.coffee b/app/coffee/modules/issues/lightboxes.coffee index 995dd2ae..3be9bb6b 100644 --- a/app/coffee/modules/issues/lightboxes.coffee +++ b/app/coffee/modules/issues/lightboxes.coffee @@ -119,7 +119,11 @@ module.directive("tgLbCreateIssue", ["$tgRepo", "$tgConfirm", "$rootScope", "lig CreateBulkIssuesDirective = ($repo, $rs, $confirm, $rootscope, $loading, lightboxService) -> link = ($scope, $el, attrs) -> + form = null + $scope.$on "issueform:bulk", (ctx, projectId, status)-> + form.reset() if form + lightboxService.open($el) $scope.new = { projectId: projectId diff --git a/app/coffee/modules/issues/list.coffee b/app/coffee/modules/issues/list.coffee index c811b2e7..132e5ab1 100644 --- a/app/coffee/modules/issues/list.coffee +++ b/app/coffee/modules/issues/list.coffee @@ -461,14 +461,14 @@ IssuesFiltersDirective = ($q, $log, $location, $rs, $confirm, $loading, $templat showFilters = (title, type) -> $el.find(".filters-cats").hide() $el.find(".filter-list").removeClass("hidden") - $el.find("h2.breadcrumb").removeClass("hidden") - $el.find("h2 a.subfilter span.title").html(title) - $el.find("h2 a.subfilter span.title").prop("data-type", type) + $el.find(".breadcrumb").removeClass("hidden") + $el.find("h2 .subfilter .title").html(title) + $el.find("h2 .subfilter .title").prop("data-type", type) showCategories = -> $el.find(".filters-cats").show() $el.find(".filter-list").addClass("hidden") - $el.find("h2.breadcrumb").addClass("hidden") + $el.find(".breadcrumb").addClass("hidden") initializeSelectedFilters = (filters) -> selectedFilters = [] @@ -502,7 +502,7 @@ IssuesFiltersDirective = ($q, $log, $location, $rs, $confirm, $loading, $templat $el.find(".filter-list").html(html) getFiltersType = () -> - return $el.find("h2 a.subfilter span.title").prop('data-type') + return $el.find(".subfilter .title").prop('data-type') reloadIssues = () -> currentFiltersType = getFiltersType() @@ -617,7 +617,7 @@ IssuesFiltersDirective = ($q, $log, $location, $rs, $confirm, $loading, $templat toggleFilterSelection(type, id) - $el.on "click", ".filter-list .single-filter .icon-delete", (event) -> + $el.on "click", ".filter-list .single-filter .remove-filter", (event) -> event.preventDefault() event.stopPropagation() @@ -665,7 +665,7 @@ IssuesFiltersDirective = ($q, $log, $location, $rs, $confirm, $loading, $templat currentLoading.finish() $scope.filters.myFilters = filters - currentfilterstype = $el.find("h2 a.subfilter span.title").prop('data-type') + currentfilterstype = $el.find("h2 .subfilter .title").prop('data-type') if currentfilterstype == "myFilters" renderFilters($scope.filters.myFilters) diff --git a/app/coffee/modules/projects/create-project-restriction.directive.coffee b/app/coffee/modules/projects/create-project-restriction.directive.coffee new file mode 100644 index 00000000..66564563 --- /dev/null +++ b/app/coffee/modules/projects/create-project-restriction.directive.coffee @@ -0,0 +1,8 @@ +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 c5561ae8..774bb866 100644 --- a/app/coffee/modules/projects/lightboxes.coffee +++ b/app/coffee/modules/projects/lightboxes.coffee @@ -29,12 +29,16 @@ debounce = @.taiga.debounce module = angular.module("taigaProject") -CreateProject = ($rootscope, $repo, $confirm, $location, $navurls, $rs, $projectUrl, $loading, lightboxService, $cacheFactory, $translate, currentUserService) -> +CreateProject = ($rootscope, $repo, $confirm, $location, $navurls, $rs, $projectUrl, $loading, lightboxService, $cacheFactory, $translate, currentUserService, $auth) -> link = ($scope, $el, attrs) -> $scope.data = {} $scope.templates = [] currentLoading = null + $auth.refresh() + $scope.canCreatePrivateProjects = currentUserService.canCreatePrivateProjects() + $scope.canCreatePublicProjects = currentUserService.canCreatePublicProjects() + form = $el.find("form").checksley({"onlyOneErrorElement": true}) onSuccessSubmit = (response) -> @@ -58,10 +62,6 @@ CreateProject = ($rootscope, $repo, $confirm, $location, $navurls, $rs, $project selectors = [] for error_field in _.keys(response) selectors.push("[name=#{error_field}]") - $el.find(".active").removeClass("active") - error_step = $el.find(selectors.join(",")).first().parents(".wizard-step") - error_step.addClass("active") - $el.find('.progress-bar').removeClass().addClass('progress-bar').addClass(error_step.data("step")) submit = (event) => event.preventDefault() @@ -77,7 +77,9 @@ CreateProject = ($rootscope, $repo, $confirm, $location, $navurls, $rs, $project promise.then(onSuccessSubmit, onErrorSubmit) openLightbox = -> - $scope.data = {} + $scope.data = { + is_private: false + } if !$scope.templates.length $rs.projects.templates().then (result) => @@ -86,40 +88,7 @@ CreateProject = ($rootscope, $repo, $confirm, $location, $navurls, $rs, $project else $scope.data.creation_template = _.head(_.filter($scope.templates, (x) -> x.slug == "scrum")).id - $el.find(".active").removeClass("active") - $el.find(".create-step1").addClass("active") - lightboxService.open($el) - timeout 600, -> - $el.find(".progress-bar").addClass('step1') - - $el.on "click", ".button-next", (event) -> - event.preventDefault() - - current = $el.find(".active") - - valid = true - for field in form.fields - if current.find("[name=#{field.element.attr('name')}]").length - valid = field.validate() != false and valid - - if not valid - return - - next = current.next() - current.toggleClass('active') - next.toggleClass('active') - step = next.data('step') - $el.find('.progress-bar').removeClass().addClass('progress-bar').addClass(step) - - $el.on "click", ".button-prev", (event) -> - event.preventDefault() - current = $el.find(".active") - prev = current.prev() - current.toggleClass('active') - prev.toggleClass('active') - step = prev.data('step') - $el.find('.progress-bar').removeClass().addClass('progress-bar').addClass(step) submitButton = $el.find(".submit-button") @@ -145,7 +114,7 @@ CreateProject = ($rootscope, $repo, $confirm, $location, $navurls, $rs, $project module.directive("tgLbCreateProject", ["$rootScope", "$tgRepo", "$tgConfirm", "$location", "$tgNavUrls", "$tgResources", "$projectUrl", "$tgLoading", - "lightboxService", "$cacheFactory", "$translate", "tgCurrentUserService", CreateProject]) + "lightboxService", "$cacheFactory", "$translate", "tgCurrentUserService", "$tgAuth", CreateProject]) ############################################################################# diff --git a/app/coffee/modules/related-tasks.coffee b/app/coffee/modules/related-tasks.coffee index 19d90949..9095773f 100644 --- a/app/coffee/modules/related-tasks.coffee +++ b/app/coffee/modules/related-tasks.coffee @@ -62,7 +62,7 @@ RelatedTaskRowDirective = ($repo, $compile, $confirm, $rootscope, $loading, $tem else if event.keyCode == 27 renderView($model.$modelValue) - $el.on "click", ".icon-floppy", (event) -> + $el.on "click", ".save-task", (event) -> saveTask($model.$modelValue).then -> renderView($model.$modelValue) @@ -79,7 +79,7 @@ RelatedTaskRowDirective = ($repo, $compile, $confirm, $rootscope, $loading, $tem $el.html($compile(templateView({task: task, perms: perms}))($scope)) - $el.on "click", ".icon-edit", -> + $el.on "click", ".edit-task", -> renderEdit($model.$modelValue) $el.find('input').focus().select() @@ -170,10 +170,10 @@ RelatedTaskCreateFormDirective = ($repo, $compile, $confirm, $tgmodel, $loading, else if event.keyCode == 27 $scope.$apply () -> close() - $el.on "click", ".icon-delete", (event)-> + $el.on "click", ".icon-close", (event)-> $scope.$apply () -> close() - $el.on "click", ".icon-floppy", (event)-> + $el.on "click", ".icon-save", (event)-> createTask(newTask).then -> close() diff --git a/app/coffee/modules/resources.coffee b/app/coffee/modules/resources.coffee index fda8262b..c32a9f56 100644 --- a/app/coffee/modules/resources.coffee +++ b/app/coffee/modules/resources.coffee @@ -45,6 +45,7 @@ urls = { "user-voted": "/users/%s/voted" "user-watched": "/users/%s/watched" "user-contacts": "/users/%s/contacts" + "user-me": "/users/me" # User - Notification "permissions": "/permissions" @@ -73,6 +74,11 @@ urls = { "project-unlike": "/projects/%s/unlike" "project-watch": "/projects/%s/watch" "project-unwatch": "/projects/%s/unwatch" + "project-transfer-validate-token": "/projects/%s/transfer_validate_token" + "project-transfer-accept": "/projects/%s/transfer_accept" + "project-transfer-reject": "/projects/%s/transfer_reject" + "project-transfer-request": "/projects/%s/transfer_request" + "project-transfer-start": "/projects/%s/transfer_start" # Project Values - Choises "userstory-statuses": "/userstory-statuses" diff --git a/app/coffee/modules/resources/projects.coffee b/app/coffee/modules/resources/projects.coffee index a1745420..b4822b05 100644 --- a/app/coffee/modules/resources/projects.coffee +++ b/app/coffee/modules/resources/projects.coffee @@ -128,7 +128,11 @@ resourceProvider = ($config, $repo, $http, $urls, $auth, $q, $translate) -> catch response.data = {} response.status = evt.target.status - + if evt.target.getResponseHeader('Taiga-Info-Project-Is-Private') + response.headers = { + isPrivate: evt.target.getResponseHeader('Taiga-Info-Project-Is-Private') == 'True', + memberships: parseInt(evt.target.getResponseHeader('Taiga-Info-Project-Memberships')) + } defered.resolve(response) if response.status in [201, 202] defered.reject(response) diff --git a/app/coffee/modules/taskboard/lightboxes.coffee b/app/coffee/modules/taskboard/lightboxes.coffee index 9cc979d2..756d84e8 100644 --- a/app/coffee/modules/taskboard/lightboxes.coffee +++ b/app/coffee/modules/taskboard/lightboxes.coffee @@ -50,7 +50,6 @@ CreateEditTaskDirective = ($repo, $model, $rs, $rootscope, $loading, lightboxSer return $q.all(promises) deleteAttachments = (obj) -> - console.log attachmentsToDelete.toJS() promises = _.map attachmentsToDelete.toJS(), (attachment) -> return attachmentsService.delete("task", attachment.id) diff --git a/app/coffee/modules/team/main.coffee b/app/coffee/modules/team/main.coffee index 2dd37f04..a90b6181 100644 --- a/app/coffee/modules/team/main.coffee +++ b/app/coffee/modules/team/main.coffee @@ -95,6 +95,7 @@ class TeamController extends mixOf(taiga.Controller, taiga.PageMixin) @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 @@ -110,15 +111,18 @@ class TeamController extends mixOf(taiga.Controller, taiga.PageMixin) @scope.stats.totals = @scope.totals _processStat: (stat) -> - max = _.max(stat) - min = _.min(stat) - singleStat = _.map stat, (value, key) -> + max = _.max(_.toArray(stat)) + min = _.min(_.toArray(stat)) + + singleStat = Object() + for own key, value of stat if value == min - return [key, 0.1] - if value == max - return [key, 1] - return [key, (value * 0.5) / max] - singleStat = _.object(singleStat) + singleStat[key] = 0.1 + else if value == max + singleStat[key] = 1 + else + singleStat[key] = (value * 0.5) / max + return singleStat _processStats: (stats) -> @@ -131,6 +135,11 @@ class TeamController extends mixOf(taiga.Controller, taiga.PageMixin) return promise.then (project) => @.fillUsersAndRoles(project.members, project.roles) @.loadMembers() + + userRoles = _.map @scope.users, (user) -> user.role + + @scope.roles = _.filter @scope.roles, (role) -> userRoles.indexOf(role.id) != -1 + return @.loadMemberStats() module.controller("TeamController", TeamController) @@ -175,12 +184,13 @@ TeamMemberCurrentUserDirective = () -> return { templateUrl: "team/team-member-current-user.html" scope: { - projectId: "=projectid", + project: "=project", currentUser: "=currentuser", - stats: "=" - issuesEnabled: "=issuesenabled" - tasksEnabled: "=tasksenabled" - wikiEnabled: "=wikienabled" + stats: "=", + issuesEnabled: "=issuesenabled", + tasksEnabled: "=tasksenabled", + wikiEnabled: "=wikienabled", + owner: "=owner" } } @@ -200,10 +210,11 @@ TeamMembersDirective = () -> memberships: "=", filtersQ: "=filtersq", filtersRole: "=filtersrole", - stats: "=" - issuesEnabled: "=issuesenabled" - tasksEnabled: "=tasksenabled" - wikiEnabled: "=wikienabled" + stats: "=", + issuesEnabled: "=issuesenabled", + tasksEnabled: "=tasksenabled", + wikiEnabled: "=wikienabled", + owner: "=owner" } } @@ -214,31 +225,46 @@ module.directive("tgTeamMembers", TeamMembersDirective) ## Leave project Directive ############################################################################# -LeaveProjectDirective = ($repo, $confirm, $location, $rs, $navurls, $translate) -> +LeaveProjectDirective = ($repo, $confirm, $location, $rs, $navurls, $translate, lightboxFactory, currentUserService) -> link = ($scope, $el, $attrs) -> - $scope.leave = () -> + leaveConfirm = () -> leave_project_text = $translate.instant("TEAM.ACTION_LEAVE_PROJECT") confirm_leave_project_text = $translate.instant("TEAM.CONFIRM_LEAVE_PROJECT") $confirm.ask(leave_project_text, confirm_leave_project_text).then (response) => - promise = $rs.projects.leave($attrs.projectid) + promise = $rs.projects.leave($scope.project.id) promise.then => - response.finish() - $confirm.notify("success") - $location.path($navurls.resolve("home")) + currentUserService.loadProjects().then () -> + response.finish() + $confirm.notify("success") + $location.path($navurls.resolve("home")) promise.then null, (response) -> response.finish() $confirm.notify('error', response.data._error_message) + $scope.leave = () -> + if $scope.project.owner.id == $scope.user.id + lightboxFactory.create("tg-lightbox-leave-project-warning", { + class: "lightbox lightbox-leave-project-warning" + }, { + isCurrentUser: true, + project: $scope.project + }) + else + leaveConfirm() + return { - scope: {}, + scope: { + user: "=", + project: "=" + }, templateUrl: "team/leave-project.html", link: link } -module.directive("tgLeaveProject", ["$tgRepo", "$tgConfirm", "$tgLocation", "$tgResources", "$tgNavUrls", "$translate", +module.directive("tgLeaveProject", ["$tgRepo", "$tgConfirm", "$tgLocation", "$tgResources", "$tgNavUrls", "$translate", "tgLightboxFactory", "tgCurrentUserService", LeaveProjectDirective]) diff --git a/app/coffee/modules/user-settings/change-password.coffee b/app/coffee/modules/user-settings/change-password.coffee index 4f38b575..a08acb8c 100644 --- a/app/coffee/modules/user-settings/change-password.coffee +++ b/app/coffee/modules/user-settings/change-password.coffee @@ -63,9 +63,14 @@ module.controller("UserChangePasswordController", UserChangePasswordController) UserChangePasswordDirective = ($rs, $confirm, $loading, $translate) -> link = ($scope, $el, $attrs, ctrl) -> + form = new checksley.Form($el.find("form")) + submit = debounce 2000, (event) => event.preventDefault() + if not form.validate() + return + if $scope.newPassword1 != $scope.newPassword2 $confirm.notify('error', $translate.instant("CHANGE_PASSWORD.ERROR_PASSWORD_MATCH")) return diff --git a/app/coffee/modules/user-settings/lightboxes.coffee b/app/coffee/modules/user-settings/lightboxes.coffee index 4906c7e9..32f32bce 100644 --- a/app/coffee/modules/user-settings/lightboxes.coffee +++ b/app/coffee/modules/user-settings/lightboxes.coffee @@ -33,7 +33,7 @@ module = angular.module("taigaUserSettings") ## Delete User Lightbox Directive ############################################################################# -DeleteUserDirective = ($repo, $rootscope, $auth, $location, $navUrls, lightboxService) -> +DeleteUserDirective = ($repo, $rootscope, $auth, $location, $navUrls, lightboxService, $loading) -> link = ($scope, $el, $attrs) -> $scope.$on "deletelightbox:new", (ctx, user)-> lightboxService.open($el) @@ -42,29 +42,37 @@ DeleteUserDirective = ($repo, $rootscope, $auth, $location, $navUrls, lightboxSe $el.off() submit = -> + currentLoading = $loading() + .target(submitButton) + .start() + promise = $repo.remove($scope.user) promise.then (data) -> + currentLoading.finish() lightboxService.close($el) $auth.logout() $location.path($navUrls.resolve("login")) # FIXME: error handling? promise.then null, -> + currentLoading.finish() console.log "FAIL" - $el.on "click", ".button-red", (event) -> + $el.on "click", ".button-green", (event) -> event.preventDefault() lightboxService.close($el) - $el.on "click", ".button-green", debounce 2000, (event) -> + $el.on "click", ".button-red", debounce 2000, (event) -> event.preventDefault() submit() + submitButton = $el.find(".button-red") + return { link: link, templateUrl: "user/lightbox/lightbox-delete-account.html" } module.directive("tgLbDeleteUser", ["$tgRepo", "$rootScope", "$tgAuth", "$tgLocation", "$tgNavUrls", - "lightboxService", DeleteUserDirective]) + "lightboxService", "$tgLoading", DeleteUserDirective]) diff --git a/app/coffee/utils.coffee b/app/coffee/utils.coffee index 6ced2cc5..443bac59 100644 --- a/app/coffee/utils.coffee +++ b/app/coffee/utils.coffee @@ -59,16 +59,19 @@ mixOf = (base, mixins...) -> trim = (data, char) -> - return _.str.trim(data, char) + return _.trim(data, char) slugify = (data) -> - return _.str.slugify(data) - + return data.toString().toLowerCase().trim() + .replace(/\s+/g, '-') + .replace(/&/g, '-and-') + .replace(/[^\w\-]+/g, '') + .replace(/\-\-+/g, '-') unslugify = (data) -> if data - return _.str.capitalize(data.replace(/-/g, ' ')) + return _.capitalize(data.replace(/-/g, ' ')) return data @@ -114,7 +117,7 @@ toString = (value) -> joinStr = (str, coll) -> - return _.str.join(str, coll) + return coll.join(str) debounce = (wait, func) -> @@ -126,7 +129,7 @@ debounceLeading = (wait, func) -> startswith = (str1, str2) -> - return _.str.startsWith(str1, str2) + return _.startsWith(str1, str2) truncate = (str, maxLength, suffix="...") -> diff --git a/app/images/beta.png b/app/images/beta.png deleted file mode 100644 index 47a8a37e..00000000 Binary files a/app/images/beta.png and /dev/null differ diff --git a/app/index.jade b/app/index.jade index 71ac29b6..66d7d234 100644 --- a/app/index.jade +++ b/app/index.jade @@ -45,3 +45,4 @@ html(lang="en") script(src="/#{v}/js/libs.js") script(src="/#{v}/js/templates.js") script(src="/#{v}/js/app-loader.js") + include svg/sprite.svg diff --git a/app/locales/taiga/locale-ca.json b/app/locales/taiga/locale-ca.json index f8dfd9cc..57a3a9b5 100644 --- a/app/locales/taiga/locale-ca.json +++ b/app/locales/taiga/locale-ca.json @@ -41,7 +41,8 @@ "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!", "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", - "CAPSLOCK_WARNING": "Be careful! You're writing with capital letters and this input is case sensitive.", + "OWNER": "Project Owner", + "CAPSLOCK_WARNING": "Be careful! You are using capital letters in an input field that is case sensitive.", "FORM_ERRORS": { "DEFAULT_MESSAGE": "Aquest valor pareix invàlid.", "TYPE_EMAIL": "Deu ser un correu vàlid.", @@ -65,7 +66,9 @@ "MIN_CHECK": "You must select at least %s choices.", "MAX_CHECK": "Heu de seleccionar la opció %s o inferior.", "RANGE_CHECK": "Heu de seleccionar entre les opcions %s i %s.", - "EQUAL_TO": "Aquest valor hauria de ser el mateix." + "EQUAL_TO": "Aquest valor hauria de ser el mateix.", + "LINEWIDTH": "One or more lines is perhaps too long. Try to keep under %s characters.", + "PIKADAY": "Invalid date format, please use DD MMM YYYY (like 23 Mar 1984)" }, "PICKERDATE": { "FORMAT": "DD MMM YYYY", @@ -315,7 +318,8 @@ "PLACEHOLDER_FIELD": "Nom d'usuari o correu electrònic", "ACTION_RESET_PASSWORD": "Resetejar contrasenya", "LINK_CANCEL": "No, porta'm enrere, crec que ja ho recordo.", - "SUCCESS": "Mira el teu correu!
Hem enviat un correu amb les instrucciones per a setejar una nova contrasenya.", + "SUCCESS_TITLE": "Check your inbox!", + "SUCCESS_TEXT": "We sent you an email with the instructions to set a new password", "ERROR": "Segons els nostres Oompa Loompas, no estàs registrat encara." }, "CHANGE_PASSWORD": { @@ -373,7 +377,6 @@ "DEPRECATED_FILE": "Obsolet?", "ADD": "Afegeix un nou adjunt. {{maxFileSizeMsg}}", "DROP": "Deixa els adjunts ací", - "MAX_FILE_SIZE": "[Max. grandària: {{maxFileSize}}]", "SHOW_DEPRECATED": "+ mostra els adjunts obsolets", "HIDE_DEPRECATED": "- Amagar els adjunts obsolets", "COUNT_DEPRECATED": "({{ counter }} obsolet)", @@ -406,7 +409,9 @@ "TITLE": "Gestió de Membres", "PAGE_TITLE": "Afiliacions - {{projectName}}", "ADD_BUTTON": "+ Nou membre", - "ADD_BUTTON_TITLE": "Afegir nou membre" + "ADD_BUTTON_TITLE": "Afegir nou membre", + "LIMIT_USERS_WARNING_MESSAGE_FOR_ADMIN": "Unfortunately, this project has reached its limit of ({{members}}) allowed members.", + "LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "This project has reached its limit of ({{members}}) allowed members. If you would like to increase that limit please contact the administrator." }, "PROJECT_EXPORT": { "TITLE": "Exportar", @@ -428,6 +433,10 @@ "DISABLE": "Desactiva", "BACKLOG": "Backlog", "BACKLOG_DESCRIPTION": "Organitza les històries d'usuari per a mantindre una vista organitzada i prioritzada del treball.", + "NUMBER_SPRINTS": "Expected number of sprints", + "NUMBER_SPRINTS_HELP": "0 for an undetermined number", + "NUMBER_US_POINTS": "Expected total of story points", + "NUMBER_US_POINTS_HELP": "0 for an undetermined number", "KANBAN": "Kanban", "KANBAN_DESCRIPTION": "Organitza els projectes de un mode sencill amb aquest tauler", "ISSUES": "Incidències", @@ -435,9 +444,9 @@ "WIKI": "Wiki", "WIKI_DESCRIPTION": "Afegix, modifica o borra contingut en col3laboració amb altres. Aquest es el lloc correcte per a la teua documentació.", "MEETUP": "Trobar-se", - "MEETUP_DESCRIPTION": "Tria el teu sistema de videonconferéncia. Inclosos els desenvolupadors necessitan contacte cara a cara", + "MEETUP_DESCRIPTION": "Choose your videoconference system.", "SELECT_VIDEOCONFERENCE": "Selecciona un sistema de videconferència", - "SALT_CHAT_ROOM": "Pots afegir un code salt a la sala de xat", + "SALT_CHAT_ROOM": "Add a prefix to the chatroom name", "JITSI_CHAT_ROOM": "Jitsi", "APPEARIN_CHAT_ROOM": "AppearIn", "TALKY_CHAT_ROOM": "Talky", @@ -449,22 +458,31 @@ "PROJECT_DETAILS": "Detalls de projecte", "PROJECT_NAME": "Nom del projecte", "PROJECT_SLUG": "Slug de projecte", - "NUMBER_SPRINTS": "Nombre d'sprints (0 per a quantitat indetermindad)", - "NUMBER_US_POINTS": "Nombre de punts d'històries (0 per a una quantitat indeterminada)", "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", "PUBLIC_PROJECT": "Projecte públic", - "PUBLIC_PROJECT_DESC": "Els usuaris podràn trobar i vore el teu projecte", "PRIVATE_PROJECT": "Projecte privat", - "PRIVATE_PROJECT_DESC": "By default, this project will be hidden to the public", "PRIVATE_OR_PUBLIC": "What's the difference between public and private projects?", "DELETE": "Esborra aquest projecte", "LOGO_HELP": "The image will be scaled to 80x80px.", "CHANGE_LOGO": "Change logo", - "ACTION_USE_DEFAULT_LOGO": "Use default image" + "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", + "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", + "REQUEST_OWNERSHIP": "Request ownership", + "REQUEST_OWNERSHIP_CONFIRMATION_TITLE": "Do you want to become the new project owner?", + "REQUEST_OWNERSHIP_DESC": "Request that current project owner {{name}} transfer ownership of this project to you.", + "REQUEST_OWNERSHIP_BUTTON": "Petició", + "REQUEST_OWNERSHIP_SUCCESS": "We'll notify the project owner", + "CHANGE_OWNER": "Change owner", + "CHANGE_OWNER_SUCCESS_TITLE": "Ok, your request has been sent!", + "CHANGE_OWNER_SUCCESS_DESC": "We will notify you by email if the project ownership request is accepted or declined" }, "REPORTS": { "TITLE": "Informes", @@ -495,7 +513,8 @@ "ISSUE_ADD": "Afegix camps personalitzats en incidències", "FIELD_TYPE_TEXT": "Text", "FIELD_TYPE_MULTI": "Múltiples línies", - "FIELD_TYPE_DATE": "Data" + "FIELD_TYPE_DATE": "Data", + "FIELD_TYPE_URL": "Url" }, "PROJECT_VALUES": { "PAGE_TITLE": "{{sectionName}} - Valors de projecte - {{projectName}}", @@ -543,7 +562,7 @@ "COUNT_MEMBERS": "{{ role.members_count }} membres amb aquest rol", "TITLE_DELETE_ROLE": "Esborrar rol", "REPLACEMENT_ROLE": "Tots els usuaris amb aquest rol es canviaran a", - "WARNING_DELETE_ROLE": "Atenció, totes les estimacions del rol seràn esborrades", + "WARNING_DELETE_ROLE": "Be careful! All role estimations will be removed", "ERROR_DELETE_ALL": "No pots esborrar tots els valors", "EXTERNAL_USER": "Usuari extern" }, @@ -671,6 +690,24 @@ }, "SUBMENU_THIDPARTIES": { "TITLE": "Serveis" + }, + "PROJECT_TRANSFER": { + "DO_YOU_ACCEPT_PROJECT_OWNERNSHIP": "Would you like to become the new project owner?", + "PRIVATE": "Private", + "ACCEPTED_PROJECT_OWNERNSHIP": "Congratulations! You're now the new project owner.", + "REJECTED_PROJECT_OWNERNSHIP": "OK. We'll contact the current project owner", + "ACCEPT": "Acceptar", + "REJECT": "Reject", + "PROPOSE_OWNERSHIP": "{{owner}}, the current owner of the project {{project}} has asked that you become the new project owner.", + "ADD_COMMENT_QUESTION": "Would you like to send a question to the project owner?", + "ADD_COMMENT": "Would you like to add a comment for the project owner?", + "UNLIMITED_PROJECTS": "Unlimited", + "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" + }, + "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" } }, "USER": { @@ -731,6 +768,11 @@ "FANS_COUNTER_TITLE": "{total, plural, one{un fan} other{# fans}}", "WATCHERS_COUNTER_TITLE": "{total, plural, one{un seguidor} other{# seguidors}}", "MEMBERS_COUNTER_TITLE": "{total, plural, one{un membre} other{# membres}}", + "BLOCKED_PROJECT": { + "BLOCKED": "Blocked project", + "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", @@ -777,6 +819,7 @@ "CHANGE_PASSWORD": "Canvi de contrasenya", "DASHBOARD_TITLE": "Tauler", "DISCOVER_TITLE": "Discover trending projects", + "NEW_ITEM": "New", "DISCOVER": "Descobreix", "ACTION_REORDER": "Arrossega els elements per endreçar" }, @@ -791,7 +834,32 @@ "ERROR_TOO_MANY_REQUEST": "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 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" + "SYNC_SUCCESS": "El teu projecte s'ha importat correctament", + "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.", + "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 private 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": "The project that you are trying to import is private and has {{members}} members." + }, + "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." + } + } }, "LIKE_BUTTON": { "LIKE": "M'agrada", @@ -819,8 +887,11 @@ "DELETE_ACCOUNT": { "SECTION_NAME": "Esborrar compte de Taiga", "CONFIRM": "Segur que vols borrar el teu compte de Taiga? ", - "SUBTITLE": "Te trobarem a faltar! :-(", - "NEWSLETTER_LABEL_TEXT": "No vull rebre més el vostre butlletí de notícies" + "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! :(" }, "DELETE_PROJECT": { "TITLE": "Esborrar projecte", @@ -876,7 +947,25 @@ }, "CREATE_MEMBER": { "PLACEHOLDER_INVITATION_TEXT": "(Opcional) Afegix un text personalizat a la invitació. Dis-li algo divertit als nous membres. ;-)", - "PLACEHOLDER_TYPE_EMAIL": "Escriu un correu" + "PLACEHOLDER_TYPE_EMAIL": "Escriu un correu", + "LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "Unfortunately, this project can't have more than {{maxMembers}} members.
If you would like to increase the current limit, please contact the administrator.", + "LIMIT_USERS_WARNING_MESSAGE": "Unfortunately, this project can't have more than {{maxMembers}} members." + }, + "LEAVE_PROJECT_WARNING": { + "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" + }, + "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.", + "BUTTON": "Request project owner change" + } + }, + "CHANGE_OWNER": { + "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" } }, "US": { @@ -1304,12 +1393,18 @@ } }, "WIZARD": { - "SECTION_TITLE_CHOOSE_TEMPLATE": "Tria una plantilla", - "CHOOSE_TEMPLATE_TEXT": "Quina plantilla encaixa millor al teu projecte?", "SECTION_TITLE_CREATE_PROJECT": "Crear projecte", "CREATE_PROJECT_TEXT": "Nou projecte. Qué il·lusió!", - "PROGRESS_TEMPLATE_SELECTION": "Selecció de plantilla", - "PROGRESS_NAME_DESCRIPTION": "Nom i descripció" + "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}}", diff --git a/app/locales/taiga/locale-de.json b/app/locales/taiga/locale-de.json index d29610f4..92639637 100644 --- a/app/locales/taiga/locale-de.json +++ b/app/locales/taiga/locale-de.json @@ -24,38 +24,39 @@ "UNBLOCK": "Blockierung aufheben", "UNBLOCK_TITLE": "Unblock this item", "BLOCKED_NOTE": "Why is this blocked?", - "BLOCKED_REASON": "Bitte erklären Sie den Grund ", + "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! ", + "BETA": "Wir sind auf beta!", "ONE_ITEM_LINE": "Ein Eintrag pro Zeile...", "NEW_BULK": "Neue Massenerstellung", "RELATED_TASKS": "Verbundene Aufgaben", "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": "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!", "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", - "CAPSLOCK_WARNING": "Achtung! SIe schreiben in Großbuchstaben und bei dieser Eingabe ist Groß- und Kleinschreibung zu beachten", + "OWNER": "Project Owner", + "CAPSLOCK_WARNING": "Be careful! You are using capital letters in an input field that is case sensitive.", "FORM_ERRORS": { - "DEFAULT_MESSAGE": "Dieser Wert scheint ungültig zu sein. ", + "DEFAULT_MESSAGE": "Dieser Wert scheint ungültig zu sein.", "TYPE_EMAIL": "Dieser Wert sollte eine gültige E-Mail Adresse enthalten.", - "TYPE_URL": "Dieser Wert sollte eine gültige URL enthalten. ", - "TYPE_URLSTRICT": "Dieser Wert sollte eine gültige URL enthalten. ", - "TYPE_NUMBER": "Dieser Wert sollte eine gültige Nummer enthalten. ", + "TYPE_URL": "Dieser Wert sollte eine gültige URL enthalten.", + "TYPE_URLSTRICT": "Dieser Wert sollte eine gültige URL enthalten.", + "TYPE_NUMBER": "Dieser Wert sollte eine gültige Nummer enthalten.", "TYPE_DIGITS": "Dieser Wert sollte Ziffern enthalten.", "TYPE_DATEISO": "Dieser Wert sollte ein gültiges Datum sein (JJJJ-MM-TT)", - "TYPE_ALPHANUM": "Dieser Wert sollte alphanumersich sein. ", + "TYPE_ALPHANUM": "Dieser Wert sollte alphanumersich sein.", "TYPE_PHONE": "Dieser Wert sollte eine gültige Telefonnummer enthalten.", - "NOTNULL": "Dieser Wert darf nicht leer sein. ", - "NOT_BLANK": "Dieser Wert darf nicht leer bleiben. ", + "NOTNULL": "Dieser Wert darf nicht leer sein.", + "NOT_BLANK": "Dieser Wert darf nicht leer bleiben.", "REQUIRED": "Diese Angabe ist erforderlich", - "REGEXP": "Dieser Wert scheint ungültig zu sein. ", + "REGEXP": "Dieser Wert scheint ungültig zu sein.", "MIN": "Dieser Wert sollte größer oder gleich %s sein.", "MAX": "Dieser Wert sollte niedriger oder gleich %s sein.", "RANGE": "Der Wert sollte zwischen %s und %s liegen.", @@ -65,14 +66,16 @@ "MIN_CHECK": "Sie müssen mindestens %s auswählen.", "MAX_CHECK": "Wählen Sie %s oder weniger.", "RANGE_CHECK": "Wählen Sie zwischen %s und %s", - "EQUAL_TO": "Dieser Wert sollte der gleiche sein." + "EQUAL_TO": "Dieser Wert sollte der gleiche sein.", + "LINEWIDTH": "One or more lines is perhaps too long. Try to keep under %s characters.", + "PIKADAY": "Invalid date format, please use DD MMM YYYY (like 23 Mar 1984)" }, "PICKERDATE": { "FORMAT": "DD MMM YYYY", "IS_RTL": "falsch", "FIRST_DAY_OF_WEEK": "1", "PREV_MONTH": "Vorheriger Monat", - "NEXT_MONTH": "Nächster Monat ", + "NEXT_MONTH": "Nächster Monat", "MONTHS": { "JAN": "Januar", "FEB": "Februar", @@ -85,7 +88,7 @@ "SEP": "September", "OCT": "Oktober", "NOV": "November", - "DEC": "Diciember" + "DEC": "Dezember" }, "WEEK_DAYS": { "SUN": "Sonntag", @@ -97,13 +100,13 @@ "SAT": "Samstag" }, "WEEK_DAYS_SHORT": { - "SUN": "Son", - "MON": "Mon", - "TUE": "Die", - "WED": "Mit", - "THU": "Don", - "FRI": "Fre", - "SAT": "Sam" + "SUN": "So", + "MON": "Mo", + "TUE": "Di", + "WED": "Mi", + "THU": "Do", + "FRI": "Fr", + "SAT": "Sa" } }, "SEE_USER_PROFILE": "Profil von {{username }} ansehen", @@ -117,7 +120,7 @@ }, "DESCRIPTION": { "EMPTY": "Bitte geben Sie eine Beschreibung ein...", - "NO_DESCRIPTION": "Noch keine Beschreibung " + "NO_DESCRIPTION": "Noch keine Beschreibung" }, "FIELDS": { "SUBJECT": "Thema", @@ -144,13 +147,13 @@ }, "ASSIGNED_TO": { "NOT_ASSIGNED": "Nicht zugeordnet", - "ASSIGN": "Assign", + "ASSIGN": "Zuweisen", "DELETE_ASSIGNMENT": "Zuordnung löschen", "REMOVE_ASSIGNED": "Zugewiesene entfernen", - "TOO_MANY": "...zu viele Benutzer. Filtern Sie! ", + "TOO_MANY": "...zu viele Benutzer. Filtern Sie!", "CONFIRM_UNASSIGNED": "Möchten dies wirklich ohne eine Zuordnung verlassen?", "TITLE_ACTION_EDIT_ASSIGNMENT": "Zuordnungen bearbeiten", - "SELF": "Assign to me" + "SELF": "An mich zuweisen" }, "STATUS": { "CLOSED": "Geschlossen", @@ -184,7 +187,7 @@ "SAVE": "Benutzerdefiniertes Feld speichern", "EDIT": "Benutzerdefiniertes Feld bearbeiten", "DELETE": "Benutzerattribut löschen", - "CONFIRM_DELETE": "Remeber that all values in this custom field will be deleted.\n Are you sure you want to continue?" + "CONFIRM_DELETE": "Alle Werte in benutzerdefinierten Feldern werden gelöscht.\n Sind Sie sicher, dass Sie fortfahren wollen?" }, "FILTERS": { "TITLE": "Filter", @@ -242,7 +245,7 @@ "NAME": "Aufgaben", "VIEW_TASKS": "Aufgaben ansehen", "ADD_TASKS": "Aufgaben hinzufügen", - "MODIFY_TASKS": "Aufgaben ändern ", + "MODIFY_TASKS": "Aufgaben ändern", "DELETE_TASKS": "Aufgaben löschen" }, "ISSUES": { @@ -265,12 +268,12 @@ }, "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. " + "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": { "PAGE_TITLE": "Login - Taiga", - "PAGE_DESCRIPTION": "Melden Sie sich bei Taiga an, einer 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. " + "PAGE_DESCRIPTION": "Melden Sie sich bei Taiga an, einer 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." }, "AUTH": { "INVITED_YOU": "hat Sie zum Projekt eingeladen", @@ -289,11 +292,11 @@ }, "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.)", - "SUCCESS": "Herzlich willkommen bei Taiga, unsere Helferlein freuen sich. " + "SUCCESS": "Herzlich willkommen bei Taiga, unsere Helferlein freuen sich." }, "REGISTER": { "PAGE_TITLE": "Registrieren - Taiga", - "PAGE_DESCRIPTION": "Erstellee Dein Benutzerkonto in Taiga, einer 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. " + "PAGE_DESCRIPTION": "Erstelle Dein Benutzerkonto in Taiga, einer 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." }, "REGISTER_FORM": { "TITLE": "Ein neues Taiga Benutzerkonto registrieren (kostenlos)", @@ -311,12 +314,13 @@ }, "FORGOT_PASSWORD_FORM": { "TITLE": "Huch, hast Du Dein Passwort vergessen?", - "SUBTITLE": "Gib Deinen Benutzernamen oder Deine E-Mail-Adresse ein, um einen neuen zu erhalten. ", + "SUBTITLE": "Gib Deinen Benutzernamen oder Deine E-Mail-Adresse ein, um einen neuen zu erhalten.", "PLACEHOLDER_FIELD": "Benutzername oder E-Mail-Adresse", "ACTION_RESET_PASSWORD": "Passwort zurücksetzen", - "LINK_CANCEL": "Nein, bring mich zurück. Ich denke, ich erinnere mich daran. ", - "SUCCESS": "Sehen Sie in Ihren Posteingang!
Wir haben Ihnen eine E-Mail mit einer Anleitung gesendet, um ein neues Passwort festzulegen.", - "ERROR": "Laut unseren Helferlein sind Sie bislang noch nicht registriert. " + "LINK_CANCEL": "Nein, bring mich zurück. Ich denke, ich erinnere mich daran.", + "SUCCESS_TITLE": "Check your inbox!", + "SUCCESS_TEXT": "We sent you an email with the instructions to set a new password", + "ERROR": "Laut unseren Helferlein sind Sie bislang noch nicht registriert." }, "CHANGE_PASSWORD": { "PAGE_TITLE": "Ändere Dein Passwort - Taiga", @@ -331,36 +335,36 @@ "ERROR_PASSWORD_MATCH": "Die Passwörter stimmen nicht überein" }, "CHANGE_PASSWORD_RECOVERY_FORM": { - "TITLE": "Erstellen Sie einen neuen Taiga Pass", - "SUBTITLE": "Und hey, es empfiehlt sich, mehr eisenreiche Nahrung zu sich zu nehmen - die ist gut für's Gehirn :P ", + "TITLE": "Erstellen Sie einen neues Passwort", + "SUBTITLE": "Und hey, es empfiehlt sich, mehr eisenreiche Nahrung zu sich zu nehmen - die ist gut für's Gehirn :P", "PLACEHOLDER_NEW_PASSWORD": "Neues Passwort", - "PLACEHOLDER_RE_TYPE_NEW_PASSWORD": "Wiederholen Sie die Eingabe des neuen Passworts ", + "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." }, "INVITATION": { "PAGE_TITLE": "Einladung Annahme - Taiga", - "PAGE_DESCRIPTION": "Nehmen Sie die Einladung an und treten Sie einem Projekt in Taiga bei, einer 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. " + "PAGE_DESCRIPTION": "Nehmen Sie die Einladung an und treten Sie einem Projekt in Taiga bei, einer 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." }, "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. " + "ERROR": "Laut unseren Helferlein sind Sie noch nicht registriert, oder Sie haben ein ungültiges Passwort eingegeben." }, "HOME": { "PAGE_TITLE": "Home - Taiga", - "PAGE_DESCRIPTION": "Die Taiga Homepage mit Ihren wichtigsten Projekten und all Ihren zugeordneten und beobachteten User-Stories, Aufgaben und Tickets. ", + "PAGE_DESCRIPTION": "Die Taiga Homepage mit Ihren wichtigsten Projekten und all Ihren zugeordneten und beobachteten User-Stories, Aufgaben und Tickets.", "EMPTY_WORKING_ON": "Hier sieht’s ziemlich leer aus, oder? Beginne deine Arbeit mit Taiga und wir zeigen dir hier die Stories, Tasks und Issues an denen du arbeitest.", - "EMPTY_WATCHING": "Follow User Stories, Tasks, Issues in your projects and be notified about its changes :)", + "EMPTY_WATCHING": "Folge User Stories, Tasks, Issues in deinem Projekt und erhalte Benachrichtigungen, wenn sich etwas ändert. :)", "EMPTY_PROJECT_LIST": "Sie haben noch keine Projekte", "WORKING_ON_SECTION": "Zuletzt bearbeitet", "WATCHING_SECTION": "Beobachtet", - "DASHBOARD": "Projects Dashboard" + "DASHBOARD": "ProjeKte Dashboard" }, "PROJECTS": { "PAGE_TITLE": "Meine Projekte - Taiga", - "PAGE_DESCRIPTION": "Eine Liste mit all Deinen Projekten. Du kannst sie ordnen oder ein Neues anlegen. ", + "PAGE_DESCRIPTION": "Eine Liste mit all Deinen Projekten. Du kannst sie ordnen oder ein Neues anlegen.", "MY_PROJECTS": "Meine Projekte" }, "ATTACHMENT": { @@ -372,8 +376,7 @@ "DEPRECATED": "(verworfen)", "DEPRECATED_FILE": "Verworfen?", "ADD": "Neuen Anhang hinzufügen. {{maxFileSizeMsg}}", - "DROP": "Drop attachments here!", - "MAX_FILE_SIZE": "[Max. Größe: {{maxFileSize}}]", + "DROP": "Ziehe Anhänge hierher!", "SHOW_DEPRECATED": "+ verworfene Anhänge zeigen", "HIDE_DEPRECATED": "- verworfene Anhänge verbergen", "COUNT_DEPRECATED": "({{ counter }} verworfen)", @@ -406,38 +409,44 @@ "TITLE": "Mitglieder verwalten", "PAGE_TITLE": "Mitgliedschaften - {{projectName}}", "ADD_BUTTON": "+ Neues Mitglied", - "ADD_BUTTON_TITLE": "Neues Mitglied hinzufügen" + "ADD_BUTTON_TITLE": "Neues Mitglied hinzufügen", + "LIMIT_USERS_WARNING_MESSAGE_FOR_ADMIN": "Unfortunately, this project has reached its limit of ({{members}}) allowed members.", + "LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "This project has reached its limit of ({{members}}) allowed members. If you would like to increase that limit please contact the administrator." }, "PROJECT_EXPORT": { "TITLE": "Exportieren", - "SUBTITLE": "Exportieren Sie Ihr Projekt, um ein Backup durchzuführen, oder ein neues, darauf basierendes, zu erstellen. ", + "SUBTITLE": "Exportieren Sie Ihr Projekt, um ein Backup durchzuführen, oder ein neues, darauf basierendes, zu erstellen.", "EXPORT_BUTTON": "Exportieren", "EXPORT_BUTTON_TITLE": "Exportieren Sie Ihr Projekt", "LOADING_TITLE": "Wir erzeugen die Exportdatei", - "DUMP_READY": "Ihre Export-Datei ist fertig! ", + "DUMP_READY": "Ihre Export-Datei ist fertig!", "LOADING_MESSAGE": "Bitte lassen Sie diese Seite geöffnet!", "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.", + "ERROR_MESSAGE": "Unsere Helferlein haben Probleme, Ihre Export-Datei zu erstellen: {{message}}" }, "MODULES": { "TITLE": "Module", "ENABLE": "Aktivieren", "DISABLE": "Deaktivieren", "BACKLOG": "Auftragsliste", - "BACKLOG_DESCRIPTION": "Verwalten Sie Ihre User-Stories, um einen organisierten Überblick der anstehenden und priorisierten Aufgaben zu erhalten. ", + "BACKLOG_DESCRIPTION": "Verwalten Sie Ihre User-Stories, um einen organisierten Überblick der anstehenden und priorisierten Aufgaben zu erhalten.", + "NUMBER_SPRINTS": "Expected number of sprints", + "NUMBER_SPRINTS_HELP": "0 for an undetermined number", + "NUMBER_US_POINTS": "Expected total of story points", + "NUMBER_US_POINTS_HELP": "0 for an undetermined number", "KANBAN": "Kanban", "KANBAN_DESCRIPTION": "Organisieren Sie Ihr Projekt auf übersichtliche Art.", "ISSUES": "Tickets", - "ISSUES_DESCRIPTION": "Verfolgen Sie Fehler, Fragen und Verbesserungen, die mit Ihrem Projekt verbunden sind. Vermissen Sie nichts! ", + "ISSUES_DESCRIPTION": "Verfolgen Sie Fehler, Fragen und Verbesserungen, die mit Ihrem Projekt verbunden sind. Vermissen Sie nichts!", "WIKI": "Wiki", "WIKI_DESCRIPTION": "Fügen Sie Inhalte hinzu, ändern oder löschen Sie sie in Zusammenarbeit mit anderen. Dies ist der richtige Ort für Ihre Projektdokumentation.", "MEETUP": "Zusammentreffen", - "MEETUP_DESCRIPTION": "Wählen Sie Ihr Videokonferenzsystem. Auch Entwickler brauchen Kontakt von Angesicht zu Angesicht. ", + "MEETUP_DESCRIPTION": "Choose your videoconference system.", "SELECT_VIDEOCONFERENCE": "Wählen Sie ein Videokonferenzsystem", - "SALT_CHAT_ROOM": "Wenn Sie möchten, können Sie einen Salt Code zum Namen des Chatrooms hinzufügen", + "SALT_CHAT_ROOM": "Add a prefix to the chatroom name", "JITSI_CHAT_ROOM": "Jitsi", "APPEARIN_CHAT_ROOM": "Erscheint in", "TALKY_CHAT_ROOM": "Gesprächig", @@ -449,36 +458,45 @@ "PROJECT_DETAILS": "Projekt Details", "PROJECT_NAME": "Projektname", "PROJECT_SLUG": "Projekt Slug", - "NUMBER_SPRINTS": "Anzahl von Sprints (0 für unbegrenzte Anzahl)", - "NUMBER_US_POINTS": "Anzahl an US Points (0 für unbegrenzte Anzahl)", "TAGS": "Schlagwörter", "DESCRIPTION": "Beschreibung", "RECRUITING": "Is this project looking for people?", "RECRUITING_MESSAGE": "Who are you looking for?", "RECRUITING_PLACEHOLDER": "Define the profiles you are looking for", "PUBLIC_PROJECT": "Öffentliches Projekt", - "PUBLIC_PROJECT_DESC": "Users will be able to find and view your project", "PRIVATE_PROJECT": "Privates Projekt", - "PRIVATE_PROJECT_DESC": "By default, this project will be hidden to the public", - "PRIVATE_OR_PUBLIC": "What's the difference between public and private projects?", + "PRIVATE_OR_PUBLIC": "Was ist der Unterschied zwischen öffentlichen und privaten Projekten?", "DELETE": "Dieses Projekt löschen", - "LOGO_HELP": "The image will be scaled to 80x80px.", - "CHANGE_LOGO": "Change logo", - "ACTION_USE_DEFAULT_LOGO": "Use default image" + "LOGO_HELP": "Das Bild wird auf 80x80px skaliert.", + "CHANGE_LOGO": "Logo ändern", + "ACTION_USE_DEFAULT_LOGO": "Nutze Standardbild", + "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", + "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", + "REQUEST_OWNERSHIP": "Request ownership", + "REQUEST_OWNERSHIP_CONFIRMATION_TITLE": "Do you want to become the new project owner?", + "REQUEST_OWNERSHIP_DESC": "Request that current project owner {{name}} transfer ownership of this project to you.", + "REQUEST_OWNERSHIP_BUTTON": "Anfrage", + "REQUEST_OWNERSHIP_SUCCESS": "We'll notify the project owner", + "CHANGE_OWNER": "Change owner", + "CHANGE_OWNER_SUCCESS_TITLE": "Ok, your request has been sent!", + "CHANGE_OWNER_SUCCESS_DESC": "We will notify you by email if the project ownership request is accepted or declined" }, "REPORTS": { "TITLE": "Berichte", - "SUBTITLE": "Exportieren Sie Ihre Projektdaten in CSV Format und erstellen Sie Ihre eigenen Berichte. ", + "SUBTITLE": "Exportieren Sie Ihre Projektdaten in CSV Format und erstellen Sie Ihre eigenen Berichte.", "DESCRIPTION": "Laden Sie eine CSV-Datei herunter oder kopieren Sie die generierte URL und öffnen Sie sie in Ihrem Lieblingstexteditor oder Tabellenkalkulationsprogramm um Ihre eigenen Projektdaten Berichte zu erstellen. So können Sie Ihre Daten einfach visualisieren und analysieren.", "HELP": "Wie kann ich dies in meiner eigenen Tabellenkalkulation nutzen?", "REGENERATE_TITLE": "Die URL ändern", "REGENERATE_SUBTITLE": "Sie sind im Begriff, die CSV data access URL zu ändern. Die vorherige URL wird deaktiviert. Sind Sie sicher?" }, "CSV": { - "SECTION_TITLE_US": "User-Stories Berichte ", + "SECTION_TITLE_US": "User-Stories Berichte", "SECTION_TITLE_TASK": "Aufgabenberichte", - "SECTION_TITLE_ISSUE": "Ticket Berichte ", - "DOWNLOAD": "CSV herunterladen ", + "SECTION_TITLE_ISSUE": "Ticket Berichte", + "DOWNLOAD": "CSV herunterladen", "URL_FIELD_PLACEHOLDER": "Bitte erstellen Sie die CSV URL neu", "TITLE_REGENERATE_URL": "Erstellen Sie die CSV URL neu", "ACTION_GENERATE_URL": "URL erzeugen", @@ -486,16 +504,17 @@ }, "CUSTOM_FIELDS": { "TITLE": "Benutzerfelder", - "SUBTITLE": "Spezifizieren Sie die Benutzerfelder für Ihre User-Stories, Aufgaben und Tickets. ", + "SUBTITLE": "Spezifizieren Sie die Benutzerfelder für Ihre User-Stories, Aufgaben und Tickets.", "US_DESCRIPTION": "Benutzerdefinierte Felder der User-Story", "US_ADD": "Benutzerdefiniertes Feld bei User-Stories hinzufügen", "TASK_DESCRIPTION": "Aufgaben benutzerdefinierte Felder", "TASK_ADD": "Fügen Sie ein benutzerdefiniertes Feld bei Aufgaben hinzu", "ISSUE_DESCRIPTION": "Tickets benutzerdefinierte Felder", - "ISSUE_ADD": "Fügen Sie den Tickets ein benutzerdefiniertes Feld hinzu ", + "ISSUE_ADD": "Fügen Sie den Tickets ein benutzerdefiniertes Feld hinzu", "FIELD_TYPE_TEXT": "Text", "FIELD_TYPE_MULTI": "Mehrzeilig", - "FIELD_TYPE_DATE": "Datum" + "FIELD_TYPE_DATE": "Datum", + "FIELD_TYPE_URL": "Url" }, "PROJECT_VALUES": { "PAGE_TITLE": "{{sectionName}} - Projekt Werte - {{projectName}}", @@ -522,7 +541,7 @@ }, "PROJECT_VALUES_STATUS": { "TITLE": "Status", - "SUBTITLE": "Spezifizieren Sie die Status, die Ihre User-Stories, Aufgaben und Tickets durchlaufen werden. ", + "SUBTITLE": "Spezifizieren Sie die Status, die Ihre User-Stories, Aufgaben und Tickets durchlaufen werden.", "US_TITLE": "User-Story Status", "TASK_TITLE": "Aufgaben-Status", "ISSUE_TITLE": "Ticket-Status" @@ -535,21 +554,21 @@ }, "ROLES": { "PAGE_TITLE": "Rollen - {{projectName}}", - "WARNING_NO_ROLE": "Beachten Sie, keine Rolle in Ihrem Projekt wird in der Lage sein, die Punktevergabe für User-Stories einzuschätzen. ", - "HELP_ROLE_ENABLED": "Wenn Sie dies freischalten, werden Mitglieder, denen diese Rolle zugewiesen ist, in der Lage sein, die Punktevergabe für User-Stories vorzunehmen. ", + "WARNING_NO_ROLE": "Beachten Sie, keine Rolle in Ihrem Projekt wird in der Lage sein, die Punktevergabe für User-Stories einzuschätzen.", + "HELP_ROLE_ENABLED": "Wenn Sie dies freischalten, werden Mitglieder, denen diese Rolle zugewiesen ist, in der Lage sein, die Punktevergabe für User-Stories vorzunehmen.", "DISABLE_COMPUTABLE_ALERT_TITLE": "Deaktiviere Estimatepoints für diese Rolle", "DISABLE_COMPUTABLE_ALERT_SUBTITLE": "Wenn du die Estimatepoints für die Rolle {{roleName}} deaktivierst, werden alle bisherigen gelöscht", "DISABLE_COMPUTABLE_ALERT_MESSAGE": "Bist du sicher, dass in dieser Rolle Estimatepoints deaktivieren möchtest?", "COUNT_MEMBERS": "{{ role.members_count }} Mitglieder mit dieser Rolle", "TITLE_DELETE_ROLE": "Rolle löschen", - "REPLACEMENT_ROLE": "Alle Benutzer mit dieser Rolle werden verschoben nach ", - "WARNING_DELETE_ROLE": "Vorsicht, alle Rollen Bewertungen werden entfernt", + "REPLACEMENT_ROLE": "Alle Benutzer mit dieser Rolle werden verschoben nach", + "WARNING_DELETE_ROLE": "Be careful! All role estimations will be removed", "ERROR_DELETE_ALL": "Sie können nicht alle Werte löschen", "EXTERNAL_USER": "Externer Benutzer" }, "THIRD_PARTIES": { "SECRET_KEY": "Geheimschlüssel", - "PAYLOAD_URL": "Payload URL ", + "PAYLOAD_URL": "Payload URL", "VALID_IPS": "Gültige Quell-IPs (getrennt von ,)" }, "BITBUCKET": { @@ -574,7 +593,7 @@ "TYPE_NAME": "Servicename...", "TYPE_PAYLOAD_URL": "Geben Sie die Service Payload URL ein", "TYPE_SERVICE_SECRET": "Sicherheitsschlüssel...", - "SAVE": "Webhook sichern ", + "SAVE": "Webhook sichern", "CANCEL": "Webhook beenden", "SHOW_HISTORY": "(Chronik anzeigen)", "TEST": "Webhook Test", @@ -615,18 +634,18 @@ "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. ", + "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}}" }, "DEFAULT_VALUES": { "LABEL_POINTS": "Vorgegebener Wert für Punkteauswahl", - "LABEL_US": "Vorgegebener Wert für User-Story-Status Auswahl ", + "LABEL_US": "Vorgegebener Wert für User-Story-Status Auswahl", "LABEL_TASK_STATUS": "Vorgegebene Auswahl für den Aufgaben-Status", "LABEL_PRIORITY": "Vorgegebener Wert für Prioritätsauswahl", "LABEL_SEVERITY": "Vorgegebener Wert für Gewichtungsauswahl", - "LABEL_ISSUE_TYPE": "Vorgegebener Wert für Ticketartauswahl ", + "LABEL_ISSUE_TYPE": "Vorgegebener Wert für Ticketartauswahl", "LABEL_ISSUE_STATUS": "Vorgegebene Auswahl für den Ticket-Status" }, "STATUS": { @@ -642,7 +661,7 @@ "PLACEHOLDER_WRITE_NAME": "Benennen Sie den neuen Status" }, "MENU": { - "TITLE": "Administrator ", + "TITLE": "Administrator", "PROJECT": "Projekt", "ATTRIBUTES": "Attribute", "MEMBERS": "Mitglieder", @@ -671,6 +690,24 @@ }, "SUBMENU_THIDPARTIES": { "TITLE": "Dienste" + }, + "PROJECT_TRANSFER": { + "DO_YOU_ACCEPT_PROJECT_OWNERNSHIP": "Would you like to become the new project owner?", + "PRIVATE": "Private", + "ACCEPTED_PROJECT_OWNERNSHIP": "Congratulations! You're now the new project owner.", + "REJECTED_PROJECT_OWNERNSHIP": "OK. We'll contact the current project owner", + "ACCEPT": "Akzeptieren", + "REJECT": "Reject", + "PROPOSE_OWNERSHIP": "{{owner}}, the current owner of the project {{project}} has asked that you become the new project owner.", + "ADD_COMMENT_QUESTION": "Would you like to send a question to the project owner?", + "ADD_COMMENT": "Would you like to add a comment for the project owner?", + "UNLIMITED_PROJECTS": "Unlimited", + "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" + }, + "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" } }, "USER": { @@ -683,11 +720,11 @@ "PROJECTS_EMPTY": "{{username}} besitzt noch keine Projekte", "CONTACTS": "Kontakte", "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 ", + "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": "Zeitlinie", "ACTIVITY_TAB_TITLE": "Alle Aktivitäten dieses Benutzers anzeigen", "PROJECTS_TAB": "Projekte", "PROJECTS_TAB_TITLE": "Liste alle Projekte auf, bei denen der Benutzer Mitglied ist", @@ -704,7 +741,7 @@ "PROFILE_SIDEBAR": { "TITLE": "Dein Profil", "DESCRIPTION": "Da andere Mitglieder sehen, dass sie ebenfalls an einem Projekt arbeiten wäre es schön, wenn Sie ein paar Informationen zu Ihrer Person angeben.", - "ADD_INFO": "Bio bearbeiten" + "ADD_INFO": "Biographie bearbeiten" }, "PROFILE_FAVS": { "FILTER_INPUT_PLACEHOLDER": "Geben sie etwas ein...", @@ -727,19 +764,24 @@ "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": "This project is looking for people", - "FANS_COUNTER_TITLE": "{total, plural, one{ein Fan} other{# Fans}}", - "WATCHERS_COUNTER_TITLE": "{total, plural, one{ein Beobachter} other{# Beobachter}}", - "MEMBERS_COUNTER_TITLE": "{total, plural, one{one member} other{# members}}", + "LOOKING_FOR_PEOPLE": "Dieses Projekt sucht nach Mitarbeitern", + "FANS_COUNTER_TITLE": "{total, plural, one{ein Fan} andere{# Fans}}", + "WATCHERS_COUNTER_TITLE": "{total, plural, one{ein Beobachter} andere{# Beobachter}}", + "MEMBERS_COUNTER_TITLE": "{total, plural, one{one member} andere{# members}}", + "BLOCKED_PROJECT": { + "BLOCKED": "Blocked project", + "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": "Projekt
Punkte", "DEFINED": "definierte
Punkte", "ASSIGNED": "zugewiesene
Punkte", - "CLOSED": "geschlossen
Punkte" + "CLOSED": "geschlossene
Punkte" }, "SECTION": { "SEARCH": "Suche", - "TIMELINE": "Zeitlinie ", + "TIMELINE": "Zeitlinie", "BACKLOG": "Auftragsliste", "KANBAN": "Kanban", "ISSUES": "Tickets", @@ -753,7 +795,7 @@ "PLACEHOLDER_SEARCH": "Suchen...", "ACTION_CREATE_PROJECT": "Projekt anlegen", "ACTION_IMPORT_PROJECT": "Projekt importieren", - "MANAGE_PROJECTS": "Manage projects", + "MANAGE_PROJECTS": "Projekte verwalten", "TITLE_CREATE_PROJECT": "Projekt anlegen", "TITLE_IMPORT_PROJECT": "Projekt importieren", "TITLE_PRVIOUS_PROJECT": "Frühere Projekte anzeigen", @@ -771,12 +813,13 @@ "SETTINGS": "Einstellungen", "VIEW_PROFILE_TITLE": "Profil ansehen", "VIEW_PROFILE": "Profil ansehen", - "EDIT_PROFILE_TITLE": "Bearbeiten Sie Ihr Profil ", + "EDIT_PROFILE_TITLE": "Bearbeiten Sie Ihr Profil", "EDIT_PROFILE": "Profil bearbeiten", "CHANGE_PASSWORD_TITLE": "Passwort ändern", "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" }, @@ -787,11 +830,36 @@ "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": "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_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" + "SYNC_SUCCESS": "Ihr Projekt wurde erfolgreich importiert", + "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.", + "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 private 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": "The project that you are trying to import is private and has {{members}} members." + }, + "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." + } + } }, "LIKE_BUTTON": { "LIKE": "Gefällt mir", @@ -819,8 +887,11 @@ "DELETE_ACCOUNT": { "SECTION_NAME": "Dein Taiga Benutzerkonto löschen", "CONFIRM": "Sind Sie sicher, dass Sie Ihr Taiga Benutzerkonto löschen wollen?", - "SUBTITLE": "Wir werden Sie vermissen! :-(", - "NEWSLETTER_LABEL_TEXT": "Ich möchte keinen Newsletter mehr erhalten" + "NEWSLETTER_LABEL_TEXT": "Ich möchte keinen Newsletter mehr erhalten", + "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! :(" }, "DELETE_PROJECT": { "TITLE": "Projekt löschen", @@ -876,7 +947,25 @@ }, "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" + "PLACEHOLDER_TYPE_EMAIL": "Geben Sie eine E-Mail ein", + "LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "Unfortunately, this project can't have more than {{maxMembers}} members.
If you would like to increase the current limit, please contact the administrator.", + "LIMIT_USERS_WARNING_MESSAGE": "Unfortunately, this project can't have more than {{maxMembers}} members." + }, + "LEAVE_PROJECT_WARNING": { + "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" + }, + "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.", + "BUTTON": "Request project owner change" + } + }, + "CHANGE_OWNER": { + "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" } }, "US": { @@ -888,7 +977,7 @@ "TOTAL_POINTS": "Gesamtpunkte", "ADD": "+ Neue User-Story anlegen", "ADD_BULK": "Mehrere neue User-Stories hinzufügen", - "PROMOTED": "Diese User-Story entstand aus Ticket: ", + "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", @@ -903,7 +992,7 @@ "TOTAL_US_POINTS": "User-Story-Punkte insgesamt", "FIELDS": { "TEAM_REQUIREMENT": "Team Anforderung", - "CLIENT_REQUIREMENT": "Kundenanforderung ", + "CLIENT_REQUIREMENT": "Kundenanforderung", "FINISH_DATE": "Endtermin" } }, @@ -914,7 +1003,7 @@ "TYPE_NEW_COMMENT": "Geben Sie hier einen neuen Kommentar ein", "SHOW_DELETED": "Gelöschten Kommentar anzeigen", "HIDE_DELETED": "Gelöschten Kommentar ausblenden", - "DELETE": "Delete comment", + "DELETE": "Kommentar löschen", "RESTORE": "Kommentar wiederherstellen" }, "ACTIVITY": { @@ -928,7 +1017,7 @@ "NEW_ATTACHMENT": "Neuer Anhang", "DELETED_ATTACHMENT": "Gelöschter Anhang", "UPDATED_ATTACHMENT": "aktualisierter Anhang {{filename}}", - "DELETED_CUSTOM_ATTRIBUTE": "gelöschtes Kundenattribut ", + "DELETED_CUSTOM_ATTRIBUTE": "gelöschtes Kundenattribut", "SIZE_CHANGE": "Machte {size, plural, one{eine Änderung} other{# Änderungen}}", "VALUES": { "YES": "ja", @@ -950,14 +1039,14 @@ "ASSIGNED_TO": "zugewiesen an", "WATCHERS": "Beobachter", "MILESTONE": "Sprint", - "USER_STORY": "User-Story ", + "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 ", + "CLIENT_REQUIREMENT": "Kunden Anforderung", + "TEAM_REQUIREMENT": "Team Anforderung", + "IS_IOCAINE": "ist Iocaine", "TAGS": "Schlagwörter", "ATTACHMENTS": "Anhänge", "IS_DEPRECATED": "ist veraltet", @@ -975,7 +1064,7 @@ "SECTION_NAME": "Auftragsliste", "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_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", @@ -985,14 +1074,14 @@ "CREATE_NEW_US": "Eine neue User-Story anlegen", "CREATE_NEW_US_EMPTY_HELP": "Sie sollten eine User-Story anlegen", "EXCESS_OF_POINTS": "Punkte Überschuss", - "PENDING_POINTS": "Unerledigte Punkte ", + "PENDING_POINTS": "Unerledigte Punkte", "CLOSED_POINTS": "geschlossen", - "COMPACT_SPRINT": "Kompakt Sprint ", + "COMPACT_SPRINT": "Kompakt Sprint", "GO_TO_TASKBOARD": "Gehen Sie zum Taskboard von {{::name}}", "EDIT_SPRINT": "Sprint bearbeiten", "TOTAL_POINTS": "insgesamt", "STATUS_NAME": "Status Bezeichnung", - "SORTABLE_FILTER_ERROR": "Es ist kein Drag & Drop über dem Backlog möglich wenn Filter geöffnet sind.", + "SORTABLE_FILTER_ERROR": "Es ist kein Drag & Drop über dem Backlog möglich, wenn Filter geöffnet sind.", "DOOMLINE": "Projekt Umfang [Doomline]", "CHART": { "XAXIS_LABEL": "Sprints", @@ -1027,7 +1116,7 @@ "POINTS_PER_SPRINT": "Punkte /
Sprint" }, "FILTERS": { - "TOGGLE": "Filter sichtbar schalten ", + "TOGGLE": "Filter sichtbar schalten", "TITLE": "Filter", "REMOVE": "Filter entfernen", "HIDE": "Filter verbergen", @@ -1037,13 +1126,13 @@ }, "SPRINTS": { "TITLE": "SPRINTS", - "DATE": "DD MMM YYYY", + "DATE": "TT MMM JJJJ", "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": "This sprint has no User Stories", - "WARNING_EMPTY_SPRINT": "Ziehe Stories aus deiner Auftragsliste her um einen neuen Sprint zu starten", + "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", "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", @@ -1053,7 +1142,7 @@ "ERROR": { "TEXT1": "Es gibt ein Problem und unsere Helferlein arbeiten schon daran!", "NOT_FOUND": "Nicht gefunden", - "NOT_FOUND_TEXT": "Fehler 404. Die angeforderte Seite existiert nicht mehr. Möglicherweise finden Sie das Gesuchte, wenn Sie zur TAIGA Homepage zurückkehren. ", + "NOT_FOUND_TEXT": "Fehler 404. Die angeforderte Seite existiert nicht mehr. Möglicherweise finden Sie das Gesuchte, wenn Sie zur TAIGA Homepage zurückkehren.", "PERMISSION_DENIED": "Berechtigung verweigert", "PERMISSION_DENIED_TEXT": "Sie haben nicht die Berechtigung um auf diese Seite zuzugreifen", "VERSION_ERROR": "Jemand anderes hat dies schon geändert und unsere Helferlein können Ihre Änderungen deshalb nicht übernehmen. Bitte laden Sie die Seite neu und machen Sie die Änderungen erneut (die aktuelle Eingabe geht dabei verloren)." @@ -1093,9 +1182,9 @@ "TITLE_LINK_TASKBOARD": "Zu Taskboard wechseln", "PLACEHOLDER_SUBJECT": "Betreff...", "TITLE_SELECT_STATUS": "Status Bezeichnung", - "OWNER_US": "Diese Aufgabe gehört zu ", + "OWNER_US": "Diese Aufgabe gehört zu", "TITLE_LINK_GO_OWNER": "Zur User-Story wechseln", - "ORIGIN_US": "Diese Aufgabe wurde erstellt durch ", + "ORIGIN_US": "Diese Aufgabe wurde erstellt durch", "TITLE_LINK_GO_ORIGIN": "Zu User-Story wechseln", "BLOCKED": "Diese Aufgabe wird blockiert", "PREVIOUS": "vorherige Aufgabe", @@ -1113,7 +1202,7 @@ "NOTIFICATION": { "OK": "Alles in Ordnung", "WARNING": "Huch, es gibt ein Problem...", - "WARNING_TEXT": "Unsere Helferlein bedauern, Ihre Änderungen wurden nicht gespeichert! ", + "WARNING_TEXT": "Unsere Helferlein bedauern, Ihre Änderungen wurden nicht gespeichert!", "SAVED": "Die Helferlein haben Ihre Änderungen gespeichert!", "CLOSE": "Benachrichtigung schließen", "MAIL": "Benachrichtigungen per Mail", @@ -1123,12 +1212,12 @@ "TITLE": "Ihr Benutzerkonto löschen", "SUBTITLE": "Wir bedauern, dass Sie die Taiga verlassen. Wir hoffen, Sie hatten einen angenehmen Aufenthalt. :)", "PLACEHOLDER_INPUT_TOKEN": "Benutzerkonto Token ungültig machen", - "ACTION_LEAVING": "Ja, ich gehe! ", - "SUCCESS": "Unsere Helferlein haben Ihr Benutzerkonto entfernt. " + "ACTION_LEAVING": "Ja, ich gehe!", + "SUCCESS": "Unsere Helferlein haben Ihr Benutzerkonto entfernt." }, "CHANGE_EMAIL_FORM": { "TITLE": "Ändern Sie Ihre E-Mail", - "SUBTITLE": "Noch ein Klick und Ihre E-Mail wird aktualisiert! ", + "SUBTITLE": "Noch ein Klick und Ihre E-Mail wird aktualisiert!", "PLACEHOLDER_INPUT_TOKEN": "E-Mail-Token ändern", "ACTION_CHANGE_EMAIL": "E-Mail ändern", "SUCCESS": "Unsere Helferlein haben Ihre E-Mail-Adresse aktualisiert" @@ -1138,14 +1227,14 @@ "PAGE_DESCRIPTION": "Das Ticket-Listen Panel des Projekts {{projectName}}: {{projectDescription}}", "LIST_SECTION_NAME": "Tickets", "SECTION_NAME": "Ticket Details", - "ACTION_NEW_ISSUE": "+ NEUES TICKET ", + "ACTION_NEW_ISSUE": "+ NEUES TICKET", "ACTION_PROMOTE_TO_US": "Zur User-Story aufwerten", "PLACEHOLDER_FILTER_NAME": "Benennen Sie den Filter und drücken Sie die Eingabetaste", "PROMOTED": "Dieses Ticket wurde aufgewertet zu User-Story:", - "EXTERNAL_REFERENCE": "Dieses Ticket wurde erstellt durch ", + "EXTERNAL_REFERENCE": "Dieses Ticket wurde erstellt durch", "GO_TO_EXTERNAL_REFERENCE": "Zur Quelle wechseln", "BLOCKED": "Dieses Ticket wird blockiert", - "TITLE_PREVIOUS_ISSUE": "vorheriges Ticket ", + "TITLE_PREVIOUS_ISSUE": "vorheriges Ticket", "TITLE_NEXT_ISSUE": "nächstes Ticket", "ACTION_DELETE": "Ticket löschen", "LIGHTBOX_TITLE_BLOKING_ISSUE": "Blockierendes Ticket", @@ -1192,7 +1281,7 @@ "ASSIGNED_TO": "Zugeordnet" }, "TITLE_ACTION_CHANGE_STATUS": "Status wechseln", - "TITLE_ACTION_ASSIGNED_TO": "Zugeordnet zu ", + "TITLE_ACTION_ASSIGNED_TO": "Zugeordnet zu", "BLOCKED": "Blockiert", "EMPTY": { "TITLE": "Es gibt keine Probleme zu berichten :-)", @@ -1216,9 +1305,9 @@ "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 ", + "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 ", + "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" }, @@ -1231,7 +1320,7 @@ "FILTER_WIKI": "Wiki Seiten", "PLACEHOLDER_SEARCH": "Suchen in...", "TITLE_ACTION_SEARCH": "suchen", - "EMPTY_TITLE": "Es sieht so aus, als könnte unter Ihren Suchkriterien nichts gefunden werden. ", + "EMPTY_TITLE": "Es sieht so aus, als könnte unter Ihren Suchkriterien nichts gefunden werden.", "EMPTY_DESCRIPTION": "Vielleicht versuchen Sie es mit einem der oberen Reiter, oder Sie suchen erneut" }, "TEAM": { @@ -1242,12 +1331,12 @@ "PLACEHOLDER_INPUT_SEARCH": "Unter Anzeigenamen suchen...", "COLUMN_MR_WOLF": "Herr Wolf", "EXPLANATION_COLUMN_MR_WOLF": "Geschlossene Tickets", - "COLUMN_IOCAINE": "Locaine Trinker ", - "EXPLANATION_COLUMN_IOCAINE": "Locaine Dosen eingenommen ", + "COLUMN_IOCAINE": "Locaine Trinker", + "EXPLANATION_COLUMN_IOCAINE": "Locaine Dosen eingenommen", "COLUMN_CERVANTES": "Cervantes", "EXPLANATION_COLUMN_CERVANTES": "Wiki Seiten geändert", "COLUMN_BUG_HUNTER": "Bug-Jäger", - "EXPLANATION_COLUMN_BUG_HUNTER": "Gemeldete Tickets ", + "EXPLANATION_COLUMN_BUG_HUNTER": "Gemeldete Tickets", "COLUMN_NIGHT_SHIFT": "Nachtschicht", "EXPLANATION_COLUMN_NIGHT_SHIFT": "Aufgaben geschlossen", "COLUMN_TOTAL_POWER": "Gesamtleistung", @@ -1263,13 +1352,13 @@ "SECTION_TITLE": "Benutzereinstellungen", "USER_PROFILE": "Benutzerprofil", "CHANGE_PASSWORD": "Passwort ändern", - "EMAIL_NOTIFICATIONS": "E-Mail Benachrichtigungen " + "EMAIL_NOTIFICATIONS": "E-Mail Benachrichtigungen" }, "NOTIFICATIONS": { "SECTION_NAME": "E-Mail-Benachrichtigungen", "COLUMN_PROJECT": "Projekt", "COLUMN_RECEIVE_ALL": "Alle erhalten", - "COLUMN_ONLY_INVOLVED": "Nur Einbezogene ", + "COLUMN_ONLY_INVOLVED": "Nur Einbezogene", "COLUMN_NO_NOTIFICATIONS": "Keine Benachrichtigungen", "OPTION_ALL": "Alle", "OPTION_INVOLVED": "Beteiligt", @@ -1280,7 +1369,7 @@ "CHANGE_PASSWORD": "Passwort ändern", "NOTIFICATIONS": "Benachrichtigungen", "FEEDBACK": "Feedback", - "TITLE_AVATAR": "Benutzereinstellungen " + "TITLE_AVATAR": "Benutzereinstellungen" } }, "USER_PROFILE": { @@ -1304,18 +1393,24 @@ } }, "WIZARD": { - "SECTION_TITLE_CHOOSE_TEMPLATE": "Wählen Sie ein Template", - "CHOOSE_TEMPLATE_TEXT": "Welches Template würde besser zu Ihrem Projekt passen?", "SECTION_TITLE_CREATE_PROJECT": "Projekt erstellen", - "CREATE_PROJECT_TEXT": "Frisch und sauber. Wie aufregend! ", - "PROGRESS_TEMPLATE_SELECTION": "Template Auswahl ", - "PROGRESS_NAME_DESCRIPTION": "Name und Beschreibung" + "CREATE_PROJECT_TEXT": "Frisch und sauber. Wie aufregend!", + "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": "Projekt anlegen", + "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": "Letzte Bearbeitung am {{lastModifiedDate}} ({{totalEditions}} Gesamtzahl der Bearbeitungen) Inhalt: {{ wikiPageContent }}", - "DATETIME": "DD MMM YYYY HH:mm", - "PLACEHOLDER_PAGE": "Schreiben Sie Ihre Wiki Seite ", + "DATETIME": "TT MMM JJJJ hh:mm", + "PLACEHOLDER_PAGE": "Schreiben Sie Ihre Wiki Seite", "REMOVE": "Diese Wiki Seite entfernen", "DELETE_LIGHTBOX_TITLE": "Wiki Seite löschen", "NAVIGATION": { @@ -1330,21 +1425,21 @@ }, "HINTS": { "SECTION_NAME": "Hinweis", - "LINK": "Mehr dazu auf unserer Support Seite ", + "LINK": "Mehr dazu auf unserer Support Seite", "LINK_TITLE": "Besuchen Sie unsere Support Seite", "HINT1_TITLE": "Wussten Sie, dass Sie Projekte importieren und exportieren?", "HINT1_TEXT": "Dies erlaubt Ihnen, alle Ihre Daten zu extrahieren und sie von einer Taiga zur nächsten zu transportieren", "HINT2_TITLE": "Wussten Sie, dass Sie benutzerdefinierte Felder erstellen können?", "HINT2_TEXT": "Teams können nun benutzerdefinierte Felder anlegen, um Werte einzugeben, die für Ihren Workflow wichtig sind.", "HINT3_TITLE": "Sortiere Deine Projekte, um Dir vor allem die anzuzeigen, die relevant für Dich sind.", - "HINT3_TEXT": "Die 10 Projekt sind in der Zugriffsleiste am oberen Bildschirmrand aufgelistet. ", + "HINT3_TEXT": "Die 10 Projekt sind in der Zugriffsleiste am oberen Bildschirmrand aufgelistet.", "HINT4_TITLE": "Did you forget what were you working on?", "HINT4_TEXT": "Machen Sie sich keine Sorgen, im Dashboard finden Sie Aufgaben, Tickets und User-Stories in der Reihenfolge in der Sie diese bearbeitet haben." }, "TIMELINE": { "UPLOAD_ATTACHMENT": "{{username}} fügte {{obj_name}} einen neuen Anhang zu", "US_CREATED": "{{username}} erstellte die neue User-Story {{obj_name}} in {{project_name}}", - "ISSUE_CREATED": "{{username}} erstellte das neue Ticket {{obj_name}} in {{project_name}} ", + "ISSUE_CREATED": "{{username}} erstellte das neue Ticket {{obj_name}} in {{project_name}}", "TASK_CREATED": "{{username}} erstellte die neue Aufgabe {{obj_name}} in {{project_name}}", "TASK_CREATED_WITH_US": "{{username}} erstellte die neue Aufgabe {{obj_name}} in {{project_name}}, die zur User-Story {{us_name}} gehört", "WIKI_CREATED": "{{username}} erstellte die neue Wiki Seite {{obj_name}} in {{project_name}}", @@ -1380,14 +1475,14 @@ "PAGE_DESCRIPTION": "Eine externe Anwendung benötigt eine Genehmigung", "AUTHORIZATION_REQUEST": "{{application}} erlauben ihren Taiga Account zu benutzen?", "LOGIN_WITH_ANOTHER_USER": "Mit einem anderen Benutzer einloggen.", - "AUTHORIZE_APP": "App autorisieren", + "AUTHORIZE_APP": "Anwendung autorisieren", "CANCEL": "Abbrechen" }, "JOYRIDE": { "NAV": { "NEXT": "Weiter", - "BACK": "Back", - "SKIP": "Skip", + "BACK": "Zurück", + "SKIP": "Überspringen", "DONE": "Erledigt" }, "DASHBOARD": { @@ -1397,7 +1492,7 @@ }, "STEP2": { "TITLE": "Zuletzt bearbeitet", - "TEXT": "Here wirst du deine User Stories, Tasks und Issues sehen, an denen du arbeitest." + "TEXT": "Hier wirst du deine User Stories, Tasks und Issues sehen, an denen du arbeitest." }, "STEP3": { "TITLE": "Beobachtet", @@ -1455,7 +1550,7 @@ "MOST_LIKED": "Most liked", "MOST_LIKED_EMPTY": "There are no LIKED projects yet", "VIEW_MORE": "View more", - "RECRUITING": "This project is looking for people", + "RECRUITING": "Dieses Projekt sucht nach Mitarbeitern", "FEATURED": "Featured Projects", "EMPTY": "There are no projects to show with this search criteria.
Try again!", "FILTERS": { @@ -1463,18 +1558,18 @@ "KANBAN": "Kanban", "SCRUM": "Scrum", "PEOPLE": "Looking for people", - "WEEK": "Last week", - "MONTH": "Last month", - "YEAR": "Last year", + "WEEK": "Letzte Woche", + "MONTH": "Letzter Monat", + "YEAR": "Letztes Jahr", "ALL_TIME": "All time", - "CLEAR": "Clear filters" + "CLEAR": "Filter zurücksetzen" }, "SEARCH": { "PAGE_TITLE": "Search - Discover projects - 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": "Geben sie etwas ein...", "ACTION_TITLE": "Suche", - "RESULTS": "Search results" + "RESULTS": "Suchergebnisse" } } } \ No newline at end of file diff --git a/app/locales/taiga/locale-en.json b/app/locales/taiga/locale-en.json index 8480026f..4a49d61f 100644 --- a/app/locales/taiga/locale-en.json +++ b/app/locales/taiga/locale-en.json @@ -41,7 +41,8 @@ "IOCAINE_TEXT": "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!", "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", - "CAPSLOCK_WARNING": "Be careful! You're writing with capital letters and this input is case sensitive.", + "OWNER": "Project Owner", + "CAPSLOCK_WARNING": "Be careful! You are using capital letters in an input field that is case sensitive.", "FORM_ERRORS": { "DEFAULT_MESSAGE": "This value seems to be invalid.", "TYPE_EMAIL": "This value should be a valid email.", @@ -65,7 +66,9 @@ "MIN_CHECK": "You must select at least %s choices.", "MAX_CHECK": "You must select %s choices or less.", "RANGE_CHECK": "You must select between %s and %s choices.", - "EQUAL_TO": "This value should be the same." + "EQUAL_TO": "This value should be the same.", + "LINEWIDTH": "One or more lines is perhaps too long. Try to keep under %s characters.", + "PIKADAY": "Invalid date format, please use DD MMM YYYY (like 23 Mar 1984)" }, "PICKERDATE": { "FORMAT": "DD MMM YYYY", @@ -315,7 +318,8 @@ "PLACEHOLDER_FIELD": "Username or email", "ACTION_RESET_PASSWORD": "Reset Password", "LINK_CANCEL": "Nah, take me back. I think I remember it.", - "SUCCESS": "Check your inbox!
We have sent you an email with the instructions to set a new password", + "SUCCESS_TITLE": "Check your inbox!", + "SUCCESS_TEXT": "We sent you an email with the instructions to set a new password", "ERROR": "According to our Oompa Loompas, your are not registered yet." }, "CHANGE_PASSWORD": { @@ -405,7 +409,9 @@ "TITLE": "Manage members", "PAGE_TITLE": "Memberships - {{projectName}}", "ADD_BUTTON": "+ New member", - "ADD_BUTTON_TITLE": "Add new member" + "ADD_BUTTON_TITLE": "Add new member", + "LIMIT_USERS_WARNING_MESSAGE_FOR_ADMIN": "Unfortunately, this project has reached its limit of ({{members}}) allowed members.", + "LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "This project has reached its limit of ({{members}}) allowed members. If you would like to increase that limit please contact the administrator." }, "PROJECT_EXPORT": { "TITLE": "Export", @@ -427,6 +433,10 @@ "DISABLE": "Disable", "BACKLOG": "Backlog", "BACKLOG_DESCRIPTION": "Manage your user stories to maintain an organized view of upcoming and prioritized work.", + "NUMBER_SPRINTS": "Expected number of sprints", + "NUMBER_SPRINTS_HELP": "0 for an undetermined number", + "NUMBER_US_POINTS": "Expected total of story points", + "NUMBER_US_POINTS_HELP": "0 for an undetermined number", "KANBAN": "Kanban", "KANBAN_DESCRIPTION": "Organize your project in a lean way with this board.", "ISSUES": "Issues", @@ -434,9 +444,9 @@ "WIKI": "Wiki", "WIKI_DESCRIPTION": "Add, modify, or delete content in collaboration with others. This is the right place for your project documentation.", "MEETUP": "Meet Up", - "MEETUP_DESCRIPTION": "Choose your videoconference system. Even developers need face to face contact.", + "MEETUP_DESCRIPTION": "Choose your videoconference system.", "SELECT_VIDEOCONFERENCE": "Select a videoconference system", - "SALT_CHAT_ROOM": "If you want you can append a salt code to the name of the chat room", + "SALT_CHAT_ROOM": "Add a prefix to the chatroom name", "JITSI_CHAT_ROOM": "Jitsi", "APPEARIN_CHAT_ROOM": "AppearIn", "TALKY_CHAT_ROOM": "Talky", @@ -448,22 +458,31 @@ "PROJECT_DETAILS": "Project details", "PROJECT_NAME": "Project name", "PROJECT_SLUG": "Project slug", - "NUMBER_SPRINTS": "Number of sprints (0 for an undetermined quantity)", - "NUMBER_US_POINTS": "Number of US points (0 for an undetermined quantity)", "TAGS": "Tags", "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", "PUBLIC_PROJECT": "Public project", - "PUBLIC_PROJECT_DESC": "Users will be able to find and view your project", "PRIVATE_PROJECT": "Private project", - "PRIVATE_PROJECT_DESC": "By default, this project will be hidden to the public", "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" + "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", + "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", + "REQUEST_OWNERSHIP": "Request ownership", + "REQUEST_OWNERSHIP_CONFIRMATION_TITLE": "Do you want to become the new project owner?", + "REQUEST_OWNERSHIP_DESC": "Request that current project owner {{name}} transfer ownership of this project to you.", + "REQUEST_OWNERSHIP_BUTTON": "Request", + "REQUEST_OWNERSHIP_SUCCESS": "We'll notify the project owner", + "CHANGE_OWNER": "Change owner", + "CHANGE_OWNER_SUCCESS_TITLE": "Ok, your request has been sent!", + "CHANGE_OWNER_SUCCESS_DESC": "We will notify you by email if the project ownership request is accepted or declined" }, "REPORTS": { "TITLE": "Reports", @@ -494,7 +513,8 @@ "ISSUE_ADD": "Add a custom field in issues", "FIELD_TYPE_TEXT": "Text", "FIELD_TYPE_MULTI": "Multi-line", - "FIELD_TYPE_DATE": "Date" + "FIELD_TYPE_DATE": "Date", + "FIELD_TYPE_URL": "Url" }, "PROJECT_VALUES": { "PAGE_TITLE": "{{sectionName}} - Project values - {{projectName}}", @@ -542,7 +562,7 @@ "COUNT_MEMBERS": "{{ role.members_count }} members with this role", "TITLE_DELETE_ROLE": "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", + "WARNING_DELETE_ROLE": "Be careful! All role estimations will be removed", "ERROR_DELETE_ALL": "You can't delete all values", "EXTERNAL_USER": "External user" }, @@ -670,6 +690,24 @@ }, "SUBMENU_THIDPARTIES": { "TITLE": "Services" + }, + "PROJECT_TRANSFER": { + "DO_YOU_ACCEPT_PROJECT_OWNERNSHIP": "Would you like to become the new project owner?", + "PRIVATE": "Private", + "ACCEPTED_PROJECT_OWNERNSHIP": "Congratulations! You're now the new project owner.", + "REJECTED_PROJECT_OWNERNSHIP": "OK. We'll contact the current project owner", + "ACCEPT": "Accept", + "REJECT": "Reject", + "PROPOSE_OWNERSHIP": "{{owner}}, the current owner of the project {{project}} has asked that you become the new project owner.", + "ADD_COMMENT_QUESTION": "Would you like to send a question to the project owner?", + "ADD_COMMENT": "Would you like to add a comment for the project owner?", + "UNLIMITED_PROJECTS": "Unlimited", + "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" + }, + "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" } }, "USER": { @@ -730,6 +768,11 @@ "FANS_COUNTER_TITLE": "{total, plural, one{one fan} other{# fans}}", "WATCHERS_COUNTER_TITLE": "{total, plural, one{one watcher} other{# watchers}}", "MEMBERS_COUNTER_TITLE": "{total, plural, one{one member} other{# members}}", + "BLOCKED_PROJECT": { + "BLOCKED": "Blocked project", + "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", @@ -776,6 +819,7 @@ "CHANGE_PASSWORD": "Change password", "DASHBOARD_TITLE": "Dashboard", "DISCOVER_TITLE": "Discover trending projects", + "NEW_ITEM": "New", "DISCOVER": "Discover", "ACTION_REORDER": "Drag & drop to reorder" }, @@ -790,7 +834,32 @@ "ERROR_TOO_MANY_REQUEST": "Sorry, our Oompa Loompas are very busy right now. Please try again in a few minutes.", "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" + "SYNC_SUCCESS": "Your project has been imported successfuly", + "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.", + "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 private 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": "The project that you are trying to import is private and has {{members}} members." + }, + "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." + } + } }, "LIKE_BUTTON": { "LIKE": "Like", @@ -818,9 +887,11 @@ "DELETE_ACCOUNT": { "SECTION_NAME": "Delete Taiga Account", "CONFIRM": "Are you sure you want to delete your Taiga account?", - "SUBTITLE": "We're going to miss you! :-(", - "NEWSLETTER_LABEL_TEXT": "I don't wanna receive your newsletter anymore" - + "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! :(" }, "DELETE_PROJECT": { "TITLE": "Delete project", @@ -855,7 +926,7 @@ "PLACEHOLDER_SPRINT_END": "Estimated End", "ACTION_DELETE_SPRINT": "Do you want to delete this sprint?", "TITLE_ACTION_DELETE_SPRINT": "delete sprint", - "LAST_SPRINT_NAME": " last sprint is {{lastSprint}} ;-) " + "LAST_SPRINT_NAME": "last sprint is {{lastSprint}} ;-) " }, "CREATE_EDIT_TASK": { "TITLE": "New task", @@ -876,13 +947,30 @@ }, "CREATE_MEMBER": { "PLACEHOLDER_INVITATION_TEXT": "(Optional) Add a personalized text to the invitation. Tell something lovely to your new members ;-)", - "PLACEHOLDER_TYPE_EMAIL": "Type an Email" + "PLACEHOLDER_TYPE_EMAIL": "Type an Email", + "LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "Unfortunately, this project can't have more than {{maxMembers}} members.
If you would like to increase the current limit, please contact the administrator.", + "LIMIT_USERS_WARNING_MESSAGE": "Unfortunately, this project can't have more than {{maxMembers}} members." + }, + "LEAVE_PROJECT_WARNING": { + "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" + }, + "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.", + "BUTTON": "Request project owner change" + } + }, + "CHANGE_OWNER": { + "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" } }, "US": { "PAGE_TITLE": "{{userStorySubject}} - User Story {{userStoryRef}} - {{projectName}}", "PAGE_DESCRIPTION": "Status: {{userStoryStatus }}. Completed {{userStoryProgressPercentage}}% ({{userStoryClosedTasks}} of {{userStoryTotalTasks}} tasks closed). Points: {{userStoryPoints}}. Description: {{userStoryDescription}}", - "SECTION_NAME": "User story details", "LINK_TASKBOARD": "Taskboard", "TITLE_LINK_TASKBOARD": "Go to the taskboard", @@ -938,36 +1026,36 @@ "UNASSIGNED": "unassigned" }, "FIELDS": { - "SUBJECT" : "subject", + "SUBJECT": "subject", "NAME": "name", - "DESCRIPTION" : "description", + "DESCRIPTION": "description", "CONTENT": "content", "STATUS": "status", - "IS_CLOSED" : "is closed", - "FINISH_DATE" : "finish date", + "IS_CLOSED": "is closed", + "FINISH_DATE": "finish date", "TYPE": "type", "PRIORITY": "priority", "SEVERITY": "severity", - "ASSIGNED_TO" : "assigned to", - "WATCHERS" : "watchers", - "MILESTONE" : "sprint", + "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", + "CLIENT_REQUIREMENT": "client requirement", + "TEAM_REQUIREMENT": "team requirement", "IS_IOCAINE": "is iocaine", "TAGS": "tags", - "ATTACHMENTS" : "attachments", + "ATTACHMENTS": "attachments", "IS_DEPRECATED": "is deprecated", - "ORDER" : "order", - "BACKLOG_ORDER" : "backlog order", - "SPRINT_ORDER" : "sprint order", - "KANBAN_ORDER" : "kanban order", - "TASKBOARD_ORDER" : "taskboard order", - "US_ORDER" : "us order" + "ORDER": "order", + "BACKLOG_ORDER": "backlog order", + "SPRINT_ORDER": "sprint order", + "KANBAN_ORDER": "kanban order", + "TASKBOARD_ORDER": "taskboard order", + "US_ORDER": "us order" } }, "BACKLOG": { @@ -987,11 +1075,10 @@ "CREATE_NEW_US_EMPTY_HELP": "You may want to create a new user story", "EXCESS_OF_POINTS": "Excess of points", "PENDING_POINTS": "Pending Points", - "CLOSED_POINTS": "Closed points", + "CLOSED_POINTS": "closed", "COMPACT_SPRINT": "Compact Sprint", "GO_TO_TASKBOARD": "Go to the taskboard of {{::name}}", "EDIT_SPRINT": "Edit Sprint", - "CLOSED_POINTS": "closed", "TOTAL_POINTS": "total", "STATUS_NAME": "Status Name", "SORTABLE_FILTER_ERROR": "You can't drop on backlog when filters are open", @@ -1062,7 +1149,7 @@ }, "TASKBOARD": { "PAGE_TITLE": "{{sprintName}} - Sprint taskboard - {{projectName}}", - "PAGE_DESCRIPTION": "Sprint {{sprintName}} (from {{startDate}} to {{endDate}}) of {{projectName}}. Completed {{completedPercentage}}% ({{completedPoints}} of {{totalPoints}} points). {{openTasks}} opened tasks of {{totalTasks}}." , + "PAGE_DESCRIPTION": "Sprint {{sprintName}} (from {{startDate}} to {{endDate}}) of {{projectName}}. Completed {{completedPercentage}}% ({{completedPoints}} of {{totalPoints}} points). {{openTasks}} opened tasks of {{totalTasks}}.", "SECTION_NAME": "Taskboard", "TITLE_ACTION_ADD": "Add a new Task", "TITLE_ACTION_ADD_BULK": "Add some new Tasks in bulk", @@ -1306,12 +1393,18 @@ } }, "WIZARD": { - "SECTION_TITLE_CHOOSE_TEMPLATE": "Choose a template", - "CHOOSE_TEMPLATE_TEXT": "Which template would fit better in your project?", "SECTION_TITLE_CREATE_PROJECT": "Create Project", "CREATE_PROJECT_TEXT": "Fresh and clean. So exciting!", - "PROGRESS_TEMPLATE_SELECTION": "Template selection", - "PROGRESS_NAME_DESCRIPTION": "Name and description" + "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}}", @@ -1479,4 +1572,4 @@ "RESULTS": "Search results" } } -} +} \ No newline at end of file diff --git a/app/locales/taiga/locale-es.json b/app/locales/taiga/locale-es.json index b5c07e2f..c8518ba9 100644 --- a/app/locales/taiga/locale-es.json +++ b/app/locales/taiga/locale-es.json @@ -41,7 +41,8 @@ "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!", "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.", - "CAPSLOCK_WARNING": "¡Ten cuidado! Usted está escribiendo con mayúsculas y esta entrada es sensible a mayúsculas.", + "OWNER": "Project Owner", + "CAPSLOCK_WARNING": "Be careful! You are using capital letters in an input field that is case sensitive.", "FORM_ERRORS": { "DEFAULT_MESSAGE": "Este valor parece inválido.", "TYPE_EMAIL": "El valor debe ser un email.", @@ -65,7 +66,9 @@ "MIN_CHECK": "Debes seleccionar al menos %s.", "MAX_CHECK": "Debes seleccionar %s o menos.", "RANGE_CHECK": "Debes seleccionar de %s a %s.", - "EQUAL_TO": "Este valor debe ser el mismo." + "EQUAL_TO": "Este valor debe ser el mismo.", + "LINEWIDTH": "One or more lines is perhaps too long. Try to keep under %s characters.", + "PIKADAY": "Invalid date format, please use DD MMM YYYY (like 23 Mar 1984)" }, "PICKERDATE": { "FORMAT": "DD MMM YYYY", @@ -315,7 +318,8 @@ "PLACEHOLDER_FIELD": "Nombre de usuario o email", "ACTION_RESET_PASSWORD": "Restablecer Contraseña", "LINK_CANCEL": "Nah, llévame de vuelta, creo que lo recordé.", - "SUCCESS": "¡Revisa tu bandeja de entrada!
Te hemos enviado un mail con las instrucciones necesarias para restablecer tu contraseña\n", + "SUCCESS_TITLE": "Check your inbox!", + "SUCCESS_TEXT": "We sent you an email with the instructions to set a new password", "ERROR": "Según nuestros Oompa Loompas tú no estás registrado" }, "CHANGE_PASSWORD": { @@ -373,7 +377,6 @@ "DEPRECATED_FILE": "¿Desactualizado?", "ADD": "Agrega nuevos adjunto. {{maxFileSizeMsg}}", "DROP": "¡Arrastre los archivos adjuntos aquí!", - "MAX_FILE_SIZE": "[Tamaño Max. : {{maxFileSize}}]", "SHOW_DEPRECATED": "+ muestra adjuntos desactualizados", "HIDE_DEPRECATED": "- ocultar adjuntos obsoletos", "COUNT_DEPRECATED": "({{ counter }} obsoletos)\n", @@ -406,7 +409,9 @@ "TITLE": "Administrar miembros", "PAGE_TITLE": "Miembros - {{projectName}}", "ADD_BUTTON": "+ Nuevo miembro", - "ADD_BUTTON_TITLE": "Añadir un nuevo miembro" + "ADD_BUTTON_TITLE": "Añadir un nuevo miembro", + "LIMIT_USERS_WARNING_MESSAGE_FOR_ADMIN": "Unfortunately, this project has reached its limit of ({{members}}) allowed members.", + "LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "This project has reached its limit of ({{members}}) allowed members. If you would like to increase that limit please contact the administrator." }, "PROJECT_EXPORT": { "TITLE": "Exportar", @@ -428,6 +433,10 @@ "DISABLE": "Desactivado", "BACKLOG": "Backlog", "BACKLOG_DESCRIPTION": "Gestiona tus historias de usuario para mantener una vista organizada y priorizada de los próximos trabajos que deberás afrontar. ", + "NUMBER_SPRINTS": "Expected number of sprints", + "NUMBER_SPRINTS_HELP": "0 for an undetermined number", + "NUMBER_US_POINTS": "Expected total of story points", + "NUMBER_US_POINTS_HELP": "0 for an undetermined number", "KANBAN": "Kanban", "KANBAN_DESCRIPTION": "Organiza tus proyectos de una manera flexible con este panel.", "ISSUES": "Peticiones", @@ -435,9 +444,9 @@ "WIKI": "Wiki", "WIKI_DESCRIPTION": "Añade, modifica o borra contenido en colaboración con otros miembros. Este es el lugar adecuado para la documentación de tu proyecto.", "MEETUP": "Meet Up", - "MEETUP_DESCRIPTION": "Elige tu sistema de videoconferencia. Incluso los desarrolladores necesitan el contacto cara a cara.", + "MEETUP_DESCRIPTION": "Choose your videoconference system.", "SELECT_VIDEOCONFERENCE": "Elige un sistema de videoconferencia", - "SALT_CHAT_ROOM": "Puedes añadirle un código salt al nombre del chat room", + "SALT_CHAT_ROOM": "Add a prefix to the chatroom name", "JITSI_CHAT_ROOM": "Jitsi", "APPEARIN_CHAT_ROOM": "AppearIn", "TALKY_CHAT_ROOM": "Talky", @@ -449,22 +458,31 @@ "PROJECT_DETAILS": "Info del proyecto", "PROJECT_NAME": "Nombre del proyecto", "PROJECT_SLUG": "Slug de proyecto", - "NUMBER_SPRINTS": "Número de sprints (0 para cantidad indeterminada)", - "NUMBER_US_POINTS": "Número de puntos de historias de usuario (0 para indeterminado)", "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", "PUBLIC_PROJECT": "Proyecto público", - "PUBLIC_PROJECT_DESC": "Los usuarios serán capaces de encontrar y ver tu proyecto", "PRIVATE_PROJECT": "Proyecto privado", - "PRIVATE_PROJECT_DESC": "Este proyecto estará oculto al público por defecto.", "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" + "ACTION_USE_DEFAULT_LOGO": "Usar imagen por defecto", + "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", + "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", + "REQUEST_OWNERSHIP": "Request ownership", + "REQUEST_OWNERSHIP_CONFIRMATION_TITLE": "Do you want to become the new project owner?", + "REQUEST_OWNERSHIP_DESC": "Request that current project owner {{name}} transfer ownership of this project to you.", + "REQUEST_OWNERSHIP_BUTTON": "Solicitud", + "REQUEST_OWNERSHIP_SUCCESS": "We'll notify the project owner", + "CHANGE_OWNER": "Change owner", + "CHANGE_OWNER_SUCCESS_TITLE": "Ok, your request has been sent!", + "CHANGE_OWNER_SUCCESS_DESC": "We will notify you by email if the project ownership request is accepted or declined" }, "REPORTS": { "TITLE": "Informes", @@ -495,7 +513,8 @@ "ISSUE_ADD": "Añadir un atributo personalizado en las peticiones", "FIELD_TYPE_TEXT": "Texto", "FIELD_TYPE_MULTI": "Multilínea", - "FIELD_TYPE_DATE": "Fecha" + "FIELD_TYPE_DATE": "Fecha", + "FIELD_TYPE_URL": "Url" }, "PROJECT_VALUES": { "PAGE_TITLE": "{{sectionName}} - Valores del Proyectos - {{projectName}}", @@ -543,7 +562,7 @@ "COUNT_MEMBERS": "{{ role.members_count }} miembros con este rol", "TITLE_DELETE_ROLE": "Borrar Rol", "REPLACEMENT_ROLE": "Todos los usuarios con este rol serán movidos a", - "WARNING_DELETE_ROLE": "Cuidado, todas las estimaciones asociadas a este rol se perderán", + "WARNING_DELETE_ROLE": "Be careful! All role estimations will be removed", "ERROR_DELETE_ALL": "No puedes eliminar todos los valores", "EXTERNAL_USER": "Usuario externo" }, @@ -671,6 +690,24 @@ }, "SUBMENU_THIDPARTIES": { "TITLE": "Servicios" + }, + "PROJECT_TRANSFER": { + "DO_YOU_ACCEPT_PROJECT_OWNERNSHIP": "Would you like to become the new project owner?", + "PRIVATE": "Private", + "ACCEPTED_PROJECT_OWNERNSHIP": "Congratulations! You're now the new project owner.", + "REJECTED_PROJECT_OWNERNSHIP": "OK. We'll contact the current project owner", + "ACCEPT": "Aceptar", + "REJECT": "Reject", + "PROPOSE_OWNERSHIP": "{{owner}}, the current owner of the project {{project}} has asked that you become the new project owner.", + "ADD_COMMENT_QUESTION": "Would you like to send a question to the project owner?", + "ADD_COMMENT": "Would you like to add a comment for the project owner?", + "UNLIMITED_PROJECTS": "Unlimited", + "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" + }, + "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" } }, "USER": { @@ -731,6 +768,11 @@ "FANS_COUNTER_TITLE": "{total, plural, one{un fan} other{# fans}}", "WATCHERS_COUNTER_TITLE": "{total, plural, one{un observador} other{# observadores}}", "MEMBERS_COUNTER_TITLE": "{total, plural, one{un miembro} other{# miembros}}", + "BLOCKED_PROJECT": { + "BLOCKED": "Blocked project", + "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": "puntos
proyecto", "DEFINED": "puntos
definidos", @@ -777,6 +819,7 @@ "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" }, @@ -791,7 +834,32 @@ "ERROR_TOO_MANY_REQUEST": "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 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." + "SYNC_SUCCESS": "Tu proyecto se ha importado con éxito.", + "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.", + "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 private 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": "The project that you are trying to import is private and has {{members}} members." + }, + "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." + } + } }, "LIKE_BUTTON": { "LIKE": "Me gusta", @@ -819,8 +887,11 @@ "DELETE_ACCOUNT": { "SECTION_NAME": "Eliminar cuenta de Taiga", "CONFIRM": "¿Está seguro que deseas eliminar tu cuenta de Taiga?", - "SUBTITLE": "¡Te extrañaremos! :-(", - "NEWSLETTER_LABEL_TEXT": "No quiero recibir la newsletter nunca más." + "NEWSLETTER_LABEL_TEXT": "No quiero recibir la newsletter nunca más.", + "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! :(" }, "DELETE_PROJECT": { "TITLE": "Borrar proyecto", @@ -876,7 +947,25 @@ }, "CREATE_MEMBER": { "PLACEHOLDER_INVITATION_TEXT": "(Opcional) Añade un texto personalizado a la invitación. Dile algo encantador a tus nuevos miembros ;-)", - "PLACEHOLDER_TYPE_EMAIL": "Escribe un email" + "PLACEHOLDER_TYPE_EMAIL": "Escribe un email", + "LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "Unfortunately, this project can't have more than {{maxMembers}} members.
If you would like to increase the current limit, please contact the administrator.", + "LIMIT_USERS_WARNING_MESSAGE": "Unfortunately, this project can't have more than {{maxMembers}} members." + }, + "LEAVE_PROJECT_WARNING": { + "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" + }, + "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.", + "BUTTON": "Request project owner change" + } + }, + "CHANGE_OWNER": { + "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" } }, "US": { @@ -1304,12 +1393,18 @@ } }, "WIZARD": { - "SECTION_TITLE_CHOOSE_TEMPLATE": "Elija una plantilla", - "CHOOSE_TEMPLATE_TEXT": "¿Que plantilla se ajusta mejor con tu proyecto?", "SECTION_TITLE_CREATE_PROJECT": "Crear Proyecto", "CREATE_PROJECT_TEXT": "Fresco y claro. ¡Es emocionante!", - "PROGRESS_TEMPLATE_SELECTION": "Selección de plantilla", - "PROGRESS_NAME_DESCRIPTION": "Nombre y descripción" + "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 proyecto", + "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}}", @@ -1446,8 +1541,8 @@ } }, "DISCOVER": { - "PAGE_TITLE": "Discover projects - 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.", + "PAGE_TITLE": "Descubre proyectos - Taiga", + "PAGE_DESCRIPTION": "Directorio de búsqueda de Proyectos Públicos en Taiga. Explora los backlogs, timelines, peticiones y equipos. Echa un vistazo a los proyectos que más gustan o más activos. Filtrar por Kanban o Scrum.", "DISCOVER_TITLE": "Descubre proyectos", "DISCOVER_SUBTITLE": "{projects, plural, one{Un proyecto público por descubrir} other{# proyectos público por descubrir}}\n", "MOST_ACTIVE": "Más activos", @@ -1470,8 +1565,8 @@ "CLEAR": "Borrar filtros" }, "SEARCH": { - "PAGE_TITLE": "Search - Discover projects - 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.", + "PAGE_TITLE": "Buscar - Descubre proyectos - Taiga", + "PAGE_DESCRIPTION": "Directorio de búsqueda de Proyectos Públicos en Taiga. Explora los backlogs, timelines, peticiones y equipos. Echa un vistazo a los proyectos que más gustan o más activos. Filtrar por Kanban o Scrum.", "INPUT_PLACEHOLDER": "Escribe algo...", "ACTION_TITLE": "Buscar", "RESULTS": "Resultados de búsqueda" diff --git a/app/locales/taiga/locale-fi.json b/app/locales/taiga/locale-fi.json index 0ab3626e..1c3f526f 100644 --- a/app/locales/taiga/locale-fi.json +++ b/app/locales/taiga/locale-fi.json @@ -41,7 +41,8 @@ "IOCAINE_TEXT": "Jos tehtävä ahdistaa, merkitse se myrkylliseksi. Ajan mittaa pieninä annoksina saattaa kastokykysi myrkkyä vastaan parantua.", "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", - "CAPSLOCK_WARNING": "Be careful! You're writing with capital letters and this input is case sensitive.", + "OWNER": "Project Owner", + "CAPSLOCK_WARNING": "Be careful! You are using capital letters in an input field that is case sensitive.", "FORM_ERRORS": { "DEFAULT_MESSAGE": "Tämä arvo vaikuttaa virheelliseltä.", "TYPE_EMAIL": "Tämän pitäisi olla toimiva sähköpostiosoite.", @@ -65,7 +66,9 @@ "MIN_CHECK": "Sinun täytyy valita vähintään %s valintaa.", "MAX_CHECK": "Valitse korkeintaan %s vaihtoehtoa.", "RANGE_CHECK": "Valitse %s - %s vaihteohtoa.", - "EQUAL_TO": "Arvojen pitäisi olla samat." + "EQUAL_TO": "Arvojen pitäisi olla samat.", + "LINEWIDTH": "One or more lines is perhaps too long. Try to keep under %s characters.", + "PIKADAY": "Invalid date format, please use DD MMM YYYY (like 23 Mar 1984)" }, "PICKERDATE": { "FORMAT": "DD.MM.YY", @@ -315,7 +318,8 @@ "PLACEHOLDER_FIELD": "Käyttäjänimi tai sähköposti", "ACTION_RESET_PASSWORD": "Uusi salsanasi", "LINK_CANCEL": "Vie minut takaisin, muistan sen.", - "SUCCESS": "Tarkista sähköpostisi!
Olemme lähettäneet sinulle sähköpostissa kirjautumisohjeet", + "SUCCESS_TITLE": "Check your inbox!", + "SUCCESS_TEXT": "We sent you an email with the instructions to set a new password", "ERROR": "Oompa Loompas sanovat että käyttäjänimesi tai sähköpostisi tai salasanasi on väärä." }, "CHANGE_PASSWORD": { @@ -373,7 +377,6 @@ "DEPRECATED_FILE": "Vanhentunut?", "ADD": "Add new attachment. {{maxFileSizeMsg}}", "DROP": "Drop attachments here!", - "MAX_FILE_SIZE": "[Maks. koko: {{maxFileSize}}]", "SHOW_DEPRECATED": "+ näytä vanhentuneet liitteet", "HIDE_DEPRECATED": "- piilota vanhentuneet liitteet", "COUNT_DEPRECATED": "({{ counter }} vanhentunutta)", @@ -406,7 +409,9 @@ "TITLE": "Hallinnoi jäseniä", "PAGE_TITLE": "Memberships - {{projectName}}", "ADD_BUTTON": "+ Uusi jäsen", - "ADD_BUTTON_TITLE": "Lisää jäsen" + "ADD_BUTTON_TITLE": "Lisää jäsen", + "LIMIT_USERS_WARNING_MESSAGE_FOR_ADMIN": "Unfortunately, this project has reached its limit of ({{members}}) allowed members.", + "LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "This project has reached its limit of ({{members}}) allowed members. If you would like to increase that limit please contact the administrator." }, "PROJECT_EXPORT": { "TITLE": "Vie", @@ -428,6 +433,10 @@ "DISABLE": "Passivoi", "BACKLOG": "Odottavat", "BACKLOG_DESCRIPTION": "Hallinnoi käyttäjätarinoita: järjestele ja priorisoi työtä.", + "NUMBER_SPRINTS": "Expected number of sprints", + "NUMBER_SPRINTS_HELP": "0 for an undetermined number", + "NUMBER_US_POINTS": "Expected total of story points", + "NUMBER_US_POINTS_HELP": "0 for an undetermined number", "KANBAN": "Kanban", "KANBAN_DESCRIPTION": "Järjestä projektisi tehokkaasti tällä taululla.", "ISSUES": "Pyynnöt", @@ -435,9 +444,9 @@ "WIKI": "Wiki", "WIKI_DESCRIPTION": "Lisää, muokkaa tai poista sisältöä yhteistyössä muiden kanssa. Tämä on oikea paikka projektin dokumentaatiolle.", "MEETUP": "Tapaa", - "MEETUP_DESCRIPTION": "Valitse videoneuvottelu- järjestelmä. Jopa kehittäjät tarvitsevat katsekontaktia.", + "MEETUP_DESCRIPTION": "Choose your videoconference system.", "SELECT_VIDEOCONFERENCE": "Valitse videoconferenssi-järjestelmä", - "SALT_CHAT_ROOM": "Voit halutessasi lisätä suolaan chat-huoneen nimeen", + "SALT_CHAT_ROOM": "Add a prefix to the chatroom name", "JITSI_CHAT_ROOM": "Jitsi", "APPEARIN_CHAT_ROOM": "AppearIn", "TALKY_CHAT_ROOM": "Talky", @@ -449,22 +458,31 @@ "PROJECT_DETAILS": "Projektin tiedot", "PROJECT_NAME": "Projektin nimi", "PROJECT_SLUG": "Projektin hukka-aika", - "NUMBER_SPRINTS": "Number of sprints (0 for an undetermined quantity)", - "NUMBER_US_POINTS": "Number of US points (0 for an undetermined quantity)", "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", "PUBLIC_PROJECT": "Julkinen projekti", - "PUBLIC_PROJECT_DESC": "Users will be able to find and view your project", "PRIVATE_PROJECT": "Yksityinen projekti", - "PRIVATE_PROJECT_DESC": "By default, this project will be hidden to the public", "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" + "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", + "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", + "REQUEST_OWNERSHIP": "Request ownership", + "REQUEST_OWNERSHIP_CONFIRMATION_TITLE": "Do you want to become the new project owner?", + "REQUEST_OWNERSHIP_DESC": "Request that current project owner {{name}} transfer ownership of this project to you.", + "REQUEST_OWNERSHIP_BUTTON": "Pyyntö", + "REQUEST_OWNERSHIP_SUCCESS": "We'll notify the project owner", + "CHANGE_OWNER": "Change owner", + "CHANGE_OWNER_SUCCESS_TITLE": "Ok, your request has been sent!", + "CHANGE_OWNER_SUCCESS_DESC": "We will notify you by email if the project ownership request is accepted or declined" }, "REPORTS": { "TITLE": "Raportit", @@ -495,7 +513,8 @@ "ISSUE_ADD": "Lisää oma kenttä pyynnöille", "FIELD_TYPE_TEXT": "Text", "FIELD_TYPE_MULTI": "Multi-line", - "FIELD_TYPE_DATE": "Date" + "FIELD_TYPE_DATE": "Date", + "FIELD_TYPE_URL": "Url" }, "PROJECT_VALUES": { "PAGE_TITLE": "{{sectionName}} - Project values - {{projectName}}", @@ -543,7 +562,7 @@ "COUNT_MEMBERS": "{{ role.members_count }} jäsentä joilla tämä rooli", "TITLE_DELETE_ROLE": "Poista rooli", "REPLACEMENT_ROLE": "Kaikki käyttäjä joilla on tämä rooli siirretään", - "WARNING_DELETE_ROLE": "Ole varovainen, rooli-arvioinnit poistetaan", + "WARNING_DELETE_ROLE": "Be careful! All role estimations will be removed", "ERROR_DELETE_ALL": "Voit poistaa kaikki arvot", "EXTERNAL_USER": "Ulkoinen käyttäjä" }, @@ -671,6 +690,24 @@ }, "SUBMENU_THIDPARTIES": { "TITLE": "Palvelut" + }, + "PROJECT_TRANSFER": { + "DO_YOU_ACCEPT_PROJECT_OWNERNSHIP": "Would you like to become the new project owner?", + "PRIVATE": "Private", + "ACCEPTED_PROJECT_OWNERNSHIP": "Congratulations! You're now the new project owner.", + "REJECTED_PROJECT_OWNERNSHIP": "OK. We'll contact the current project owner", + "ACCEPT": "Hyväksy", + "REJECT": "Reject", + "PROPOSE_OWNERSHIP": "{{owner}}, the current owner of the project {{project}} has asked that you become the new project owner.", + "ADD_COMMENT_QUESTION": "Would you like to send a question to the project owner?", + "ADD_COMMENT": "Would you like to add a comment for the project owner?", + "UNLIMITED_PROJECTS": "Unlimited", + "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" + }, + "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" } }, "USER": { @@ -731,6 +768,11 @@ "FANS_COUNTER_TITLE": "{total, plural, one{one fan} other{# fans}}", "WATCHERS_COUNTER_TITLE": "{total, plural, one{one watcher} other{# watchers}}", "MEMBERS_COUNTER_TITLE": "{total, plural, one{one member} other{# members}}", + "BLOCKED_PROJECT": { + "BLOCKED": "Blocked project", + "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ä", @@ -777,6 +819,7 @@ "CHANGE_PASSWORD": "Muuta salasanaa", "DASHBOARD_TITLE": "Dashboard", "DISCOVER_TITLE": "Discover trending projects", + "NEW_ITEM": "Uusi", "DISCOVER": "Discover", "ACTION_REORDER": "Drag & drop to reorder" }, @@ -791,7 +834,32 @@ "ERROR_TOO_MANY_REQUEST": "Oompa Loompas ovat kiireisiä juuri nyt. Yritä hetken päästä uudelleen.", "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" + "SYNC_SUCCESS": "Projektisi on tuotu sisään onnistuneesti", + "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.", + "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 private 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": "The project that you are trying to import is private and has {{members}} members." + }, + "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." + } + } }, "LIKE_BUTTON": { "LIKE": "Like", @@ -819,8 +887,11 @@ "DELETE_ACCOUNT": { "SECTION_NAME": "Poista Taiga-tunnus", "CONFIRM": "Haluatko varmasti poistaa Taiga-tunnuksesi?", - "SUBTITLE": "Tulemme kaipaamaan sinua! :-(", - "NEWSLETTER_LABEL_TEXT": "En halua uutiskirjettä enää" + "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! :(" }, "DELETE_PROJECT": { "TITLE": "Poista projekti", @@ -876,7 +947,25 @@ }, "CREATE_MEMBER": { "PLACEHOLDER_INVITATION_TEXT": "(Vapaaehtoinen) Lisää oma kuvaus kutsuusi uusille jäsenille ;-)", - "PLACEHOLDER_TYPE_EMAIL": "Anna sähköposti" + "PLACEHOLDER_TYPE_EMAIL": "Anna sähköposti", + "LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "Unfortunately, this project can't have more than {{maxMembers}} members.
If you would like to increase the current limit, please contact the administrator.", + "LIMIT_USERS_WARNING_MESSAGE": "Unfortunately, this project can't have more than {{maxMembers}} members." + }, + "LEAVE_PROJECT_WARNING": { + "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" + }, + "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.", + "BUTTON": "Request project owner change" + } + }, + "CHANGE_OWNER": { + "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" } }, "US": { @@ -1304,12 +1393,18 @@ } }, "WIZARD": { - "SECTION_TITLE_CHOOSE_TEMPLATE": "Valitse pohja", - "CHOOSE_TEMPLATE_TEXT": "Mikä pohja sopii paremmin projektillesi?", "SECTION_TITLE_CREATE_PROJECT": "Luo projekti", "CREATE_PROJECT_TEXT": "Täysin koskematon. Jännittävää!", - "PROGRESS_TEMPLATE_SELECTION": "Pohjan valinta", - "PROGRESS_NAME_DESCRIPTION": "Nimi ja kuvaus" + "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}}", diff --git a/app/locales/taiga/locale-fr.json b/app/locales/taiga/locale-fr.json index 249be795..5af40473 100644 --- a/app/locales/taiga/locale-fr.json +++ b/app/locales/taiga/locale-fr.json @@ -24,7 +24,7 @@ "UNBLOCK": "Débloquer", "UNBLOCK_TITLE": "Débloquer cet élément", "BLOCKED_NOTE": "Pourquoi est-ce bloqué ?", - "BLOCKED_REASON": "Veillez s'il vous plait indiquer la raison", + "BLOCKED_REASON": "Veuillez s'il vous plait indiquer la raison", "CREATED_BY": "Créé par {{fullDisplayName}}", "FROM": "de", "TO": "à", @@ -38,10 +38,11 @@ "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é par une tâche ? Soyez certains d'en informer les autres en cliquant su 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": "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 !", "CLIENT_REQUIREMENT": "Un besoin client est un nouveau besoin qui n'était pas prévu et qu'il est nécessaire d'intégrer au projet", "TEAM_REQUIREMENT": "Un besoin projet est un besoin qui est nécessaire au projet mais qui ne doit avoir aucun impact pour le client", - "CAPSLOCK_WARNING": "Attention ! Vous tapez en lettres majuscules et ce champ est sensible à la casse.", + "OWNER": "Propriétaire du Projet", + "CAPSLOCK_WARNING": "Be careful! You are using capital letters in an input field that is case sensitive.", "FORM_ERRORS": { "DEFAULT_MESSAGE": "Cette valeur semble être invalide.", "TYPE_EMAIL": "Cette valeur devrait être une adresse courriel valide.", @@ -65,7 +66,9 @@ "MIN_CHECK": "Vous devez sélectionner au moins %s options.", "MAX_CHECK": "Vous devez sélectionner %s options ou moins.", "RANGE_CHECK": "Vous devez sélectionner parmi les choix %s et %s.", - "EQUAL_TO": "Cette valeur doit être identique." + "EQUAL_TO": "Cette valeur doit être identique.", + "LINEWIDTH": "One or more lines is perhaps too long. Try to keep under %s characters.", + "PIKADAY": "Invalid date format, please use DD MMM YYYY (like 23 Mar 1984)" }, "PICKERDATE": { "FORMAT": "DD MMM YYYY", @@ -116,7 +119,7 @@ "ADD": "Ajouter un mot-clé" }, "DESCRIPTION": { - "EMPTY": "Un espace vide est si ennuyeux… allez-y, soyez descriptif… ", + "EMPTY": "Un espace vide est si ennuyeux… allez-y, soyez descriptif…", "NO_DESCRIPTION": "Pas encore de description" }, "FIELDS": { @@ -144,13 +147,13 @@ }, "ASSIGNED_TO": { "NOT_ASSIGNED": "Non affecté", - "ASSIGN": "Assigné", + "ASSIGN": "Affecter", "DELETE_ASSIGNMENT": "Supprimer l'affectation", "REMOVE_ASSIGNED": "Supprimer l'affectation", "TOO_MANY": "...trop d'utilisateurs ; filtrez davantage", "CONFIRM_UNASSIGNED": "Etes-vous sûr de vouloir continuer sans affectation ?", "TITLE_ACTION_EDIT_ASSIGNMENT": "Modifier l'affectation", - "SELF": "Me l'assigné" + "SELF": "Me l'affecter" }, "STATUS": { "CLOSED": "Fermé", @@ -315,7 +318,8 @@ "PLACEHOLDER_FIELD": "Nom d'utilisateur ou adresse courriel", "ACTION_RESET_PASSWORD": "Réinitialiser le mot de passe", "LINK_CANCEL": "Nan, ramenez-moi en arrière. Je crois que je m'en souviens.", - "SUCCESS": "Consultez votre messagerie !
Nous venons d'envoyer un courriel avec les instructions pour créer un nouveau mot de passe", + "SUCCESS_TITLE": "Check your inbox!", + "SUCCESS_TEXT": "We sent you an email with the instructions to set a new password", "ERROR": "D'après nos Oompa Loompas, vous n'êtes pas encore enregistré." }, "CHANGE_PASSWORD": { @@ -373,7 +377,6 @@ "DEPRECATED_FILE": "Obsolète ?", "ADD": "Ajoutez une nouvelle pièce jointe. {{maxFileSizeMsg}}", "DROP": "Déposer les pièces jointes ici !", - "MAX_FILE_SIZE": "[Taille max. : {{maxFileSize}}]", "SHOW_DEPRECATED": "+ montrer les pièces jointes obsolètes", "HIDE_DEPRECATED": "- cacher les pièces jointes obsolètes", "COUNT_DEPRECATED": "({{ counter }} obsolètes)", @@ -406,7 +409,9 @@ "TITLE": "Gérer les membres", "PAGE_TITLE": "Membres - {{projectName}}", "ADD_BUTTON": "+ Nouveau membre", - "ADD_BUTTON_TITLE": "Ajouter un membre" + "ADD_BUTTON_TITLE": "Ajouter un membre", + "LIMIT_USERS_WARNING_MESSAGE_FOR_ADMIN": "Unfortunately, this project has reached its limit of ({{members}}) allowed members.", + "LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "This project has reached its limit of ({{members}}) allowed members. If you would like to increase that limit please contact the administrator." }, "PROJECT_EXPORT": { "TITLE": "Exporter", @@ -428,6 +433,10 @@ "DISABLE": "Désactiver", "BACKLOG": "Backlog", "BACKLOG_DESCRIPTION": "Gérez votre récits utilisateur pour garder une vue organisée des travaux à venir et priorisés.", + "NUMBER_SPRINTS": "Nombre prévu de sprints", + "NUMBER_SPRINTS_HELP": "0 for an undetermined number", + "NUMBER_US_POINTS": "Total prévu de points d'histoire", + "NUMBER_US_POINTS_HELP": "0 for an undetermined number", "KANBAN": "Kanban", "KANBAN_DESCRIPTION": "Organisez votre projet de manière agile avec ce tableau.", "ISSUES": "Tickets", @@ -435,9 +444,9 @@ "WIKI": "Wiki", "WIKI_DESCRIPTION": "Ajoutez, modifiez, ou supprimez du contenu en collaboration avec d'autres. C'est le bon endroit pour la documentation de votre projet.", "MEETUP": "Meet Up", - "MEETUP_DESCRIPTION": "Choisissez votre système de vidéoconférence. Même les développeurs ont besoin de contact en face à face.", + "MEETUP_DESCRIPTION": "Choisissez un système de vidéoconférence", "SELECT_VIDEOCONFERENCE": "Choisissez un système de vidéoconférence", - "SALT_CHAT_ROOM": "Si vous le souhaitez vous pouvez ajouter un code de salage au nom du salon de discussion", + "SALT_CHAT_ROOM": "Add a prefix to the chatroom name", "JITSI_CHAT_ROOM": "Jitsi", "APPEARIN_CHAT_ROOM": "AppearIn", "TALKY_CHAT_ROOM": "Talky", @@ -449,22 +458,31 @@ "PROJECT_DETAILS": "Détails du projet", "PROJECT_NAME": "Nom du projet", "PROJECT_SLUG": "Label du projet", - "NUMBER_SPRINTS": "Nombre de sprints (0 pour non déterminé)", - "NUMBER_US_POINTS": "Nombre de points de RU (0 pour non déterminé)", "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", "PUBLIC_PROJECT": "Projet public", - "PUBLIC_PROJECT_DESC": "Les membres vont pouvoir chercher et voir votre projet.", "PRIVATE_PROJECT": "Projet privé", - "PRIVATE_PROJECT_DESC": "Par défaut, ce project va être caché au public", "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 " + "ACTION_USE_DEFAULT_LOGO": "Utiliser l'image par défaut", + "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", + "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", + "REQUEST_OWNERSHIP": "Request ownership", + "REQUEST_OWNERSHIP_CONFIRMATION_TITLE": "Do you want to become the new project owner?", + "REQUEST_OWNERSHIP_DESC": "Request that current project owner {{name}} transfer ownership of this project to you.", + "REQUEST_OWNERSHIP_BUTTON": "Requête", + "REQUEST_OWNERSHIP_SUCCESS": "We'll notify the project owner", + "CHANGE_OWNER": "Change owner", + "CHANGE_OWNER_SUCCESS_TITLE": "Ok, your request has been sent!", + "CHANGE_OWNER_SUCCESS_DESC": "We will notify you by email if the project ownership request is accepted or declined" }, "REPORTS": { "TITLE": "Rapports", @@ -495,11 +513,12 @@ "ISSUE_ADD": "Ajouter un champ personnalisé dans les tickets", "FIELD_TYPE_TEXT": "Texte", "FIELD_TYPE_MULTI": "Multiligne", - "FIELD_TYPE_DATE": "Date" + "FIELD_TYPE_DATE": "Date", + "FIELD_TYPE_URL": "Url" }, "PROJECT_VALUES": { "PAGE_TITLE": "{{sectionName}} - Valeurs du projet - {{projectName}}", - "REPLACEMENT": "Tous les éléments avec cette valeur seront modifiés pour ", + "REPLACEMENT": "Tous les éléments avec cette valeur seront modifiés pour", "ERROR_DELETE_ALL": "Vous ne pouvez pas effacer toutes les valeurs." }, "PROJECT_VALUES_POINTS": { @@ -543,9 +562,9 @@ "COUNT_MEMBERS": "{{ role.members_count }} membres avec ce rôle", "TITLE_DELETE_ROLE": "Supprimer des rôles", "REPLACEMENT_ROLE": "Tous les utilisateurs avec ce rôle seront déplacés dans", - "WARNING_DELETE_ROLE": "Attention, toutes les estimations de rôle seront supprimées", + "WARNING_DELETE_ROLE": "Be careful! All role estimations will be removed", "ERROR_DELETE_ALL": "Vous ne pouvez pas supprimer toutes les valeurs", - "EXTERNAL_USER": "Utilisateur externe " + "EXTERNAL_USER": "Utilisateur externe" }, "THIRD_PARTIES": { "SECRET_KEY": "Clé secrète", @@ -583,7 +602,7 @@ "REQUEST": "Requête", "RESEND_REQUEST": "Renvoyer la requête", "HEADERS": "Entêtes", - "PAYLOAD": "Données utiles ", + "PAYLOAD": "Données utiles", "RESPONSE": "Réponse", "DATE": "DD MMM YYYY [at] hh:mm:ss", "ACTION_HIDE_HISTORY": "(Cacher l'historique)", @@ -671,6 +690,24 @@ }, "SUBMENU_THIDPARTIES": { "TITLE": "Services" + }, + "PROJECT_TRANSFER": { + "DO_YOU_ACCEPT_PROJECT_OWNERNSHIP": "Would you like to become the new project owner?", + "PRIVATE": "Private", + "ACCEPTED_PROJECT_OWNERNSHIP": "Congratulations! You're now the new project owner.", + "REJECTED_PROJECT_OWNERNSHIP": "OK. We'll contact the current project owner", + "ACCEPT": "Accepter", + "REJECT": "Reject", + "PROPOSE_OWNERSHIP": "{{owner}}, the current owner of the project {{project}} has asked that you become the new project owner.", + "ADD_COMMENT_QUESTION": "Would you like to send a question to the project owner?", + "ADD_COMMENT": "Would you like to add a comment for the project owner?", + "UNLIMITED_PROJECTS": "Unlimited", + "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" + }, + "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" } }, "USER": { @@ -703,7 +740,7 @@ }, "PROFILE_SIDEBAR": { "TITLE": "Votre profil", - "DESCRIPTION": "Tout le monde peut voir ce que vous fêtes et ce sur quoi vous travaillez. Ajoutez votre bio pour donner une version améliorée de vos informations.", + "DESCRIPTION": "Tout le monde peut voir ce que vous faites et ce sur quoi vous travaillez. Ajoutez votre bio pour donner une version améliorée de vos informations.", "ADD_INFO": "Editer la biographie" }, "PROFILE_FAVS": { @@ -731,6 +768,11 @@ "FANS_COUNTER_TITLE": "{total, plural, one{un fan} other{# fans}}", "WATCHERS_COUNTER_TITLE": "{total, plural, one{un observateur} other{# observateurs}}", "MEMBERS_COUNTER_TITLE": "{total, plural, one{un membre} other{# membres}}", + "BLOCKED_PROJECT": { + "BLOCKED": "Projet bloqué", + "THIS_PROJECT_IS_BLOCKED": "Ce projet est temporairement verrouillé", + "TO_UNBLOCK_CONTACT_THE_ADMIN_STAFF": "In order to unblock your projects, contact the administrator." + }, "STATS": { "PROJECT": "points
projet", "DEFINED": "points
définis", @@ -760,7 +802,7 @@ "TITLE_NEXT_PROJECT": "Montrer les projets suivants", "HELP_TITLE": "Page d'assistance Taiga", "HELP": "Aide", - "HOMEPAGE": "Page d'accueil ", + "HOMEPAGE": "Page d'accueil", "FEEDBACK_TITLE": "Envoyez vos commentaires", "FEEDBACK": "Feedback", "NOTIFICATIONS_TITLE": "Modifier vos réglages de notification", @@ -777,6 +819,7 @@ "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" }, @@ -791,7 +834,32 @@ "ERROR_TOO_MANY_REQUEST": "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 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" + "SYNC_SUCCESS": "Votre projet a été importé avec succès", + "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.", + "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 private 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": "The project that you are trying to import is private and has {{members}} members." + }, + "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." + } + } }, "LIKE_BUTTON": { "LIKE": "J'aime", @@ -819,8 +887,11 @@ "DELETE_ACCOUNT": { "SECTION_NAME": "Supprimer le compte Taiga", "CONFIRM": "Etes-vous sûr de vouloir supprimer votre compte Taiga ?", - "SUBTITLE": "Vous allez nous manquer ! :-(", - "NEWSLETTER_LABEL_TEXT": "Je ne veux plus recevoir votre bulletin d'information" + "NEWSLETTER_LABEL_TEXT": "Je ne veux plus recevoir votre bulletin d'information", + "CANCEL": "Retour aux réglages", + "ACCEPT": "Supprimer le compte", + "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! :(" }, "DELETE_PROJECT": { "TITLE": "Supprimer le projet", @@ -876,7 +947,25 @@ }, "CREATE_MEMBER": { "PLACEHOLDER_INVITATION_TEXT": "(Optionnel) Ajoutez un texte personnalisé à l'invitation. Dites quelque chose de gentil à vos nouveaux membres ;-)", - "PLACEHOLDER_TYPE_EMAIL": "Saisissez une adresse courriel" + "PLACEHOLDER_TYPE_EMAIL": "Saisissez une adresse courriel", + "LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "Unfortunately, this project can't have more than {{maxMembers}} members.
If you would like to increase the current limit, please contact the administrator.", + "LIMIT_USERS_WARNING_MESSAGE": "Unfortunately, this project can't have more than {{maxMembers}} members." + }, + "LEAVE_PROJECT_WARNING": { + "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" + }, + "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.", + "BUTTON": "Request project owner change" + } + }, + "CHANGE_OWNER": { + "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" } }, "US": { @@ -1013,7 +1102,7 @@ }, "SPRINT_SUMMARY": { "TOTAL_POINTS": "total
points", - "COMPLETED_POINTS": "complétés
points", + "COMPLETED_POINTS": "points
complétés", "OPEN_TASKS": "tâches
ouvertes", "CLOSED_TASKS": "tâches
fermées", "IOCAINE_DOSES": "doses
de iocaine", @@ -1108,7 +1197,7 @@ "IS_IOCAINE": "est sous iocaine" }, "ACTION_IOCAINE": "locaine", - "TITLE_ACTION_IOCAINE": "Vous vous sentez un peu dépassé 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 !" + "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": { "OK": "Tout est ok", @@ -1286,7 +1375,7 @@ "USER_PROFILE": { "IMAGE_HELP": "L'image va être agrandie à 80x80px", "ACTION_CHANGE_IMAGE": "Modifier", - "ACTION_USE_GRAVATAR": "Utiliser l'image par défaut ", + "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", "CHANGE_PHOTO": "Changer la photo", @@ -1300,16 +1389,22 @@ "LANGUAGE": "Langue", "LANGUAGE_DEFAULT": "-- utiliser la langue par défaut --", "THEME": "Thème", - "THEME_DEFAULT": "-- Utiliser la langue par défaut --" + "THEME_DEFAULT": "-- utiliser le thème par défaut --" } }, "WIZARD": { - "SECTION_TITLE_CHOOSE_TEMPLATE": "Choisissez un template", - "CHOOSE_TEMPLATE_TEXT": "Quel template conviendrait le mieux à votre projet ?", "SECTION_TITLE_CREATE_PROJECT": "Créer un projet", "CREATE_PROJECT_TEXT": "Tout beau, tout nouveau !", - "PROGRESS_TEMPLATE_SELECTION": "Choix du modèle", - "PROGRESS_NAME_DESCRIPTION": "Nom et description" + "CHOOSE_TEMPLATE": "Which template fits your project best?", + "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": "Unfortunately, you've reached the maximum number of public projects", + "CHANGE_PLANS": "changer de souscription" }, "WIKI": { "PAGE_TITLE": "{{wikiPageName}} - Wiki - {{projectName}}", @@ -1446,12 +1541,12 @@ } }, "DISCOVER": { - "PAGE_TITLE": "Discover projects - Taiga", + "PAGE_TITLE": "Découvrir les projets - 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": "Découvrir les projets", "DISCOVER_SUBTITLE": "{projects, plural, one{Un projet public à découvrir} other{# projets publics à découvrir}}", "MOST_ACTIVE": "les plus actifs", - "MOST_ACTIVE_EMPTY": "Il n'y a pas de projets actifs pour le moment", + "MOST_ACTIVE_EMPTY": "Il n'y a pas de projet actif pour le moment", "MOST_LIKED": "Les plus « aimés »", "MOST_LIKED_EMPTY": "Il n'y a pas encore de projet « aimé »", "VIEW_MORE": "Voir plus", @@ -1465,12 +1560,12 @@ "PEOPLE": "En recherche de membres", "WEEK": "Semaine dernière", "MONTH": "Mois dernier", - "YEAR": "Leanne dernière", + "YEAR": "Année dernière", "ALL_TIME": "Tout le temps", "CLEAR": "Effacer les filtres" }, "SEARCH": { - "PAGE_TITLE": "Search - Discover projects - Taiga", + "PAGE_TITLE": "Rechercher - Découvrir les projets - 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": "Écrivez quelque chose...", "ACTION_TITLE": "Rechercher", diff --git a/app/locales/taiga/locale-it.json b/app/locales/taiga/locale-it.json index 17f45748..ed6e9b2b 100644 --- a/app/locales/taiga/locale-it.json +++ b/app/locales/taiga/locale-it.json @@ -2,7 +2,7 @@ "COMMON": { "YES": "Sì", "NO": "No", - "OR": "or", + "OR": "o", "LOADING": "Caricamento...", "LOADING_PROJECT": "Stiamo caricando il progetto...", "DATE": "DD MMM YYYY", @@ -22,8 +22,8 @@ "BLOCK_TITLE": "Block this item for example if it has a dependency that can not be satisfied", "BLOCKED": "Bloccato", "UNBLOCK": "Sblocca", - "UNBLOCK_TITLE": "Unblock this item", - "BLOCKED_NOTE": "Why is this blocked?", + "UNBLOCK_TITLE": "Sblocca questo elemento", + "BLOCKED_NOTE": "Perché questo compito è bloccato?", "BLOCKED_REASON": "Spiega il motivo", "CREATED_BY": "Creato da {{fullDisplayName}}", "FROM": "da", @@ -41,7 +41,8 @@ "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!", "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", - "CAPSLOCK_WARNING": "Attento! stai scrivendo in maiuscolo e questo input è sensibile alle maiuscole..", + "OWNER": "Project Owner", + "CAPSLOCK_WARNING": "Be careful! You are using capital letters in an input field that is case sensitive.", "FORM_ERRORS": { "DEFAULT_MESSAGE": "Questo valore non è valido.", "TYPE_EMAIL": "Questo valore dovrebbe corrispondere ad una mail valida", @@ -65,7 +66,9 @@ "MIN_CHECK": "Devi selezionare almeno %s scelte.", "MAX_CHECK": "Devi selezionare la scelta %s o meno.", "RANGE_CHECK": "Devi selezionare tra %s e %s scelta.", - "EQUAL_TO": "Il valore dovrebbe essere uguale" + "EQUAL_TO": "Il valore dovrebbe essere uguale", + "LINEWIDTH": "One or more lines is perhaps too long. Try to keep under %s characters.", + "PIKADAY": "Invalid date format, please use DD MMM YYYY (like 23 Mar 1984)" }, "PICKERDATE": { "FORMAT": "DD MMM YYYY", @@ -315,7 +318,8 @@ "PLACEHOLDER_FIELD": "Nome utente o email", "ACTION_RESET_PASSWORD": "Reimposta la password", "LINK_CANCEL": "Fa niente dai, riportami indietro. Penso di ricordarmela.", - "SUCCESS": "Controlla la tua posta!
Ti abbiamo inviato una email con le istruzioni per reimpostare la password", + "SUCCESS_TITLE": "Check your inbox!", + "SUCCESS_TEXT": "We sent you an email with the instructions to set a new password", "ERROR": "Secondo i nostri Oompa Loompa, non sei ancora registrato." }, "CHANGE_PASSWORD": { @@ -373,7 +377,6 @@ "DEPRECATED_FILE": "Deprecato?", "ADD": "Aggiungi un nuovo allegato. {{maxFileSizeMsg}}", "DROP": "Rilascia qui l'allegato!", - "MAX_FILE_SIZE": "[Dimensione max. {{maxFileSize}}]", "SHOW_DEPRECATED": "+ visualizza allegati deprecati", "HIDE_DEPRECATED": "- nascondi allegati deprecati", "COUNT_DEPRECATED": "({{ counter }} deprecati)", @@ -406,7 +409,9 @@ "TITLE": "Gestisci membri", "PAGE_TITLE": "Webhooks - {{projectName}}", "ADD_BUTTON": "Nuovo Membro", - "ADD_BUTTON_TITLE": "Aggiungi un nuovo membro" + "ADD_BUTTON_TITLE": "Aggiungi un nuovo membro", + "LIMIT_USERS_WARNING_MESSAGE_FOR_ADMIN": "Unfortunately, this project has reached its limit of ({{members}}) allowed members.", + "LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "This project has reached its limit of ({{members}}) allowed members. If you would like to increase that limit please contact the administrator." }, "PROJECT_EXPORT": { "TITLE": "Esporta", @@ -428,6 +433,10 @@ "DISABLE": "Disabilita", "BACKLOG": "Backlog", "BACKLOG_DESCRIPTION": "Amministra le storie degli utenti per mantenere una visione organizzata dei lavori in arrivo e di quelli ad alta priorità ", + "NUMBER_SPRINTS": "Expected number of sprints", + "NUMBER_SPRINTS_HELP": "0 for an undetermined number", + "NUMBER_US_POINTS": "Expected total of story points", + "NUMBER_US_POINTS_HELP": "0 for an undetermined number", "KANBAN": "Kanban", "KANBAN_DESCRIPTION": "Organizza in modo semplice il tuo progetto con questa board", "ISSUES": "problemi", @@ -435,9 +444,9 @@ "WIKI": "Wiki", "WIKI_DESCRIPTION": "Aggiungi, modifica o elimina i contenuti in collaborazione con gli altri. E' il posto giusto per la documentazione del tuo progetto", "MEETUP": "Incontro", - "MEETUP_DESCRIPTION": "Scegli il tuo sistema di videoconferenza. Anche gli sviluppatori hanno bisogno di qualche contatto faccia a faccia. ", + "MEETUP_DESCRIPTION": "Choose your videoconference system.", "SELECT_VIDEOCONFERENCE": "Seleziona un sistema di videoconferenza", - "SALT_CHAT_ROOM": "Se preferisci puoi aggiungere un valore sale al nome della chat room", + "SALT_CHAT_ROOM": "Add a prefix to the chatroom name", "JITSI_CHAT_ROOM": "Jitsi", "APPEARIN_CHAT_ROOM": "AppearIn", "TALKY_CHAT_ROOM": "Talky", @@ -449,22 +458,31 @@ "PROJECT_DETAILS": "Dettagli progetto", "PROJECT_NAME": "Nome progetto", "PROJECT_SLUG": "Progetto lumaca", - "NUMBER_SPRINTS": "Numero di sprint (0 come quantità indeterminata)", - "NUMBER_US_POINTS": "Numero di punti delle storie utente (0 come quantità indeterminata)", "TAGS": "Tag", "DESCRIPTION": "Descrizione", "RECRUITING": "Il progetto cerca persone?", "RECRUITING_MESSAGE": "Chi stai cercando?", "RECRUITING_PLACEHOLDER": "Definisci il profilo che stai cercando", "PUBLIC_PROJECT": "Progetto pubblico", - "PUBLIC_PROJECT_DESC": "Gli utenti possono cercare e vedere il tuo progetto", "PRIVATE_PROJECT": "Progetto privato", - "PRIVATE_PROJECT_DESC": "Di default, il progetto sarà nascosto al pubblico", "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" + "ACTION_USE_DEFAULT_LOGO": "Usa l'immagine di default", + "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", + "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", + "REQUEST_OWNERSHIP": "Request ownership", + "REQUEST_OWNERSHIP_CONFIRMATION_TITLE": "Do you want to become the new project owner?", + "REQUEST_OWNERSHIP_DESC": "Request that current project owner {{name}} transfer ownership of this project to you.", + "REQUEST_OWNERSHIP_BUTTON": "Richiesta", + "REQUEST_OWNERSHIP_SUCCESS": "We'll notify the project owner", + "CHANGE_OWNER": "Change owner", + "CHANGE_OWNER_SUCCESS_TITLE": "Ok, your request has been sent!", + "CHANGE_OWNER_SUCCESS_DESC": "We will notify you by email if the project ownership request is accepted or declined" }, "REPORTS": { "TITLE": "Rapporti", @@ -495,7 +513,8 @@ "ISSUE_ADD": "Aggiungi un campo personalizzato alla criticitá", "FIELD_TYPE_TEXT": "Testo", "FIELD_TYPE_MULTI": "Multilinea", - "FIELD_TYPE_DATE": "Data" + "FIELD_TYPE_DATE": "Data", + "FIELD_TYPE_URL": "Url" }, "PROJECT_VALUES": { "PAGE_TITLE": "{{sectionName}} - Valori di progetto - {{projectName}}", @@ -543,7 +562,7 @@ "COUNT_MEMBERS": "{{ role.members_count }} membri con questo ruolo", "TITLE_DELETE_ROLE": "Elimina ruolo", "REPLACEMENT_ROLE": "Tutti gli utenti con questo ruolo saranno spostati a ", - "WARNING_DELETE_ROLE": "Attento, tutte le stime dei ruoli saranno eliminate", + "WARNING_DELETE_ROLE": "Be careful! All role estimations will be removed", "ERROR_DELETE_ALL": "Non puoi cancellare tutti i valori", "EXTERNAL_USER": "Utente esterno" }, @@ -671,6 +690,24 @@ }, "SUBMENU_THIDPARTIES": { "TITLE": "Servizi" + }, + "PROJECT_TRANSFER": { + "DO_YOU_ACCEPT_PROJECT_OWNERNSHIP": "Would you like to become the new project owner?", + "PRIVATE": "Private", + "ACCEPTED_PROJECT_OWNERNSHIP": "Congratulations! You're now the new project owner.", + "REJECTED_PROJECT_OWNERNSHIP": "OK. We'll contact the current project owner", + "ACCEPT": "Accetta", + "REJECT": "Reject", + "PROPOSE_OWNERSHIP": "{{owner}}, the current owner of the project {{project}} has asked that you become the new project owner.", + "ADD_COMMENT_QUESTION": "Would you like to send a question to the project owner?", + "ADD_COMMENT": "Would you like to add a comment for the project owner?", + "UNLIMITED_PROJECTS": "Unlimited", + "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" + }, + "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" } }, "USER": { @@ -731,6 +768,11 @@ "FANS_COUNTER_TITLE": "{total, plural, one{un follower} other{# followers}}", "WATCHERS_COUNTER_TITLE": "{total, plural, one{un osservatore} other{# osservatori}} ", "MEMBERS_COUNTER_TITLE": "{total, plural, one{un membro} other{# membri}}", + "BLOCKED_PROJECT": { + "BLOCKED": "Blocked project", + "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": "progetto
punti", "DEFINED": "Definiti
punti", @@ -777,6 +819,7 @@ "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" }, @@ -791,7 +834,32 @@ "ERROR_TOO_MANY_REQUEST": "Scusaci, i nostri Oompa Loompa sono di nuovo occupati. Riprova di nuovo in qualche minuto.", "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" + "SYNC_SUCCESS": "Il tuo progetto è stato importato con successo", + "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.", + "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 private 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": "The project that you are trying to import is private and has {{members}} members." + }, + "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." + } + } }, "LIKE_BUTTON": { "LIKE": "Mi piace", @@ -819,8 +887,11 @@ "DELETE_ACCOUNT": { "SECTION_NAME": "Elimina Account Taiga", "CONFIRM": "Sei sicuro di voler eliminare il tuo account Taiga?", - "SUBTITLE": "Ci mancherai! :-(", - "NEWSLETTER_LABEL_TEXT": "Non voglio più ricevere le vostre newsletter" + "NEWSLETTER_LABEL_TEXT": "Non voglio più ricevere le vostre newsletter", + "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! :(" }, "DELETE_PROJECT": { "TITLE": "Elimina progetto", @@ -876,7 +947,25 @@ }, "CREATE_MEMBER": { "PLACEHOLDER_INVITATION_TEXT": "(facoltativo) aggiungi un testo personalizzato all'invito. Di qualcosa di simpatico ai tuoi nuovi membri ;-)", - "PLACEHOLDER_TYPE_EMAIL": "Scrivi una mail" + "PLACEHOLDER_TYPE_EMAIL": "Scrivi una mail", + "LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "Unfortunately, this project can't have more than {{maxMembers}} members.
If you would like to increase the current limit, please contact the administrator.", + "LIMIT_USERS_WARNING_MESSAGE": "Unfortunately, this project can't have more than {{maxMembers}} members." + }, + "LEAVE_PROJECT_WARNING": { + "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" + }, + "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.", + "BUTTON": "Request project owner change" + } + }, + "CHANGE_OWNER": { + "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" } }, "US": { @@ -914,7 +1003,7 @@ "TYPE_NEW_COMMENT": "Scrivi un nuovo commento qui", "SHOW_DELETED": "Visualizza commento cancellato", "HIDE_DELETED": "Nascondi commento cancellato", - "DELETE": "Delete comment", + "DELETE": "Cancella commento", "RESTORE": "Ripristina commento" }, "ACTIVITY": { @@ -1304,12 +1393,18 @@ } }, "WIZARD": { - "SECTION_TITLE_CHOOSE_TEMPLATE": "Scegli il tema", - "CHOOSE_TEMPLATE_TEXT": "Quale template si adatta meglio al tuo progetto?", "SECTION_TITLE_CREATE_PROJECT": "Crea Progetto", "CREATE_PROJECT_TEXT": "Nuovo di zecca. Vai così!", - "PROGRESS_TEMPLATE_SELECTION": "Selezione del template", - "PROGRESS_NAME_DESCRIPTION": "Nome e descrizione" + "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": "Crea progetto", + "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}}", @@ -1446,7 +1541,7 @@ } }, "DISCOVER": { - "PAGE_TITLE": "Discover projects - Taiga", + "PAGE_TITLE": "Scopri i progetti - 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": "Scopri progetti", "DISCOVER_SUBTITLE": "{projects, plural, one{Un progetto pubblico da scoprire} other{# progetti pubblici da scoprire}}", @@ -1470,7 +1565,7 @@ "CLEAR": "Cancella filtri" }, "SEARCH": { - "PAGE_TITLE": "Search - Discover projects - Taiga", + "PAGE_TITLE": "Cerca - Scopri i progetti - 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": "Inserisci testo...", "ACTION_TITLE": "Cerca", diff --git a/app/locales/taiga/locale-nl.json b/app/locales/taiga/locale-nl.json index c1807b09..df0de862 100644 --- a/app/locales/taiga/locale-nl.json +++ b/app/locales/taiga/locale-nl.json @@ -2,7 +2,7 @@ "COMMON": { "YES": "Ja", "NO": "Nee", - "OR": "or", + "OR": "of", "LOADING": "Aan het laden...", "LOADING_PROJECT": "Project laden...", "DATE": "DD MMM YYYY", @@ -41,7 +41,8 @@ "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!", "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", - "CAPSLOCK_WARNING": "Let op! Je schrijft met alleen hoofdletters en dit veld is hoofdlettergevoelig.", + "OWNER": "Project Owner", + "CAPSLOCK_WARNING": "Be careful! You are using capital letters in an input field that is case sensitive.", "FORM_ERRORS": { "DEFAULT_MESSAGE": "Deze waarde lijkt ongeldig te zijn", "TYPE_EMAIL": "Deze waarde moet een geldig emailadres bevatten", @@ -65,7 +66,9 @@ "MIN_CHECK": "Je moet minstens %s opties selecteren.", "MAX_CHECK": "Je moet %s keuzes of minder selecteren.", "RANGE_CHECK": "Je moet tussen %s en %s keuzes selecteren.", - "EQUAL_TO": "Deze waarde zou hetzelfde moeten zijn." + "EQUAL_TO": "Deze waarde zou hetzelfde moeten zijn.", + "LINEWIDTH": "One or more lines is perhaps too long. Try to keep under %s characters.", + "PIKADAY": "Invalid date format, please use DD MMM YYYY (like 23 Mar 1984)" }, "PICKERDATE": { "FORMAT": "DD MMM YYYY", @@ -282,9 +285,9 @@ "HEADER": "Ik heb al een Taiga login", "PLACEHOLDER_AUTH_NAME": "Gebruikersnaam of email (case sensitive)", "LINK_FORGOT_PASSWORD": "Vergeten?", - "TITLE_LINK_FORGOT_PASSWORD": "Did you forget your password?", + "TITLE_LINK_FORGOT_PASSWORD": "Ben je je wachtwoord vergeten?", "ACTION_ENTER": "Enter", - "ACTION_SIGN_IN": "Login", + "ACTION_SIGN_IN": "Log in", "PLACEHOLDER_AUTH_PASSWORD": "Wachtwoord (hoofdlettergevoelig)" }, "LOGIN_FORM": { @@ -315,7 +318,8 @@ "PLACEHOLDER_FIELD": "Gebruikersnaam of e-mail", "ACTION_RESET_PASSWORD": "Wachtwoord resetten", "LINK_CANCEL": "Nah, stuur me terug. I denk dat ik het zal onthouden.", - "SUCCESS": "Controleer je inbox!
We hebben je een email gestuurd met instructie om een nieuw wachtwoord aan te maken", + "SUCCESS_TITLE": "Check your inbox!", + "SUCCESS_TEXT": "We sent you an email with the instructions to set a new password", "ERROR": "Volgens onze Oempa-Loempa's ben je nog niet geregisteerd" }, "CHANGE_PASSWORD": { @@ -336,7 +340,7 @@ "PLACEHOLDER_NEW_PASSWORD": "Nieuw wachtwoord", "PLACEHOLDER_RE_TYPE_NEW_PASSWORD": "Herhaal wachtwoord", "ACTION_RESET_PASSWORD": "Wachtwoord resetten", - "ERROR": "Our Oompa Loompas can't find your request to recover your password. Try to ask for it again.", + "ERROR": "Onze Oempa-Loempa's kunnen het verzoek om je wachtwoord te herstellen niet terugvinden. Probeer het nog een keer.", "SUCCESS": "Onze Oempa-Loempas hebben je nieuwe wachtwoord opgeslagen.
Probeer ermee in te loggen." }, "INVITATION": { @@ -351,8 +355,8 @@ "HOME": { "PAGE_TITLE": "Home -Taiga", "PAGE_DESCRIPTION": "De Taiga start pagina met jouw projecten en de aan jou toegewezen en gevolgde user stories, taken en issues", - "EMPTY_WORKING_ON": "It feels empty, doesn't it? Start working with Taiga and you'll see here the stories, tasks and issues you are workin on.", - "EMPTY_WATCHING": "Follow User Stories, Tasks, Issues in your projects and be notified about its changes :)", + "EMPTY_WORKING_ON": "Beetje kaal, vind je niet? Als je aan de slag gaat met Taiga, zie je hier de stories, taken en issues waar je aan werkt", + "EMPTY_WATCHING": "Volg User Stories, Taken, Issues binnen jouw projecten en ontvang een bericht bij veranderingen :)", "EMPTY_PROJECT_LIST": "Je hebt nog geen projecten", "WORKING_ON_SECTION": "Werkt aan", "WATCHING_SECTION": "Volgers", @@ -366,14 +370,13 @@ "ATTACHMENT": { "SECTION_NAME": "bijlagen", "TITLE": "{{ fileName }} toegevoegd op {{ date }}", - "LIST_VIEW_MODE": "List view mode", - "GALLERY_VIEW_MODE": "Gallery view mode", + "LIST_VIEW_MODE": "Lijst weergave", + "GALLERY_VIEW_MODE": "Afbeeldingweergave", "DESCRIPTION": "Geef een korte beschrijving", "DEPRECATED": "(verouderd)", "DEPRECATED_FILE": "Verouderd?", "ADD": "Nieuwe bijlage toevoegen. {{maxFileSizeMsg}}", "DROP": "Drop attachments here!", - "MAX_FILE_SIZE": "[Max. grootte: {{maxFileSize}}]", "SHOW_DEPRECATED": "+ toon verouderde bijlagen", "HIDE_DEPRECATED": "- verberg verouderde bijlagen", "COUNT_DEPRECATED": "({{ counter }} verouderd)", @@ -406,7 +409,9 @@ "TITLE": "Gebruikers beheren", "PAGE_TITLE": "Lidmaatschappen - {{projectName}}", "ADD_BUTTON": "+ Nieuwe gebruiker", - "ADD_BUTTON_TITLE": "Nieuwe gebruiker toevoegen" + "ADD_BUTTON_TITLE": "Nieuwe gebruiker toevoegen", + "LIMIT_USERS_WARNING_MESSAGE_FOR_ADMIN": "Unfortunately, this project has reached its limit of ({{members}}) allowed members.", + "LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "This project has reached its limit of ({{members}}) allowed members. If you would like to increase that limit please contact the administrator." }, "PROJECT_EXPORT": { "TITLE": "Export", @@ -428,6 +433,10 @@ "DISABLE": "Uitschakelen", "BACKLOG": "Backlog", "BACKLOG_DESCRIPTION": "Organiseer je user stories om een duidelijk overzicht van aankomend en geprioritiseerd werk te behouden.", + "NUMBER_SPRINTS": "Expected number of sprints", + "NUMBER_SPRINTS_HELP": "0 for an undetermined number", + "NUMBER_US_POINTS": "Expected total of story points", + "NUMBER_US_POINTS_HELP": "0 for an undetermined number", "KANBAN": "Kanban", "KANBAN_DESCRIPTION": "Organiseer je project volgens het lean principe met dit bord.", "ISSUES": "Issues", @@ -435,9 +444,9 @@ "WIKI": "Wiki\n", "WIKI_DESCRIPTION": "Voeg toe, wijzig of verwijder inhoud in samenwerking met anderen. Dit is the juiste plaats voor je project documentatie.", "MEETUP": "Meet Up", - "MEETUP_DESCRIPTION": "Kies je videoconference systeem. Zelfs programmeurs hebben face-to-face contact nodig.", + "MEETUP_DESCRIPTION": "Choose your videoconference system.", "SELECT_VIDEOCONFERENCE": "Kies een videoconference systeem", - "SALT_CHAT_ROOM": "Als je wil kan je een salt code aan de naam van de chatroom toevoegen", + "SALT_CHAT_ROOM": "Add a prefix to the chatroom name", "JITSI_CHAT_ROOM": "Jitsi", "APPEARIN_CHAT_ROOM": "AppearIn", "TALKY_CHAT_ROOM": "Talky", @@ -449,22 +458,31 @@ "PROJECT_DETAILS": "Project details", "PROJECT_NAME": "Naam project", "PROJECT_SLUG": "Project Slug", - "NUMBER_SPRINTS": "Aantal sprinten (0 voor een onbepaalde hoeveelheid)", - "NUMBER_US_POINTS": "Aantal US punten (0 voor een onbepaalde hoeveelheid)", "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", "PUBLIC_PROJECT": "Open project", - "PUBLIC_PROJECT_DESC": "Users will be able to find and view your project", "PRIVATE_PROJECT": "Gesloten project", - "PRIVATE_PROJECT_DESC": "By default, this project will be hidden to the public", "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" + "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", + "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", + "REQUEST_OWNERSHIP": "Request ownership", + "REQUEST_OWNERSHIP_CONFIRMATION_TITLE": "Do you want to become the new project owner?", + "REQUEST_OWNERSHIP_DESC": "Request that current project owner {{name}} transfer ownership of this project to you.", + "REQUEST_OWNERSHIP_BUTTON": "Verzoek", + "REQUEST_OWNERSHIP_SUCCESS": "We'll notify the project owner", + "CHANGE_OWNER": "Change owner", + "CHANGE_OWNER_SUCCESS_TITLE": "Ok, your request has been sent!", + "CHANGE_OWNER_SUCCESS_DESC": "We will notify you by email if the project ownership request is accepted or declined" }, "REPORTS": { "TITLE": "Rapporten", @@ -495,7 +513,8 @@ "ISSUE_ADD": "Voeg een aangepast veld toe in issues", "FIELD_TYPE_TEXT": "Tekst", "FIELD_TYPE_MULTI": "Over meerdere regels", - "FIELD_TYPE_DATE": "Date" + "FIELD_TYPE_DATE": "Date", + "FIELD_TYPE_URL": "Url" }, "PROJECT_VALUES": { "PAGE_TITLE": "{{sectionName}} - Project waardes - {{projectName}}", @@ -543,7 +562,7 @@ "COUNT_MEMBERS": "{{ role.members_count }} leden met deze rol", "TITLE_DELETE_ROLE": "Verwijder Rol", "REPLACEMENT_ROLE": "Al de gebruikers met deze rol zullen verplaats worden naar", - "WARNING_DELETE_ROLE": "Wees voorzichtig, alle schattingen door deze rol zullen worden verwijderd", + "WARNING_DELETE_ROLE": "Be careful! All role estimations will be removed", "ERROR_DELETE_ALL": "Je kan niet alle waarden verwijderen", "EXTERNAL_USER": "Externe gebruiker" }, @@ -671,6 +690,24 @@ }, "SUBMENU_THIDPARTIES": { "TITLE": "Services" + }, + "PROJECT_TRANSFER": { + "DO_YOU_ACCEPT_PROJECT_OWNERNSHIP": "Would you like to become the new project owner?", + "PRIVATE": "Private", + "ACCEPTED_PROJECT_OWNERNSHIP": "Congratulations! You're now the new project owner.", + "REJECTED_PROJECT_OWNERNSHIP": "OK. We'll contact the current project owner", + "ACCEPT": "Accepteren", + "REJECT": "Reject", + "PROPOSE_OWNERSHIP": "{{owner}}, the current owner of the project {{project}} has asked that you become the new project owner.", + "ADD_COMMENT_QUESTION": "Would you like to send a question to the project owner?", + "ADD_COMMENT": "Would you like to add a comment for the project owner?", + "UNLIMITED_PROJECTS": "Unlimited", + "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" + }, + "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" } }, "USER": { @@ -731,6 +768,11 @@ "FANS_COUNTER_TITLE": "{total, plural, one{one fan} other{# fans}}", "WATCHERS_COUNTER_TITLE": "{total, plural, one{one watcher} other{# watchers}}", "MEMBERS_COUNTER_TITLE": "{total, plural, one{one member} other{# members}}", + "BLOCKED_PROJECT": { + "BLOCKED": "Blocked project", + "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", @@ -777,6 +819,7 @@ "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" }, @@ -791,7 +834,32 @@ "ERROR_TOO_MANY_REQUEST": "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 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" + "SYNC_SUCCESS": "Je project werd met succes geïmporteerd", + "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.", + "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 private 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": "The project that you are trying to import is private and has {{members}} members." + }, + "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." + } + } }, "LIKE_BUTTON": { "LIKE": "Vind ik leuk", @@ -819,8 +887,11 @@ "DELETE_ACCOUNT": { "SECTION_NAME": "Taiga account verwijderen", "CONFIRM": "Weet je zeker dat je je Taiga account wilt verwijderen?", - "SUBTITLE": "We gaan je missen! :-(", - "NEWSLETTER_LABEL_TEXT": "Ik wil de nieuwsbrief niet meer ontvangen" + "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! :(" }, "DELETE_PROJECT": { "TITLE": "Verwijder project", @@ -876,7 +947,25 @@ }, "CREATE_MEMBER": { "PLACEHOLDER_INVITATION_TEXT": "(Optioneel) Voeg een gepersonaliseerd bericht toe aan je uitnodiging. Vertel iets leuks aan je nieuwe leden ;-)", - "PLACEHOLDER_TYPE_EMAIL": "Type en E-mail" + "PLACEHOLDER_TYPE_EMAIL": "Type en E-mail", + "LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "Unfortunately, this project can't have more than {{maxMembers}} members.
If you would like to increase the current limit, please contact the administrator.", + "LIMIT_USERS_WARNING_MESSAGE": "Unfortunately, this project can't have more than {{maxMembers}} members." + }, + "LEAVE_PROJECT_WARNING": { + "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" + }, + "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.", + "BUTTON": "Request project owner change" + } + }, + "CHANGE_OWNER": { + "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" } }, "US": { @@ -1171,7 +1260,7 @@ "SEVERITY": "Ernst", "PRIORITIES": "Prioriteiten", "TAGS": "Tags", - "ASSIGNED_TO": "Toegezen aan", + "ASSIGNED_TO": "Toegewezen aan", "CREATED_BY": "Aangemaakt door", "CUSTOM_FILTERS": "Eigen filters" }, @@ -1304,12 +1393,18 @@ } }, "WIZARD": { - "SECTION_TITLE_CHOOSE_TEMPLATE": "Kies een template", - "CHOOSE_TEMPLATE_TEXT": "Welk template zou beter bij je project passen?", "SECTION_TITLE_CREATE_PROJECT": "Project aanmaken", "CREATE_PROJECT_TEXT": "Vers en proper. Spanned!", - "PROGRESS_TEMPLATE_SELECTION": "Template selectie", - "PROGRESS_NAME_DESCRIPTION": "Naam en beschrijving" + "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}}", diff --git a/app/locales/taiga/locale-pl.json b/app/locales/taiga/locale-pl.json index d12e6d95..fb9db52f 100644 --- a/app/locales/taiga/locale-pl.json +++ b/app/locales/taiga/locale-pl.json @@ -41,7 +41,8 @@ "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!", "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", - "CAPSLOCK_WARNING": "UWAGA! Klawisz CAPSLOCK jest aktywny.", + "OWNER": "Project Owner", + "CAPSLOCK_WARNING": "Be careful! You are using capital letters in an input field that is case sensitive.", "FORM_ERRORS": { "DEFAULT_MESSAGE": "Nieprawidłowa wartość", "TYPE_EMAIL": "Podaj prawidłowy adres email.", @@ -65,7 +66,9 @@ "MIN_CHECK": "Musisz zaznaczyć przynajmniej %s pozycji.", "MAX_CHECK": "Musisz zaznaczyć %s pozycji lub mniej.", "RANGE_CHECK": "Musisz zaznaczyć pomiędzy %s a %s pozycji.", - "EQUAL_TO": "Ta wartość powinna być taka sama." + "EQUAL_TO": "Ta wartość powinna być taka sama.", + "LINEWIDTH": "One or more lines is perhaps too long. Try to keep under %s characters.", + "PIKADAY": "Invalid date format, please use DD MMM YYYY (like 23 Mar 1984)" }, "PICKERDATE": { "FORMAT": "DD MMM YYYY", @@ -315,7 +318,8 @@ "PLACEHOLDER_FIELD": "Login albo e-mail", "ACTION_RESET_PASSWORD": "Resetuj hasło", "LINK_CANCEL": "Nie, zabierz mnie stąd. Chyba je pamiętam.", - "SUCCESS": "Sprawdź swoją skrzynkę!
Wysłaliśmy Ci wiadomość e-mail z instrukcją jak ustawić nowe hasło.", + "SUCCESS_TITLE": "Check your inbox!", + "SUCCESS_TEXT": "We sent you an email with the instructions to set a new password", "ERROR": "Nasze Umpa Lumpy twierdzą, że nie jesteś jeszcze zarejestrowany." }, "CHANGE_PASSWORD": { @@ -373,7 +377,6 @@ "DEPRECATED_FILE": "Przestarzałe?", "ADD": "Dodaj nowy załącznik. {{maxFileSizeMsg}}", "DROP": "Drop attachments here!", - "MAX_FILE_SIZE": "[Maks. rozmiar: {{maxFileSize}}]", "SHOW_DEPRECATED": "+ pokaż przestarzałe załączniki", "HIDE_DEPRECATED": "- ukryj przestarzałe załączniki", "COUNT_DEPRECATED": "({{ counter }} przestarzałych", @@ -406,7 +409,9 @@ "TITLE": "Zarządzaj członkami", "PAGE_TITLE": "Członkostwa - {{projectName}}", "ADD_BUTTON": "+ Nowy członek", - "ADD_BUTTON_TITLE": "Dodaj nowego członka" + "ADD_BUTTON_TITLE": "Dodaj nowego członka", + "LIMIT_USERS_WARNING_MESSAGE_FOR_ADMIN": "Unfortunately, this project has reached its limit of ({{members}}) allowed members.", + "LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "This project has reached its limit of ({{members}}) allowed members. If you would like to increase that limit please contact the administrator." }, "PROJECT_EXPORT": { "TITLE": "Eksport", @@ -428,6 +433,10 @@ "DISABLE": "Wyłącz", "BACKLOG": "Dziennik", "BACKLOG_DESCRIPTION": "Zarządzaj swoimi historyjkami użytkownika aby utrzymać zorganizowany widok i priorytety zadań", + "NUMBER_SPRINTS": "Expected number of sprints", + "NUMBER_SPRINTS_HELP": "0 for an undetermined number", + "NUMBER_US_POINTS": "Expected total of story points", + "NUMBER_US_POINTS_HELP": "0 for an undetermined number", "KANBAN": "Kanban", "KANBAN_DESCRIPTION": "Organizuj swój projekt przy użyciu metody lean.", "ISSUES": "Zgłoszenia", @@ -435,9 +444,9 @@ "WIKI": "Wiki", "WIKI_DESCRIPTION": "Dodawaj, modyfikuj lub usuwaj dane we współpracy z innymi. To jest właściwe miejsce dla Twojej dokumentacji projektowej.", "MEETUP": "Spotkaj się", - "MEETUP_DESCRIPTION": "Wybierz system wideokonferencji. Nawet programiści potrzebują kontaktu twarzą w twarz.", + "MEETUP_DESCRIPTION": "Choose your videoconference system.", "SELECT_VIDEOCONFERENCE": "Wybierz system do wideokonferencji.", - "SALT_CHAT_ROOM": "Jeśli chcesz możesz dodać salt code do nazwy pokoju chatu.", + "SALT_CHAT_ROOM": "Add a prefix to the chatroom name", "JITSI_CHAT_ROOM": "Jitsi", "APPEARIN_CHAT_ROOM": "AppearIn", "TALKY_CHAT_ROOM": "Talky", @@ -449,22 +458,31 @@ "PROJECT_DETAILS": "Szczegóły projektu", "PROJECT_NAME": "Nazwa projektu", "PROJECT_SLUG": "Szczegóły projektu", - "NUMBER_SPRINTS": "Number of sprints (0 for an undetermined quantity)", - "NUMBER_US_POINTS": "Number of US points (0 for an undetermined quantity)", "TAGS": "Tagi", "DESCRIPTION": "Opis", "RECRUITING": "Is this project looking for people?", "RECRUITING_MESSAGE": "Who are you looking for?", "RECRUITING_PLACEHOLDER": "Define the profiles you are looking for", "PUBLIC_PROJECT": "Projekt publiczny", - "PUBLIC_PROJECT_DESC": "Users will be able to find and view your project", "PRIVATE_PROJECT": "Projekt prywatny", - "PRIVATE_PROJECT_DESC": "By default, this project will be hidden to the public", "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" + "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", + "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", + "REQUEST_OWNERSHIP": "Request ownership", + "REQUEST_OWNERSHIP_CONFIRMATION_TITLE": "Do you want to become the new project owner?", + "REQUEST_OWNERSHIP_DESC": "Request that current project owner {{name}} transfer ownership of this project to you.", + "REQUEST_OWNERSHIP_BUTTON": "Żądanie", + "REQUEST_OWNERSHIP_SUCCESS": "We'll notify the project owner", + "CHANGE_OWNER": "Change owner", + "CHANGE_OWNER_SUCCESS_TITLE": "Ok, your request has been sent!", + "CHANGE_OWNER_SUCCESS_DESC": "We will notify you by email if the project ownership request is accepted or declined" }, "REPORTS": { "TITLE": "Raporty", @@ -495,7 +513,8 @@ "ISSUE_ADD": "Dodaj własne pole dla zgłoszeń", "FIELD_TYPE_TEXT": "Tekst", "FIELD_TYPE_MULTI": "Pole wielowierszowe", - "FIELD_TYPE_DATE": "Date" + "FIELD_TYPE_DATE": "Date", + "FIELD_TYPE_URL": "Url" }, "PROJECT_VALUES": { "PAGE_TITLE": "{{sectionName}} - Wartości projektu - {{projectName}}", @@ -543,7 +562,7 @@ "COUNT_MEMBERS": "{{ role.members_count }} użytkowników pełniących tę rolę w projekcie", "TITLE_DELETE_ROLE": "Usuń rolę", "REPLACEMENT_ROLE": "Wszyscy użytkownicy pełniący tę rolę zostaną przeniesieni do", - "WARNING_DELETE_ROLE": "Ostrożnie, wszystkie estymaty dodane przez ludzi pełniących tę rolę zostaną usunięte", + "WARNING_DELETE_ROLE": "Be careful! All role estimations will be removed", "ERROR_DELETE_ALL": "Nie możesz usunąć wszystkich wartości", "EXTERNAL_USER": "Zewnętrzny użytkownik" }, @@ -671,6 +690,24 @@ }, "SUBMENU_THIDPARTIES": { "TITLE": "Ważność" + }, + "PROJECT_TRANSFER": { + "DO_YOU_ACCEPT_PROJECT_OWNERNSHIP": "Would you like to become the new project owner?", + "PRIVATE": "Private", + "ACCEPTED_PROJECT_OWNERNSHIP": "Congratulations! You're now the new project owner.", + "REJECTED_PROJECT_OWNERNSHIP": "OK. We'll contact the current project owner", + "ACCEPT": "Akceptuj", + "REJECT": "Reject", + "PROPOSE_OWNERSHIP": "{{owner}}, the current owner of the project {{project}} has asked that you become the new project owner.", + "ADD_COMMENT_QUESTION": "Would you like to send a question to the project owner?", + "ADD_COMMENT": "Would you like to add a comment for the project owner?", + "UNLIMITED_PROJECTS": "Unlimited", + "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" + }, + "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" } }, "USER": { @@ -731,6 +768,11 @@ "FANS_COUNTER_TITLE": "{total, plural, one{one fan} other{# fans}}", "WATCHERS_COUNTER_TITLE": "{total, plural, one{one watcher} other{# watchers}}", "MEMBERS_COUNTER_TITLE": "{total, plural, one{one member} other{# members}}", + "BLOCKED_PROJECT": { + "BLOCKED": "Blocked project", + "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": "projekt
punkty", "DEFINED": "zdefiniowane
punkty", @@ -777,6 +819,7 @@ "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ść" }, @@ -791,7 +834,32 @@ "ERROR_TOO_MANY_REQUEST": "Umpa Lumpy są teraz zajęte a serwer ma zadyszkę. 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!" + "SYNC_SUCCESS": "Twój projekt zaimportował się prawidłowo!", + "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.", + "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 private 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": "The project that you are trying to import is private and has {{members}} members." + }, + "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." + } + } }, "LIKE_BUTTON": { "LIKE": "Like", @@ -819,8 +887,11 @@ "DELETE_ACCOUNT": { "SECTION_NAME": "Usuń konto z Taiga", "CONFIRM": "Czy na pewno chcesz usunąć swoje konto z Taiga?", - "SUBTITLE": "Będziemy tęsknić! :(", - "NEWSLETTER_LABEL_TEXT": "Nie chcę więcej otrzymywać waszego newslettera" + "NEWSLETTER_LABEL_TEXT": "Nie chcę więcej otrzymywać waszego newslettera", + "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! :(" }, "DELETE_PROJECT": { "TITLE": "Usuń projekt", @@ -876,7 +947,25 @@ }, "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" + "PLACEHOLDER_TYPE_EMAIL": "Wpisz Email", + "LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "Unfortunately, this project can't have more than {{maxMembers}} members.
If you would like to increase the current limit, please contact the administrator.", + "LIMIT_USERS_WARNING_MESSAGE": "Unfortunately, this project can't have more than {{maxMembers}} members." + }, + "LEAVE_PROJECT_WARNING": { + "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" + }, + "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.", + "BUTTON": "Request project owner change" + } + }, + "CHANGE_OWNER": { + "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" } }, "US": { @@ -1304,12 +1393,18 @@ } }, "WIZARD": { - "SECTION_TITLE_CHOOSE_TEMPLATE": "Wybierz szablon", - "CHOOSE_TEMPLATE_TEXT": "Który szablon lepiej pasuje do Twojego projektu?", "SECTION_TITLE_CREATE_PROJECT": "Utwórz projekt", "CREATE_PROJECT_TEXT": "Nowy, zwinny! To takie ekscytujące!", - "PROGRESS_TEMPLATE_SELECTION": "Wybór szablonu", - "PROGRESS_NAME_DESCRIPTION": "Nazwa i opis" + "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": "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}}", diff --git a/app/locales/taiga/locale-pt-br.json b/app/locales/taiga/locale-pt-br.json index d4754245..2e78ad2d 100644 --- a/app/locales/taiga/locale-pt-br.json +++ b/app/locales/taiga/locale-pt-br.json @@ -2,7 +2,7 @@ "COMMON": { "YES": "Sim", "NO": "Não", - "OR": "or", + "OR": "ou", "LOADING": "Carregando...", "LOADING_PROJECT": "Carregando o projeto...", "DATE": "DD MMM YYYY", @@ -19,11 +19,11 @@ "TAG_LINE": "Sua ferramenta de código aberto, gratuita e ágil.", "TAG_LINE_2": "AME SEU PROJETO", "BLOCK": "Bloquear", - "BLOCK_TITLE": "Block this item for example if it has a dependency that can not be satisfied", + "BLOCK_TITLE": "Bloqueia este item, por exemplo, se ele possui uma dependência não resolvida", "BLOCKED": "Bloqueado", "UNBLOCK": "Desbloquear", - "UNBLOCK_TITLE": "Unblock this item", - "BLOCKED_NOTE": "Why is this blocked?", + "UNBLOCK_TITLE": "Desbloquear este item", + "BLOCKED_NOTE": "Por que esta bloqueado?", "BLOCKED_REASON": "Por favor, explique a razão", "CREATED_BY": "Criado por {{fullDisplayName}}", "FROM": "de", @@ -41,7 +41,8 @@ "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!", "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", - "CAPSLOCK_WARNING": "Seja cuidadoso! Você está escrevendo em letras maiúsculas e esse campo é case sensitive, ou seja trata com distinção letras maiúsculas das minúsculas", + "OWNER": "Project Owner", + "CAPSLOCK_WARNING": "Be careful! You are using capital letters in an input field that is case sensitive.", "FORM_ERRORS": { "DEFAULT_MESSAGE": "Este valor parece ser inválido.", "TYPE_EMAIL": "Este valor deve ser um e-mail válido.", @@ -65,7 +66,9 @@ "MIN_CHECK": "Você deve selecionar pelo menos %s escolhas.", "MAX_CHECK": "Você deve selecionar %s escolhas ou menos.", "RANGE_CHECK": "Você deve selecionar entre %s e %s escolhas.", - "EQUAL_TO": "Esse valor deveria ser o mesmo." + "EQUAL_TO": "Esse valor deveria ser o mesmo.", + "LINEWIDTH": "One or more lines is perhaps too long. Try to keep under %s characters.", + "PIKADAY": "Invalid date format, please use DD MMM YYYY (like 23 Mar 1984)" }, "PICKERDATE": { "FORMAT": "DD MMM YYYY", @@ -205,11 +208,11 @@ "BOLD_BUTTON_SAMPLE_TEXT": "Seu texto aqui...", "ITALIC_BUTTON": "Itálico", "ITALIC_SAMPLE_TEXT": "Seu texto aqui...", - "STRIKE_BUTTON": "Strike", + "STRIKE_BUTTON": "Riscar", "STRIKE_SAMPLE_TEXT": "Seu texto aqui...", - "BULLETED_LIST_BUTTON": "Lista de Marcadores", + "BULLETED_LIST_BUTTON": "Lista de marcadores", "BULLETED_LIST_SAMPLE_TEXT": "Seu texto aqui...", - "NUMERIC_LIST_BUTTON": "Lista Numérica", + "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...", @@ -217,7 +220,7 @@ "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_BUTTON": "Bloco de código", "CODE_BLOCK_SAMPLE_TEXT": "Seu texto aqui...", "PREVIEW_BUTTON": "Pré Visualizar", "EDIT_BUTTON": "Editar", @@ -229,13 +232,13 @@ "VIEW_SPRINTS": "Ver sprints", "ADD_SPRINTS": "Adicionar sprints", "MODIFY_SPRINTS": "Modificar sprints", - "DELETE_SPRINTS": "Apagar Sprints" + "DELETE_SPRINTS": "Apagar sprints" }, "USER_STORIES": { "NAME": "User Stories", "VIEW_USER_STORIES": "Ver user stories", "ADD_USER_STORIES": "Adicionar user stories", - "MODIFY_USER_STORIES": "Modificar user stories", + "MODIFY_USER_STORIES": "Modificar estórias de usuário", "DELETE_USER_STORIES": "Apagar user stories" }, "TASKS": { @@ -315,7 +318,8 @@ "PLACEHOLDER_FIELD": "Nome de usuário ou email", "ACTION_RESET_PASSWORD": "Resetar Senha", "LINK_CANCEL": "Nããão, me leve de volta. Acho que me lembrei.", - "SUCCESS": "Verifique sua conta de email
Enviamos um email com as instruções para configurar uma nova senha", + "SUCCESS_TITLE": "Check your inbox!", + "SUCCESS_TEXT": "We sent you an email with the instructions to set a new password", "ERROR": "Segundo nossos Oompa Loompas, você ainda não está inscrito." }, "CHANGE_PASSWORD": { @@ -350,9 +354,9 @@ }, "HOME": { "PAGE_TITLE": "Início - Taiga", - "PAGE_DESCRIPTION": "A página inicial do Taiga contém seus projetos principais e todos as user stories atribuídas ou observadas por você, tarefas e casos", - "EMPTY_WORKING_ON": "Isso parece vazio não acha? Comece a trabalhar com Taiga para começar a ver estórias, tarefas e casos em que está trabalhando.", - "EMPTY_WATCHING": "Siga Estórias, Tarefas e Casos nos seus projetos e seja notificado das mudanças :)", + "PAGE_DESCRIPTION": "A página inicial do Taiga com seus principais projetos e todas as estórias atribuídas ou observadas por você, tarefas e problemas", + "EMPTY_WORKING_ON": "Isso parece vazio não acha? Comece a trabalhar com Taiga para começar a ver estórias, tarefas e problemas em que está trabalhando.", + "EMPTY_WATCHING": "Siga Estórias, Tarefas e Problemas nos seus projetos e seja notificado das mudanças :)", "EMPTY_PROJECT_LIST": "Você ainda não tem projetos", "WORKING_ON_SECTION": "Trabalhando em", "WATCHING_SECTION": "Observando", @@ -366,14 +370,13 @@ "ATTACHMENT": { "SECTION_NAME": "anexos", "TITLE": "{{ fileName }} enviado em {{ date }}", - "LIST_VIEW_MODE": "List view mode", - "GALLERY_VIEW_MODE": "Gallery view mode", + "LIST_VIEW_MODE": "Modo de visualização lista", + "GALLERY_VIEW_MODE": "Modo de Visualização Galeria", "DESCRIPTION": "Escreva uma curta descrição", "DEPRECATED": "(obsoleto)", "DEPRECATED_FILE": "Obsoleto?", "ADD": "Adicionar novo anexo. {{maxFileSizeMsg}}", "DROP": "Jogue os anexos aqui!", - "MAX_FILE_SIZE": "[Tamanho Máximo: {{maxFileSize}}]", "SHOW_DEPRECATED": "+ mostrar anexos deprecados", "HIDE_DEPRECATED": "- esconder anexos obsoletos", "COUNT_DEPRECATED": "({{ counter }} deprecados)", @@ -406,7 +409,9 @@ "TITLE": "Gerenciar Membros", "PAGE_TITLE": "Filiados - {{projectName}}", "ADD_BUTTON": "+ Novo Membro", - "ADD_BUTTON_TITLE": "Adicionar novo membro" + "ADD_BUTTON_TITLE": "Adicionar novo membro", + "LIMIT_USERS_WARNING_MESSAGE_FOR_ADMIN": "Unfortunately, this project has reached its limit of ({{members}}) allowed members.", + "LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "This project has reached its limit of ({{members}}) allowed members. If you would like to increase that limit please contact the administrator." }, "PROJECT_EXPORT": { "TITLE": "Exportar", @@ -428,16 +433,20 @@ "DISABLE": "Desabilitar", "BACKLOG": "Backlog", "BACKLOG_DESCRIPTION": "Gerencie suas user stories para manter uma visualização organizada de trabalhos futuros e priorizados.", + "NUMBER_SPRINTS": "Expected number of sprints", + "NUMBER_SPRINTS_HELP": "0 for an undetermined number", + "NUMBER_US_POINTS": "Expected total of story points", + "NUMBER_US_POINTS_HELP": "0 for an undetermined number", "KANBAN": "Kanban", "KANBAN_DESCRIPTION": "Organize seu projeto de um jeito \"lean\" com esse mural", - "ISSUES": "Casos", + "ISSUES": "Problemas", "ISSUES_DESCRIPTION": "Acompanhe os bugs, questões e melhorias relacionadas ao seu projeto. Não perca nada!", "WIKI": "Wiki", "WIKI_DESCRIPTION": "Adicione, modifique ou apague conteúdo em colaboração com outras pessoas. Este é o local certo pra documentação do seu projeto.", "MEETUP": "Reunião", - "MEETUP_DESCRIPTION": "Escolha seu sistema de vídeo conferência. Até desenvolvedores precisam de contato cara a cara.", + "MEETUP_DESCRIPTION": "Choose your videoconference system.", "SELECT_VIDEOCONFERENCE": "Selecione um sistema de video conferência", - "SALT_CHAT_ROOM": "Se você quiser, pode acrescentar um 'salt code' para o nome da sala de bate-papo", + "SALT_CHAT_ROOM": "Add a prefix to the chatroom name", "JITSI_CHAT_ROOM": "Jitsi", "APPEARIN_CHAT_ROOM": "AppearIn", "TALKY_CHAT_ROOM": "Talky", @@ -449,22 +458,31 @@ "PROJECT_DETAILS": "Detalhes do projeto", "PROJECT_NAME": "Nome do projeto", "PROJECT_SLUG": "Slug do projeto", - "NUMBER_SPRINTS": "Número de sprints (0 para uma quantidade indeterminada)", - "NUMBER_US_POINTS": "Número de pontos US (0 para uma quantidade indeterminada)", "TAGS": "Tags", "DESCRIPTION": "Descrição", - "RECRUITING": "Is this project looking for people?", + "RECRUITING": "Este projeto esta a procura de colaboradores?", "RECRUITING_MESSAGE": "O que você está procurando?", - "RECRUITING_PLACEHOLDER": "Define the profiles you are looking for", + "RECRUITING_PLACEHOLDER": "Defina o perfil que você procura?", "PUBLIC_PROJECT": "Projeto Publico", - "PUBLIC_PROJECT_DESC": "Users will be able to find and view your project", "PRIVATE_PROJECT": "Projeto Privado", - "PRIVATE_PROJECT_DESC": "Por padrão, esse projeto é escondido do público", "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" + "ACTION_USE_DEFAULT_LOGO": "Usar imagem padrão", + "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", + "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", + "REQUEST_OWNERSHIP": "Request ownership", + "REQUEST_OWNERSHIP_CONFIRMATION_TITLE": "Do you want to become the new project owner?", + "REQUEST_OWNERSHIP_DESC": "Request that current project owner {{name}} transfer ownership of this project to you.", + "REQUEST_OWNERSHIP_BUTTON": "Solicitação", + "REQUEST_OWNERSHIP_SUCCESS": "We'll notify the project owner", + "CHANGE_OWNER": "Change owner", + "CHANGE_OWNER_SUCCESS_TITLE": "Ok, your request has been sent!", + "CHANGE_OWNER_SUCCESS_DESC": "We will notify you by email if the project ownership request is accepted or declined" }, "REPORTS": { "TITLE": "Relatórios", @@ -477,7 +495,7 @@ "CSV": { "SECTION_TITLE_US": "Relatórios de user stories", "SECTION_TITLE_TASK": "relatórios de tarefas", - "SECTION_TITLE_ISSUE": "relatórios de casos", + "SECTION_TITLE_ISSUE": "relatórios de problemas", "DOWNLOAD": "Baixar CSV", "URL_FIELD_PLACEHOLDER": "Por favor, gere novamente a url do CSV", "TITLE_REGENERATE_URL": "Regerar URL CSV", @@ -486,16 +504,17 @@ }, "CUSTOM_FIELDS": { "TITLE": "Campos Personalizados", - "SUBTITLE": "Especificar campos personalizados para user stories, tarefas e casos", + "SUBTITLE": "Especificar campos personalizados para estórias, tarefas e problemas", "US_DESCRIPTION": "Campos personalizados das user stories", "US_ADD": "Adicionar campo personalizado nas user stories", "TASK_DESCRIPTION": "Campos personalizados das Tarefas\n", "TASK_ADD": "Adicionar campos personalizados na tarefa", - "ISSUE_DESCRIPTION": "Campos personalizados dos casos", - "ISSUE_ADD": "Adicionar um campo personalizado no caso", + "ISSUE_DESCRIPTION": "Campos personalizados dos problemas", + "ISSUE_ADD": "Adicionar um campo personalizado no problema", "FIELD_TYPE_TEXT": "Texto", "FIELD_TYPE_MULTI": "Multi-linha", - "FIELD_TYPE_DATE": "Data" + "FIELD_TYPE_DATE": "Data", + "FIELD_TYPE_URL": "Url" }, "PROJECT_VALUES": { "PAGE_TITLE": "{{sectionName}} - Valores do projeto - {{projectName}}", @@ -510,26 +529,26 @@ }, "PROJECT_VALUES_PRIORITIES": { "TITLE": "Prioridades", - "SUBTITLE": "Especifique as prioridades que seus casos terão", - "ISSUE_TITLE": "Prioridades do caso", + "SUBTITLE": "Especifique as prioridades que seus problemas terão", + "ISSUE_TITLE": "Prioridades do problema", "ACTION_ADD": "Adicionar nova prioridade" }, "PROJECT_VALUES_SEVERITIES": { "TITLE": "Seriedades", - "SUBTITLE": "Especifique a severidade que seus casos terão", - "ISSUE_TITLE": "Seriedades do caso", + "SUBTITLE": "Especifique as severidades que seus problemas terão", + "ISSUE_TITLE": "Seriedades do problema", "ACTION_ADD": "Adicionar nova severidade" }, "PROJECT_VALUES_STATUS": { "TITLE": "Situação", - "SUBTITLE": "Especifique os status pelos quais suas user stories, tarefas e casos passarão", + "SUBTITLE": "Especifique os status pelos quais suas estórias, tarefas e problemas passarão", "US_TITLE": "Estados das Users Strories", "TASK_TITLE": "Estados da tarefa", "ISSUE_TITLE": "Estados do caso" }, "PROJECT_VALUES_TYPES": { "TITLE": "Tipos", - "SUBTITLE": "Especifique os tipos que seu caso pode ser", + "SUBTITLE": "Especifique os tipos que seu problema pode ser", "ISSUE_TITLE": "Tipos de casos", "ACTION_ADD": "Adicionar novo {{objName}}" }, @@ -543,7 +562,7 @@ "COUNT_MEMBERS": "{{ role.members_count }} membros com a mesma função", "TITLE_DELETE_ROLE": "Apagar Função", "REPLACEMENT_ROLE": "Todos os usuários com essa função serão movidos para", - "WARNING_DELETE_ROLE": "Seja cuidadoso, todas as estimativas para as funções serão removidas.", + "WARNING_DELETE_ROLE": "Be careful! All role estimations will be removed", "ERROR_DELETE_ALL": "Você não pode apagar todos os valores", "EXTERNAL_USER": "Usuário externo" }, @@ -671,6 +690,24 @@ }, "SUBMENU_THIDPARTIES": { "TITLE": "Serviços" + }, + "PROJECT_TRANSFER": { + "DO_YOU_ACCEPT_PROJECT_OWNERNSHIP": "Would you like to become the new project owner?", + "PRIVATE": "Private", + "ACCEPTED_PROJECT_OWNERNSHIP": "Congratulations! You're now the new project owner.", + "REJECTED_PROJECT_OWNERNSHIP": "OK. We'll contact the current project owner", + "ACCEPT": "Aceitar", + "REJECT": "Reject", + "PROPOSE_OWNERSHIP": "{{owner}}, the current owner of the project {{project}} has asked that you become the new project owner.", + "ADD_COMMENT_QUESTION": "Would you like to send a question to the project owner?", + "ADD_COMMENT": "Would you like to add a comment for the project owner?", + "UNLIMITED_PROJECTS": "Unlimited", + "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" + }, + "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" } }, "USER": { @@ -703,7 +740,7 @@ }, "PROFILE_SIDEBAR": { "TITLE": "Seu perfil", - "DESCRIPTION": "People can see everything you do and what you are working on. Add a nice bio to give an enhanced version of your information.", + "DESCRIPTION": "As pessoas podem ver tudo que você faz e no que você está trabalhando. Adicione uma bela biografia para disponibilizar uma versão melhorada das sua informações.", "ADD_INFO": "Editar biografia" }, "PROFILE_FAVS": { @@ -716,7 +753,7 @@ "FILTER_TYPE_USER_STORIES_TITLES": "Mostrar apenas user stories", "FILTER_TYPE_TASKS": "Tarefas", "FILTER_TYPE_TASK_TITLES": "Mostrar apenas tarefas", - "FILTER_TYPE_ISSUES": "Casos", + "FILTER_TYPE_ISSUES": "Problemas", "FILTER_TYPE_ISSUES_TITLE": "mostrar apenas problemas", "EMPTY_TITLE": "Parece que não há nada para exibir aqui." } @@ -727,10 +764,15 @@ "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": "This project is looking for people", + "LOOKING_FOR_PEOPLE": "Este projeto esta a procura de colaboradores", "FANS_COUNTER_TITLE": "{total, plural, um{um fã} outro{# fãs}}", "WATCHERS_COUNTER_TITLE": "{total, plural, um{um observador} outro{#watchers}}", "MEMBERS_COUNTER_TITLE": "{total, plural, um{one member} outro{# members}}", + "BLOCKED_PROJECT": { + "BLOCKED": "Blocked project", + "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": "projetos
pontos", "DEFINED": "pontos
definidos", @@ -742,7 +784,7 @@ "TIMELINE": "Linha do Tempo", "BACKLOG": "Backlog", "KANBAN": "Kanban", - "ISSUES": "Casos", + "ISSUES": "Problemas", "WIKI": "Wiki", "TEAM": "Time", "MEETUP": "Reunião", @@ -777,6 +819,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" }, @@ -791,7 +834,32 @@ "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" + "SYNC_SUCCESS": "Seu projeto foi importado com sucesso", + "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.", + "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 private 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": "The project that you are trying to import is private and has {{members}} members." + }, + "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." + } + } }, "LIKE_BUTTON": { "LIKE": "Curtir", @@ -819,13 +887,16 @@ "DELETE_ACCOUNT": { "SECTION_NAME": "Apagar conta no Taiga", "CONFIRM": "Você tem certeza que quer apagar sua conta Taiga?", - "SUBTITLE": "Nós vamos sentir sua falta! :-(", - "NEWSLETTER_LABEL_TEXT": "Eu não quero receber mais os informativos" + "NEWSLETTER_LABEL_TEXT": "Eu não quero receber mais os informativos", + "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! :(" }, "DELETE_PROJECT": { "TITLE": "Apagar projeto", "QUESTION": "Você tem certeza que quer apagar este projeto?", - "SUBTITLE": "Todas as informações do projeto (estórias de uso, tarefas, casos, sprints e páginas de wiki) serão perdidos! :-(", + "SUBTITLE": "Todas as informações do projeto (estórias, tarefas, problemas, sprints e páginas de wiki) serão perdidos! :-(", "CONFIRM": "Sim, eu tenho certeza" }, "ASSIGNED_TO": { @@ -837,7 +908,7 @@ "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": { - "TITLE": "Adicionar caso" + "TITLE": "Adicionar problema" }, "FEEDBACK": { "TITLE": "Diga-nos algo...", @@ -850,10 +921,10 @@ }, "ADD_EDIT_SPRINT": { "TITLE": "Novo Sprint", - "PLACEHOLDER_SPRINT_NAME": "nome do Sprint", + "PLACEHOLDER_SPRINT_NAME": "nome do sprint", "PLACEHOLDER_SPRINT_START": "Inicio Estimado", "PLACEHOLDER_SPRINT_END": "Estimativa de Termino", - "ACTION_DELETE_SPRINT": "Você quer apagar este Sprint?", + "ACTION_DELETE_SPRINT": "Você quer apagar este sprint?", "TITLE_ACTION_DELETE_SPRINT": "apagar sprint", "LAST_SPRINT_NAME": "último sprint é {{lastSprint}} ;-) " }, @@ -872,11 +943,29 @@ "EDIT_US": "Editar user story" }, "DELETE_SPRINT": { - "TITLE": "Apagar Sprint" + "TITLE": "Apagar sprint" }, "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" + "PLACEHOLDER_TYPE_EMAIL": "Digite um Email", + "LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "Unfortunately, this project can't have more than {{maxMembers}} members.
If you would like to increase the current limit, please contact the administrator.", + "LIMIT_USERS_WARNING_MESSAGE": "Unfortunately, this project can't have more than {{maxMembers}} members." + }, + "LEAVE_PROJECT_WARNING": { + "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" + }, + "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.", + "BUTTON": "Request project owner change" + } + }, + "CHANGE_OWNER": { + "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" } }, "US": { @@ -888,8 +977,8 @@ "TOTAL_POINTS": "total de pontos", "ADD": "+ Adicionar uma nova User Story", "ADD_BULK": "Adicionar User Stories em lote", - "PROMOTED": "Esta estória de uso foi promovida do caso:", - "TITLE_LINK_GO_TO_ISSUE": "Ir para caso", + "PROMOTED": "Esta estória de uso foi promovida do problema:", + "TITLE_LINK_GO_TO_ISSUE": "Ir para problema", "EXTERNAL_REFERENCE": "Esta EU foi criada de", "GO_TO_EXTERNAL_REFERENCE": "Ir para a origem", "BLOCKED": "Esta user story está bloqueada", @@ -914,7 +1003,7 @@ "TYPE_NEW_COMMENT": "Escreva um novo comentário aqui", "SHOW_DELETED": "Mostrar comentários apagados", "HIDE_DELETED": "Esconder comentário apagado", - "DELETE": "Delete comment", + "DELETE": "Apagar comentário", "RESTORE": "Restaurar comentário" }, "ACTIVITY": { @@ -977,8 +1066,8 @@ "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": "Administrador", "CUSTOMIZE_GRAPH_TITLE": "Configure os pontos e sprints pelo Administrador", - "MOVE_US_TO_CURRENT_SPRINT": "Mover para Sprint Corrente", - "MOVE_US_TO_LATEST_SPRINT": "ir para o último Sprint", + "MOVE_US_TO_CURRENT_SPRINT": "Mover para sprint corrente", + "MOVE_US_TO_LATEST_SPRINT": "ir para o último sprint", "SHOW_FILTERS": "Mostrar filtros", "SHOW_TAGS": "Exibir tags", "EMPTY": "O backlog está vazio!", @@ -989,7 +1078,7 @@ "CLOSED_POINTS": "fechado", "COMPACT_SPRINT": "Sprint Resumido", "GO_TO_TASKBOARD": "Ir ao quadro de tarefas de {{::name}}", - "EDIT_SPRINT": "Editar Sprint", + "EDIT_SPRINT": "Editar sprint", "TOTAL_POINTS": "total", "STATUS_NAME": "Nome de Situação", "SORTABLE_FILTER_ERROR": "Você não pode jogar sobre o backlog quando filtros estão abertos", @@ -998,9 +1087,9 @@ "XAXIS_LABEL": "Sprintes", "YAXIS_LABEL": "Pontos", "OPTIMAL": "Ideal de pontos pendentes para o sprint \"{{sprintName}}\" deve ser {{value}}", - "REAL": "Real pending points for sprint \"{{sprintName}}\" is {{value}}", - "INCREMENT_TEAM": "Pontos incrementados pelos requerimentos do time para o sprint \"{{sprintName}}\" é {{value}}", - "INCREMENT_CLIENT": "Pontos incrementados pelos requerimentos do cliente para o sprint \"{{sprintName}}\" é {{value}}" + "REAL": "Pontos realmente pendentes para o sprint \"{{sprintName}}\" é {{value}}", + "INCREMENT_TEAM": "Pontos incrementados pelos requisitos do time para o sprint \"{{sprintName}}\" é {{value}}", + "INCREMENT_CLIENT": "Pontos incrementados pelos requisitos do cliente para o sprint \"{{sprintName}}\" é {{value}}" }, "TAGS": { "TOGGLE": "Alternar visibilidade das tags", @@ -1014,7 +1103,7 @@ "SPRINT_SUMMARY": { "TOTAL_POINTS": "pontos
totais", "COMPLETED_POINTS": "pontos
completados", - "OPEN_TASKS": "tasks
abertas", + "OPEN_TASKS": "tarefas
abertas", "CLOSED_TASKS": "tarefas
fechadas", "IOCAINE_DOSES": "iocaine
doses", "SHOW_STATISTICS_TITLE": "Mostrar estatísticas", @@ -1038,13 +1127,13 @@ "SPRINTS": { "TITLE": "SPRINTS", "DATE": "DD MMM YYYY", - "LINK_TASKBOARD": "Sprint quadro de tarefas", + "LINK_TASKBOARD": "Quadro de tarefas do sprint", "TITLE_LINK_TASKBOARD": "ir para quadro de tarefas de \"{{name}}\"", "NUMBER_SPRINTS": "
sprints", "EMPTY": "Ainda não temos sprints.", - "WARNING_EMPTY_SPRINT_ANONYMOUS": "Esse sprint não tem Estórias", - "WARNING_EMPTY_SPRINT": "Solte aqui Estórias do seu backlog para iniciar uma nova sprint", - "TITLE_ACTION_NEW_SPRINT": "Add nova sprint", + "WARNING_EMPTY_SPRINT_ANONYMOUS": "Esse sprint não tem estórias de usuário", + "WARNING_EMPTY_SPRINT": "Solte aqui estórias do seu backlog para iniciar uma nova sprint", + "TITLE_ACTION_NEW_SPRINT": "Adicionar nova sprint", "TEXT_ACTION_NEW_SPRINT": "Você poderá querer criar uma nova sprint em seu projeto", "ACTION_SHOW_CLOSED_SPRINTS": "Mostre os sprints fechados", "ACTION_HIDE_CLOSED_SPRINTS": "Esconder sprints fechados" @@ -1134,9 +1223,9 @@ "SUCCESS": "Nossos Oompa Loompas atualizaram seu email" }, "ISSUES": { - "PAGE_TITLE": "Casos - {{projectName}}", - "PAGE_DESCRIPTION": "O painel de casos do projeto {{projectName}}: {{projectDescription}}", - "LIST_SECTION_NAME": "Casos", + "PAGE_TITLE": "Problemas - {{projectName}}", + "PAGE_DESCRIPTION": "O painel de problemas do projeto {{projectName}}: {{projectDescription}}", + "LIST_SECTION_NAME": "Problemas", "SECTION_NAME": "Detalhes do caso", "ACTION_NEW_ISSUE": "+ NOVO CASO", "ACTION_PROMOTE_TO_US": "Promover para User Story", @@ -1201,7 +1290,7 @@ } }, "ISSUE": { - "PAGE_TITLE": "{{issueSubject}} - caso {{issueRef}} - {{projectName}}", + "PAGE_TITLE": "{{issueSubject}} - problema {{issueRef}} - {{projectName}}", "PAGE_DESCRIPTION": "Estado: {{issueStatus }}. Tipo: {{issueType}}, Prioridade: {{issuePriority}}. severidade: {{issueSeverity}}. Descrição: {{issueDescription}}" }, "KANBAN": { @@ -1304,12 +1393,18 @@ } }, "WIZARD": { - "SECTION_TITLE_CHOOSE_TEMPLATE": "Escolher um template", - "CHOOSE_TEMPLATE_TEXT": "Qual template se encaixa melhor no seu projeto?", "SECTION_TITLE_CREATE_PROJECT": "Criar Projeto", "CREATE_PROJECT_TEXT": "Novo em folha. Tão excitante!", - "PROGRESS_TEMPLATE_SELECTION": "Seleção de tipo de projeto", - "PROGRESS_NAME_DESCRIPTION": "Nome e descrição" + "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": "Criar projeto", + "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}}", @@ -1335,7 +1430,7 @@ "HINT1_TITLE": "Você sabia que você pode importar e exportar projetos?", "HINT1_TEXT": "Isso permite você extrair todo o seu conteúdo de um Taiga e mover para outro.", "HINT2_TITLE": "Você sabia que pode criar campos personalizados?", - "HINT2_TEXT": "Teams can now create custom fields as a flexible means to enter specific data useful for their particular workflow.", + "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": "Reorder your projects to feature those most relevant to you.", "HINT3_TEXT": "The 10 projects are listed in the direct access bar at the top.", "HINT4_TITLE": "Você esqueceu onde está trabalhando?", @@ -1365,12 +1460,12 @@ "NEW_COMMENT_ISSUE": "{{username}} comentou no issue {{obj_name}}", "NEW_COMMENT_TASK": "{{username}} comentou na tarefa {{obj_name}}", "NEW_MEMBER": "{{project_name}} tem um membro novo", - "US_ADDED_MILESTONE": "{{username}} adicionou a US {{obj_name}} a {{sprint_name}}", + "US_ADDED_MILESTONE": "{{username}} adicionou a estória {{obj_name}} a {{sprint_name}}", "US_MOVED": "{{username}} moveu a US {{obj_name}}", "US_REMOVED_FROM_MILESTONE": "{{username}} adicionou a US {{obj_name}} ao backlog", "BLOCKED": "{{username}} bloqueou {{obj_name}}", "UNBLOCKED": "{{username}} desbloqueou {{obj_name}}", - "NEW_USER": "{{username}} ingressou no taiga" + "NEW_USER": "{{username}} ingressou no Taiga" }, "LEGAL": { "TERMS_OF_SERVICE_AND_PRIVACY_POLICY_AD": "When creating a new account, you agree to our
terms of service and privacy policy." @@ -1414,7 +1509,7 @@ "STEP1": { "TITLE": "Sumário do projeto", "TEXT1": "Aqui você verá o estado do seu projeto", - "TEXT2": "You can change every kind of project settings through the admin." + "TEXT2": "Você pode alterar qualquer configuração do projeto no menu admin." }, "STEP2": { "TITLE": "Backlog do Produto", @@ -1426,7 +1521,7 @@ }, "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." + "TEXT": "Estes são os requisitos em alto nível. Você pode adicioná-los ao backlog e arrastá-los ao sprint em que deve ser entregue. " } }, "KANBAN": { @@ -1455,7 +1550,7 @@ "MOST_LIKED": "Mais curtidas", "MOST_LIKED_EMPTY": "Não existe projetos curtidos ainda", "VIEW_MORE": "Visualizar mais", - "RECRUITING": "This project is looking for people", + "RECRUITING": "Este projeto esta procurando colaboradores", "FEATURED": "Featured Projects", "EMPTY": "There are no projects to show with this search criteria.
Try again!", "FILTERS": { @@ -1470,7 +1565,7 @@ "CLEAR": "Limpar filtros" }, "SEARCH": { - "PAGE_TITLE": "Search - Discover projects - Taiga", + "PAGE_TITLE": "Procurar - Descobrir projetos - 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": "Digite algo...", "ACTION_TITLE": "Procurar", diff --git a/app/locales/taiga/locale-ru.json b/app/locales/taiga/locale-ru.json index ac2e7076..50ec8091 100644 --- a/app/locales/taiga/locale-ru.json +++ b/app/locales/taiga/locale-ru.json @@ -2,7 +2,7 @@ "COMMON": { "YES": "Да", "NO": "Нет", - "OR": "or", + "OR": "или", "LOADING": "Пожалуйста, подождите...", "LOADING_PROJECT": "Проект загружается...", "DATE": "DD MMM YYYY", @@ -19,11 +19,11 @@ "TAG_LINE": "Ваш свободный, agile инструмент управления проектами с открытым исходным кодом", "TAG_LINE_2": "Любит ваши проекты", "BLOCK": "Блокировать", - "BLOCK_TITLE": "Block this item for example if it has a dependency that can not be satisfied", + "BLOCK_TITLE": "Заблокировать это, например, если имеются зависимости, которые не могут быть удовлетворены", "BLOCKED": "Заблокирован", "UNBLOCK": "Разблокировать", - "UNBLOCK_TITLE": "Unblock this item", - "BLOCKED_NOTE": "Why is this blocked?", + "UNBLOCK_TITLE": "Разблокировать это", + "BLOCKED_NOTE": "Почему это заблокировано?", "BLOCKED_REASON": "Пожалуйста разъясните причину", "CREATED_BY": "Создано {{fullDisplayName}}", "FROM": "от", @@ -41,7 +41,8 @@ "IOCAINE_TEXT": "Чувствуете, что задание берет верх над вами? Дайте другим знать об этом, нажав на \"Иокаин\", когда редактируете задание. Возможно стать неуязвимым к этому (выдуманному) смертельном яду, потребляя небольшие количества время от времени, так же как возможно стать лучше в том, что вы делаете, временами беря на себя дополнительные препятствия!", "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", - "CAPSLOCK_WARNING": "Будьте внимательны! Введённый текст состоит из заглавных букв, а регистр имеет значение.", + "OWNER": "Project Owner", + "CAPSLOCK_WARNING": "Be careful! You are using capital letters in an input field that is case sensitive.", "FORM_ERRORS": { "DEFAULT_MESSAGE": "Кажется, это значение некорректно.", "TYPE_EMAIL": "Это значение должно быть корректным email-адресом.", @@ -65,7 +66,9 @@ "MIN_CHECK": "Вы должны выбрать хотя бы %s вариантов.", "MAX_CHECK": "Вы должны выбрать %s вариантов или меньше.", "RANGE_CHECK": "Вы должны выбрать от %s до %s вариантов.", - "EQUAL_TO": "Это значение должно быть таким же." + "EQUAL_TO": "Это значение должно быть таким же.", + "LINEWIDTH": "One or more lines is perhaps too long. Try to keep under %s characters.", + "PIKADAY": "Invalid date format, please use DD MMM YYYY (like 23 Mar 1984)" }, "PICKERDATE": { "FORMAT": "DD MMM YYYY", @@ -144,13 +147,13 @@ }, "ASSIGNED_TO": { "NOT_ASSIGNED": "Не назначен", - "ASSIGN": "Assign", + "ASSIGN": "Назначить", "DELETE_ASSIGNMENT": "Удалить назначение", "REMOVE_ASSIGNED": "Удалить назначение", "TOO_MANY": "...слишком много пользователей, продолжайте фильтровать", "CONFIRM_UNASSIGNED": "Вы уверены что не хотите назначить ответственного?", "TITLE_ACTION_EDIT_ASSIGNMENT": "Изменить назначение", - "SELF": "Assign to me" + "SELF": "Назначено мне" }, "STATUS": { "CLOSED": "Закрыт", @@ -175,7 +178,7 @@ "UPVOTE": "Повысить", "UPVOTED": "Повышено", "DOWNVOTE": "Понизить", - "VOTERS": "Voters", + "VOTERS": "Проголосовавшие", "BUTTON_TITLE": "Повысить/понизить", "COUNTER_TITLE": "{total, plural, one{один голос} other{# голоса (-ов)}}" }, @@ -315,7 +318,8 @@ "PLACEHOLDER_FIELD": "Логин или e-mail", "ACTION_RESET_PASSWORD": "Сбросить пароль", "LINK_CANCEL": "Не, давай назад, думаю я вспомню.", - "SUCCESS": "Проверьте почту!
Мы выслали Вам письмо с инструкцией по установке нового пароля", + "SUCCESS_TITLE": "Check your inbox!", + "SUCCESS_TEXT": "We sent you an email with the instructions to set a new password", "ERROR": "Умпа-Лумпы говорят, что вы еще не зарегистрированы." }, "CHANGE_PASSWORD": { @@ -352,11 +356,11 @@ "PAGE_TITLE": "Домашняя страница - Taiga", "PAGE_DESCRIPTION": "Главная страница Taiga с вашими основными проектами, назначенными и отслеживаемыми ПИ, задачами и запросами", "EMPTY_WORKING_ON": "Пустовато, не правда ли? Начните работать в Taiga - и тут появятся ПИ, задачи и запросы, над которыми вы работаете.", - "EMPTY_WATCHING": "Follow User Stories, Tasks, Issues in your projects and be notified about its changes :)", + "EMPTY_WATCHING": "Следите за пользовательскими историями, задачами, запросами в ваших проектах и будьте уведомлены об изменениях :)", "EMPTY_PROJECT_LIST": "У Вас пока нет проектов", "WORKING_ON_SECTION": "Работает над", "WATCHING_SECTION": "Отслеживаемые", - "DASHBOARD": "Projects Dashboard" + "DASHBOARD": "Рабочий стол с проектами" }, "PROJECTS": { "PAGE_TITLE": "Мои проекты", @@ -366,14 +370,13 @@ "ATTACHMENT": { "SECTION_NAME": "Вложения", "TITLE": "{{ fileName }} загружен {{ date }}", - "LIST_VIEW_MODE": "List view mode", - "GALLERY_VIEW_MODE": "Gallery view mode", + "LIST_VIEW_MODE": "Режим \"список\"", + "GALLERY_VIEW_MODE": "Режим \"галерея\"", "DESCRIPTION": "Введите краткое описание", "DEPRECATED": "(устаревший)", "DEPRECATED_FILE": "Устаревший?", "ADD": "Добавить вложение. {{maxFileSizeMsg}}", - "DROP": "Drop attachments here!", - "MAX_FILE_SIZE": "[Макс. размер: {{maxFileSize}}]", + "DROP": "Перетяните вложение сюда", "SHOW_DEPRECATED": "Показать устаревшие приложения", "HIDE_DEPRECATED": "- спрятать устаревшие приложения", "COUNT_DEPRECATED": "({{ counter }} устарело)", @@ -406,7 +409,9 @@ "TITLE": "Управление участниками", "PAGE_TITLE": "Участие - {{projectName}}", "ADD_BUTTON": "+ Новый участник", - "ADD_BUTTON_TITLE": "Добавить нового участника" + "ADD_BUTTON_TITLE": "Добавить нового участника", + "LIMIT_USERS_WARNING_MESSAGE_FOR_ADMIN": "Unfortunately, this project has reached its limit of ({{members}}) allowed members.", + "LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "This project has reached its limit of ({{members}}) allowed members. If you would like to increase that limit please contact the administrator." }, "PROJECT_EXPORT": { "TITLE": "Экспорт", @@ -428,6 +433,10 @@ "DISABLE": "Выключить", "BACKLOG": "Список задач", "BACKLOG_DESCRIPTION": "Управляйте пользовательскими историями, чтобы поддерживать организованное видение важных и приоритетных задач.", + "NUMBER_SPRINTS": "Expected number of sprints", + "NUMBER_SPRINTS_HELP": "0 for an undetermined number", + "NUMBER_US_POINTS": "Expected total of story points", + "NUMBER_US_POINTS_HELP": "0 for an undetermined number", "KANBAN": "Kanban", "KANBAN_DESCRIPTION": "Организуйте эффективную работу с проектом с помощью этой панели", "ISSUES": "Запросы", @@ -435,9 +444,9 @@ "WIKI": "Вики", "WIKI_DESCRIPTION": "Добавляйте, изменяйте или удаляйте контент совместно с остальными. Это самое правильное место для документации вашего проекта.", "MEETUP": "Созвониться", - "MEETUP_DESCRIPTION": "Выберите вашу систему для видеоконференций. Даже разработчикам нужны митинги \"лицом к лицу\"", + "MEETUP_DESCRIPTION": "Choose your videoconference system.", "SELECT_VIDEOCONFERENCE": "Выберите систему видеоконференций", - "SALT_CHAT_ROOM": "Если хотите, можете добавить \"соль\" к имени чат-комнаты", + "SALT_CHAT_ROOM": "Add a prefix to the chatroom name", "JITSI_CHAT_ROOM": "Jitsi", "APPEARIN_CHAT_ROOM": "AppearIn", "TALKY_CHAT_ROOM": "Talky", @@ -449,22 +458,31 @@ "PROJECT_DETAILS": "Детали проекта", "PROJECT_NAME": "Название проекта", "PROJECT_SLUG": "Ссылочное имя проекта", - "NUMBER_SPRINTS": "Количество спринтов (0 - неопределенное количество)", - "NUMBER_US_POINTS": "Количество очков ПИ (0 - неопределенное количество)", "TAGS": "Тэги", "DESCRIPTION": "Описание", - "RECRUITING": "Is this project looking for people?", - "RECRUITING_MESSAGE": "Who are you looking for?", - "RECRUITING_PLACEHOLDER": "Define the profiles you are looking for", + "RECRUITING": "Этот проект ищет людей?", + "RECRUITING_MESSAGE": "Кого вы ищете?", + "RECRUITING_PLACEHOLDER": "Уточните, какие профили вы ищете", "PUBLIC_PROJECT": "Публичный проект", - "PUBLIC_PROJECT_DESC": "Users will be able to find and view your project", "PRIVATE_PROJECT": "Закрытый проект", - "PRIVATE_PROJECT_DESC": "By default, this project will be hidden to the public", - "PRIVATE_OR_PUBLIC": "What's the difference between public and private projects?", + "PRIVATE_OR_PUBLIC": "В чём разница между публичными и приватными проектами?", "DELETE": "Удалить проект", - "LOGO_HELP": "The image will be scaled to 80x80px.", + "LOGO_HELP": "Изображение будет отмасштабировано до 80x80px.", "CHANGE_LOGO": "Change logo", - "ACTION_USE_DEFAULT_LOGO": "Use default image" + "ACTION_USE_DEFAULT_LOGO": "Использовать картинку по умолчанию", + "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", + "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", + "REQUEST_OWNERSHIP": "Request ownership", + "REQUEST_OWNERSHIP_CONFIRMATION_TITLE": "Do you want to become the new project owner?", + "REQUEST_OWNERSHIP_DESC": "Request that current project owner {{name}} transfer ownership of this project to you.", + "REQUEST_OWNERSHIP_BUTTON": "Запрос", + "REQUEST_OWNERSHIP_SUCCESS": "We'll notify the project owner", + "CHANGE_OWNER": "Change owner", + "CHANGE_OWNER_SUCCESS_TITLE": "Ok, your request has been sent!", + "CHANGE_OWNER_SUCCESS_DESC": "We will notify you by email if the project ownership request is accepted or declined" }, "REPORTS": { "TITLE": "Отчеты", @@ -495,7 +513,8 @@ "ISSUE_ADD": "Добавить специальное поле для запросов", "FIELD_TYPE_TEXT": "Текст", "FIELD_TYPE_MULTI": "Многостроковое", - "FIELD_TYPE_DATE": "Дата" + "FIELD_TYPE_DATE": "Дата", + "FIELD_TYPE_URL": "Url" }, "PROJECT_VALUES": { "PAGE_TITLE": "{{sectionName}} - Значения атрибутов проекта - {{projectName}}", @@ -539,11 +558,11 @@ "HELP_ROLE_ENABLED": "Когда включено, участники, назначенные на эту роль, смогут оценивать очки для пользовательских историй", "DISABLE_COMPUTABLE_ALERT_TITLE": "Отключить оценку очков для этой роли", "DISABLE_COMPUTABLE_ALERT_SUBTITLE": "If you disable estimation permissions for role {{roleName}} all previous estimations made by this role will be removed", - "DISABLE_COMPUTABLE_ALERT_MESSAGE": "Are you sure you want to disable this role estimations?", + "DISABLE_COMPUTABLE_ALERT_MESSAGE": "Вы уверены, что хотите отключить оценку очков для этой роли?", "COUNT_MEMBERS": "{{ role.members_count }} участников с этой ролью", "TITLE_DELETE_ROLE": "Удалить Роль", "REPLACEMENT_ROLE": "Все пользователи этой роли будут перемещены в", - "WARNING_DELETE_ROLE": "Осторожнее, все оценки, связанные с этой будут удалены", + "WARNING_DELETE_ROLE": "Be careful! All role estimations will be removed", "ERROR_DELETE_ALL": "Вы не можете удалить все значения", "EXTERNAL_USER": "Внешний пользователь" }, @@ -671,6 +690,24 @@ }, "SUBMENU_THIDPARTIES": { "TITLE": "Сервисы" + }, + "PROJECT_TRANSFER": { + "DO_YOU_ACCEPT_PROJECT_OWNERNSHIP": "Would you like to become the new project owner?", + "PRIVATE": "Private", + "ACCEPTED_PROJECT_OWNERNSHIP": "Congratulations! You're now the new project owner.", + "REJECTED_PROJECT_OWNERNSHIP": "OK. We'll contact the current project owner", + "ACCEPT": "Принимаю", + "REJECT": "Reject", + "PROPOSE_OWNERSHIP": "{{owner}}, the current owner of the project {{project}} has asked that you become the new project owner.", + "ADD_COMMENT_QUESTION": "Would you like to send a question to the project owner?", + "ADD_COMMENT": "Would you like to add a comment for the project owner?", + "UNLIMITED_PROJECTS": "Unlimited", + "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" + }, + "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" } }, "USER": { @@ -692,13 +729,13 @@ "PROJECTS_TAB": "Проекты", "PROJECTS_TAB_TITLE": "Список всех проектов, в которых участвует пользователь", "LIKES_TAB": "Лайки", - "LIKES_TAB_TITLE": "List all likes made by this user", + "LIKES_TAB_TITLE": "Список всех лайков, поставленных этим пользователем", "VOTES_TAB": "Голоса", - "VOTES_TAB_TITLE": "List all votes made by this user", + "VOTES_TAB_TITLE": "Список всех голосов, сделанных этим пользователем", "WATCHED_TAB": "Просмотренные", "WATCHED_TAB_TITLE": "Список всего, за чем наблюдает пользователь", "CONTACTS_TAB": "Контакты", - "CONTACTS_TAB_TITLE": "List all contacts made by this user" + "CONTACTS_TAB_TITLE": "Список всех контактов, созданных этим пользователем" } }, "PROFILE_SIDEBAR": { @@ -727,10 +764,15 @@ "SECTION_PROJECTS": "Проекты", "HELP": "Реорганизуйте свои проекты так чтобы часто используемые были бы наверху.
Первые 10 проектов будут находится вверху списка проектов.", "PRIVATE": "Закрытый проект", - "LOOKING_FOR_PEOPLE": "This project is looking for people", + "LOOKING_FOR_PEOPLE": "Этот проект ищет людей", "FANS_COUNTER_TITLE": "{total, plural, one{один фанат} other{# фаната (-ов)}}", "WATCHERS_COUNTER_TITLE": "{total, plural, one{один наблюдатель} other{# наблюдателя (-ей)}}", "MEMBERS_COUNTER_TITLE": "{total, plural, one{one member} other{# members}}", + "BLOCKED_PROJECT": { + "BLOCKED": "Blocked project", + "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": "заданные
очки", @@ -753,14 +795,14 @@ "PLACEHOLDER_SEARCH": "Искать в...", "ACTION_CREATE_PROJECT": "Создать проект", "ACTION_IMPORT_PROJECT": "Импортировать проект", - "MANAGE_PROJECTS": "Manage projects", + "MANAGE_PROJECTS": "Управлять проектами", "TITLE_CREATE_PROJECT": "Создать проект", "TITLE_IMPORT_PROJECT": "Импортировать проект", "TITLE_PRVIOUS_PROJECT": "Показать предыдущие проекты", "TITLE_NEXT_PROJECT": "Показать следующие проекты", "HELP_TITLE": "Страница поддержки Taiga", "HELP": "Помощь", - "HOMEPAGE": "Homepage", + "HOMEPAGE": "Домашняя страница", "FEEDBACK_TITLE": "Оставить отзыв", "FEEDBACK": "Обратная связь", "NOTIFICATIONS_TITLE": "Настроить уведомления", @@ -777,6 +819,7 @@ "CHANGE_PASSWORD": "Изменить пароль", "DASHBOARD_TITLE": "Рабочий стол", "DISCOVER_TITLE": "Найти проекты в тренде", + "NEW_ITEM": "Новая", "DISCOVER": "Найти", "ACTION_REORDER": "Можно перетаскивать мышкой" }, @@ -791,7 +834,32 @@ "ERROR_TOO_MANY_REQUEST": "Извините, Oompa Loompas очень загружен сейчас. Повторите через несколько минут.", "ERROR_MESSAGE": "У Oompa Loompas возникли проблемы при импорте резервной копии: {{error_message}}", "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) это слишком много для наших Умпа-Лумп, попробуйте еще раз с размером меньшим, чем ({{maxFileSize}})", - "SYNC_SUCCESS": "Импорт проекта выполнен успешно" + "SYNC_SUCCESS": "Импорт проекта выполнен успешно", + "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.", + "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 private 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": "The project that you are trying to import is private and has {{members}} members." + }, + "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." + } + } }, "LIKE_BUTTON": { "LIKE": "Мне нравится", @@ -819,8 +887,11 @@ "DELETE_ACCOUNT": { "SECTION_NAME": "Удалить аккаунт", "CONFIRM": "Вы уверены, что хотите удалить ваш аккаунт?", - "SUBTITLE": "Мы будем скучать по вам! :-(", - "NEWSLETTER_LABEL_TEXT": "Я больше не хочу получать вашу новостную рассылку" + "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! :(" }, "DELETE_PROJECT": { "TITLE": "Удалить проект", @@ -876,7 +947,25 @@ }, "CREATE_MEMBER": { "PLACEHOLDER_INVITATION_TEXT": "(Необязательно) Добавьте персональный текст в приглашение. Скажите что-нибудь приятное вашим новым участникам ;-)", - "PLACEHOLDER_TYPE_EMAIL": "Укажите e-mail" + "PLACEHOLDER_TYPE_EMAIL": "Укажите e-mail", + "LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "Unfortunately, this project can't have more than {{maxMembers}} members.
If you would like to increase the current limit, please contact the administrator.", + "LIMIT_USERS_WARNING_MESSAGE": "Unfortunately, this project can't have more than {{maxMembers}} members." + }, + "LEAVE_PROJECT_WARNING": { + "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" + }, + "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.", + "BUTTON": "Request project owner change" + } + }, + "CHANGE_OWNER": { + "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" } }, "US": { @@ -914,7 +1003,7 @@ "TYPE_NEW_COMMENT": "Добавить комментарий", "SHOW_DELETED": "Показать удаленный комментарий", "HIDE_DELETED": "Скрыть удаленный комментарий", - "DELETE": "Delete comment", + "DELETE": "Удалить комментарий", "RESTORE": "Показать удаленный комментарий" }, "ACTIVITY": { @@ -973,12 +1062,12 @@ "PAGE_TITLE": "Список задач - {{projectName}}", "PAGE_DESCRIPTION": "Список задач с пользовательскими историями и спринтами проекта {{projectName}}: {{projectDescription}}", "SECTION_NAME": "Список задач", - "CUSTOMIZE_GRAPH": "Customize your backlog graph", + "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": "Move to latest Sprint", + "MOVE_US_TO_LATEST_SPRINT": "Перейти к последнему спринту", "SHOW_FILTERS": "Показать фильтры", "SHOW_TAGS": "Показать теги", "EMPTY": "Список задач пуст!", @@ -1042,7 +1131,7 @@ "TITLE_LINK_TASKBOARD": "Перейти к Панели Задач \"{{name}}\"", "NUMBER_SPRINTS": "
спринты", "EMPTY": "Спринтов пока что нет", - "WARNING_EMPTY_SPRINT_ANONYMOUS": "This sprint has no User Stories", + "WARNING_EMPTY_SPRINT_ANONYMOUS": "У этого спринта нет пользовательских историй", "WARNING_EMPTY_SPRINT": "Накидайте сюда ПИ из списка задач чтобы начать новый спринт", "TITLE_ACTION_NEW_SPRINT": "Добавить новый спринт", "TEXT_ACTION_NEW_SPRINT": "Вы можете создать новый спринт в проекте", @@ -1066,7 +1155,7 @@ "TITLE_ACTION_ADD_BULK": "Добавить новые задачи пакетно", "TITLE_ACTION_ASSIGN": "Назначить задачу", "TITLE_ACTION_EDIT": "Редактировать задачу", - "PLACEHOLDER_CARD_TITLE": "This could be a task", + "PLACEHOLDER_CARD_TITLE": "Это может быть задачей", "PLACEHOLDER_CARD_TEXT": "Разделяйте ПИ в задачи чтобы отслеживать их по отдельности", "TABLE": { "COLUMN": "Пользовательская история", @@ -1268,8 +1357,8 @@ "NOTIFICATIONS": { "SECTION_NAME": "Уведомления почтой", "COLUMN_PROJECT": "Проект", - "COLUMN_RECEIVE_ALL": "Получать Всё", - "COLUMN_ONLY_INVOLVED": "Только задействованные", + "COLUMN_RECEIVE_ALL": "Получать все", + "COLUMN_ONLY_INVOLVED": "Только вовлечённые", "COLUMN_NO_NOTIFICATIONS": "Уведомлений нет", "OPTION_ALL": "Все", "OPTION_INVOLVED": "Вовлечен", @@ -1284,9 +1373,9 @@ } }, "USER_PROFILE": { - "IMAGE_HELP": "The image will be scaled to 80x80px.", + "IMAGE_HELP": "Изображение будет отмасштабировано до 80x80px.", "ACTION_CHANGE_IMAGE": "Изменить", - "ACTION_USE_GRAVATAR": "Use default image", + "ACTION_USE_GRAVATAR": "Использовать картинку по умолчанию", "ACTION_DELETE_ACCOUNT": "Удалить аккаунт", "CHANGE_EMAIL_SUCCESS": "Проверьте входящие письма!
Мы послали письмо на ваш аккаунт
с инструкциями по установке вашего нового адреса.", "CHANGE_PHOTO": "Изменить фото", @@ -1294,7 +1383,7 @@ "USERNAME": "Имя пользователя", "EMAIL": "Email", "FULL_NAME": "Полное имя", - "PLACEHOLDER_FULL_NAME": "Установите ваше полное имя (например, Игорь Николаев)", + "PLACEHOLDER_FULL_NAME": "Полное имя (например, Игорь Николаев)", "BIO": "Биография (не более 210 символов)", "PLACEHOLDER_BIO": "Расскажите нам что-нибудь о себе", "LANGUAGE": "Язык", @@ -1304,12 +1393,18 @@ } }, "WIZARD": { - "SECTION_TITLE_CHOOSE_TEMPLATE": "Выберете шаблон", - "CHOOSE_TEMPLATE_TEXT": "Какой шаблон лучше всего подойдет для Вашего проекта?", "SECTION_TITLE_CREATE_PROJECT": "Создать проект", "CREATE_PROJECT_TEXT": "Свежий и чистый! Так здóрово!", - "PROGRESS_TEMPLATE_SELECTION": "Выбор шаблона", - "PROGRESS_NAME_DESCRIPTION": "Название и описание" + "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}}", @@ -1338,7 +1433,7 @@ "HINT2_TEXT": "Теперь команды могут создавать специальные поля, чтобы гибко вводить данные, специфические для их рабочего процесса.", "HINT3_TITLE": "Перестройте список своих проектов так, чтобы выделить самые важные для себя.", "HINT3_TEXT": "Первые 10 проектов доступны из панели прямого доступа сверху.", - "HINT4_TITLE": "Did you forget what were you working on?", + "HINT4_TITLE": "Забыли, над чем вы работали?", "HINT4_TEXT": "Не переживайте, на вашем рабочем столе вы найдёте ваши активные задачи, запросы и пользовательские истории в том порядке, в котором вы над ними работали." }, "TIMELINE": { @@ -1387,7 +1482,7 @@ "NAV": { "NEXT": "Следующий", "BACK": "Бэкенд разработчик", - "SKIP": "Skip", + "SKIP": "Пропустить", "DONE": "Завершена" }, "DASHBOARD": { @@ -1402,7 +1497,7 @@ "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 ;)" + "TEXT2": "Вы уже работаете с Taiga ;)" }, "STEP4": { "TITLE": "Давайте начнём", @@ -1446,35 +1541,35 @@ } }, "DISCOVER": { - "PAGE_TITLE": "Discover projects - Taiga", + "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 projects", + "DISCOVER_TITLE": "Найти проекты", "DISCOVER_SUBTITLE": "{projects, plural, one{One public project to discover} other{# public projects to discover}}", - "MOST_ACTIVE": "Most active", + "MOST_ACTIVE": "Наиболее активные", "MOST_ACTIVE_EMPTY": "There are no ACTIVE projects yet", - "MOST_LIKED": "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!", + "VIEW_MORE": "Показать больше", + "RECRUITING": "Этот проект ищет людей", + "FEATURED": "Популярные проекты", + "EMPTY": "Нету проектов, удовлетворяющих заданным критериям поиска.
Попробуйте снова!", "FILTERS": { "ALL": "Все", "KANBAN": "Kanban", "SCRUM": "Scrum", - "PEOPLE": "Looking for people", - "WEEK": "Last week", - "MONTH": "Last month", - "YEAR": "Last year", - "ALL_TIME": "All time", - "CLEAR": "Clear filters" + "PEOPLE": "Ищем людей", + "WEEK": "За неделю", + "MONTH": "За месяц", + "YEAR": "За год", + "ALL_TIME": "За всё время", + "CLEAR": "Очистить фильтры" }, "SEARCH": { - "PAGE_TITLE": "Search - Discover projects - Taiga", + "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": "Search results" + "RESULTS": "Результаты поиска" } } } \ No newline at end of file diff --git a/app/locales/taiga/locale-sv.json b/app/locales/taiga/locale-sv.json index d8f2115c..7caf2895 100644 --- a/app/locales/taiga/locale-sv.json +++ b/app/locales/taiga/locale-sv.json @@ -41,7 +41,8 @@ "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!", "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", - "CAPSLOCK_WARNING": "Var försiktig! Du skriver med STORA bokstäver och det här fältet är skriftlägekänsligt.", + "OWNER": "Project Owner", + "CAPSLOCK_WARNING": "Be careful! You are using capital letters in an input field that is case sensitive.", "FORM_ERRORS": { "DEFAULT_MESSAGE": "Det här värdet är felaktigt. ", "TYPE_EMAIL": "Värdet måste vara en giltig e-postadress", @@ -65,7 +66,9 @@ "MIN_CHECK": "Du måste välja minst %s val.", "MAX_CHECK": "Du måste välja %s val eller mindre.", "RANGE_CHECK": "Du måste välja mellan %s och %s val.", - "EQUAL_TO": "Det här värdet skulle vara det samma. " + "EQUAL_TO": "Det här värdet skulle vara det samma. ", + "LINEWIDTH": "One or more lines is perhaps too long. Try to keep under %s characters.", + "PIKADAY": "Invalid date format, please use DD MMM YYYY (like 23 Mar 1984)" }, "PICKERDATE": { "FORMAT": "YYYY-MM-DD", @@ -315,7 +318,8 @@ "PLACEHOLDER_FIELD": "Användarnamn eller e-postadress", "ACTION_RESET_PASSWORD": "Återställ lösenord", "LINK_CANCEL": "Nej, ta mig tillbaka. Jag tror att jag minns det.", - "SUCCESS": "Kolla inboxen!
Du ska ha fått ett e-postmeddelande med instruktioner för hur du ändrar lösenordet", + "SUCCESS_TITLE": "Check your inbox!", + "SUCCESS_TEXT": "We sent you an email with the instructions to set a new password", "ERROR": "Enligt våra Oompaloompier är du inte registrerad ännu." }, "CHANGE_PASSWORD": { @@ -373,7 +377,6 @@ "DEPRECATED_FILE": "Borttagen?", "ADD": "Lägg till ny bilaga. {{maxFileSizeMsg}}", "DROP": "Drag och släpp filer som ska bifogas här!", - "MAX_FILE_SIZE": "[Max. size: {{maxFileSize}}]", "SHOW_DEPRECATED": "+ visa ogillade bilagor", "HIDE_DEPRECATED": "- dölj ogillade bilagor", "COUNT_DEPRECATED": "({{ counter }} deprecated)", @@ -406,7 +409,9 @@ "TITLE": "Hantera medlemmar", "PAGE_TITLE": "Medlemskap - {{projectName}}", "ADD_BUTTON": "+ Ny medlem", - "ADD_BUTTON_TITLE": "Lägg till ny medlem" + "ADD_BUTTON_TITLE": "Lägg till ny medlem", + "LIMIT_USERS_WARNING_MESSAGE_FOR_ADMIN": "Unfortunately, this project has reached its limit of ({{members}}) allowed members.", + "LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "This project has reached its limit of ({{members}}) allowed members. If you would like to increase that limit please contact the administrator." }, "PROJECT_EXPORT": { "TITLE": "Exportera", @@ -428,6 +433,10 @@ "DISABLE": "Avvaktivera", "BACKLOG": "Inkorg", "BACKLOG_DESCRIPTION": "Hantera dina användarhistorier för att organisera visningar av kommande och prioriterade jobb. ", + "NUMBER_SPRINTS": "Expected number of sprints", + "NUMBER_SPRINTS_HELP": "0 for an undetermined number", + "NUMBER_US_POINTS": "Expected total of story points", + "NUMBER_US_POINTS_HELP": "0 for an undetermined number", "KANBAN": "Kanban", "KANBAN_DESCRIPTION": "Organisera dina projekt med Lean med den här tavlan. ", "ISSUES": "Frågor", @@ -435,9 +444,9 @@ "WIKI": "Wiki", "WIKI_DESCRIPTION": "Lägg till, modifiera eller ta bort innehåll i samarbetet med andra. Det här är rätt plats för ditt projektdokumentation. ", "MEETUP": "Möt upp", - "MEETUP_DESCRIPTION": "Välj ditt videokonferenssystem. Även utvecklare behöver mötas ansikte mot ansikte.", + "MEETUP_DESCRIPTION": "Choose your videoconference system.", "SELECT_VIDEOCONFERENCE": "Välj videokonferenssystem", - "SALT_CHAT_ROOM": "Om du önskar det kan du lägga till några tillfälliga tecken till chat-rummets namn. ", + "SALT_CHAT_ROOM": "Add a prefix to the chatroom name", "JITSI_CHAT_ROOM": "Jitsi", "APPEARIN_CHAT_ROOM": "Dyker upp i ", "TALKY_CHAT_ROOM": "Talky", @@ -449,22 +458,31 @@ "PROJECT_DETAILS": "Projektdetaljer", "PROJECT_NAME": "Projektnamn", "PROJECT_SLUG": "Projektslugg", - "NUMBER_SPRINTS": "Antal sprintar (0 för en obestämd kvantitet)", - "NUMBER_US_POINTS": "Antal US-poäng (0 för ett obestämd antal)", "TAGS": "Etiketter", "DESCRIPTION": "Beskrivning", "RECRUITING": "Is this project looking for people?", "RECRUITING_MESSAGE": "Vem letar du efter?", "RECRUITING_PLACEHOLDER": "Define the profiles you are looking for", "PUBLIC_PROJECT": "Publika projekt", - "PUBLIC_PROJECT_DESC": "Users will be able to find and view your project", "PRIVATE_PROJECT": "Privata projekt", - "PRIVATE_PROJECT_DESC": "By default, this project will be hidden to the public", "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" + "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", + "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", + "REQUEST_OWNERSHIP": "Request ownership", + "REQUEST_OWNERSHIP_CONFIRMATION_TITLE": "Do you want to become the new project owner?", + "REQUEST_OWNERSHIP_DESC": "Request that current project owner {{name}} transfer ownership of this project to you.", + "REQUEST_OWNERSHIP_BUTTON": "Förfrågan", + "REQUEST_OWNERSHIP_SUCCESS": "We'll notify the project owner", + "CHANGE_OWNER": "Change owner", + "CHANGE_OWNER_SUCCESS_TITLE": "Ok, your request has been sent!", + "CHANGE_OWNER_SUCCESS_DESC": "We will notify you by email if the project ownership request is accepted or declined" }, "REPORTS": { "TITLE": "Rapporter", @@ -495,7 +513,8 @@ "ISSUE_ADD": "Anpassade fält för ärenden", "FIELD_TYPE_TEXT": "Text", "FIELD_TYPE_MULTI": "Flerradig", - "FIELD_TYPE_DATE": "Datum" + "FIELD_TYPE_DATE": "Datum", + "FIELD_TYPE_URL": "Url" }, "PROJECT_VALUES": { "PAGE_TITLE": "{{sectionName}} - Projektvärden - {{projectName}}", @@ -543,7 +562,7 @@ "COUNT_MEMBERS": "{{ role.members_count }} medlemmar med den här rollen", "TITLE_DELETE_ROLE": "Ta bort rollen", "REPLACEMENT_ROLE": "Alla användarna med den här rollen vill flyttas till", - "WARNING_DELETE_ROLE": "Var försiktig. Alla beräkninger för den här rollen vill tas bort", + "WARNING_DELETE_ROLE": "Be careful! All role estimations will be removed", "ERROR_DELETE_ALL": "Du kan inte ta bort alla värden", "EXTERNAL_USER": "Extern användare" }, @@ -671,6 +690,24 @@ }, "SUBMENU_THIDPARTIES": { "TITLE": "Tjänster" + }, + "PROJECT_TRANSFER": { + "DO_YOU_ACCEPT_PROJECT_OWNERNSHIP": "Would you like to become the new project owner?", + "PRIVATE": "Private", + "ACCEPTED_PROJECT_OWNERNSHIP": "Congratulations! You're now the new project owner.", + "REJECTED_PROJECT_OWNERNSHIP": "OK. We'll contact the current project owner", + "ACCEPT": "Acceptera", + "REJECT": "Reject", + "PROPOSE_OWNERSHIP": "{{owner}}, the current owner of the project {{project}} has asked that you become the new project owner.", + "ADD_COMMENT_QUESTION": "Would you like to send a question to the project owner?", + "ADD_COMMENT": "Would you like to add a comment for the project owner?", + "UNLIMITED_PROJECTS": "Unlimited", + "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" + }, + "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" } }, "USER": { @@ -731,6 +768,11 @@ "FANS_COUNTER_TITLE": "{total, plural, one{one fan} andra{# fans}}", "WATCHERS_COUNTER_TITLE": "{total, plural, en{one watcher} andra{# watchers}}", "MEMBERS_COUNTER_TITLE": "{total, plural, one{one member} other{# members}}", + "BLOCKED_PROJECT": { + "BLOCKED": "Blocked project", + "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": "projekt
poäng", "DEFINED": "definierad
poäng", @@ -777,6 +819,7 @@ "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" }, @@ -791,7 +834,32 @@ "ERROR_TOO_MANY_REQUEST": "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 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" + "SYNC_SUCCESS": "Ditt projekt är korrekt importerad", + "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.", + "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 private 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": "The project that you are trying to import is private and has {{members}} members." + }, + "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." + } + } }, "LIKE_BUTTON": { "LIKE": "Gillar", @@ -819,8 +887,11 @@ "DELETE_ACCOUNT": { "SECTION_NAME": "Ta bort konto", "CONFIRM": "Är du säker på att du vill radera kontot?", - "SUBTITLE": "Vi kommer att sakna dig!", - "NEWSLETTER_LABEL_TEXT": "Jag vill inte motta flera nyhetsbrev" + "NEWSLETTER_LABEL_TEXT": "Jag vill inte motta flera nyhetsbrev", + "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! :(" }, "DELETE_PROJECT": { "TITLE": "Ta bort projekt", @@ -876,7 +947,25 @@ }, "CREATE_MEMBER": { "PLACEHOLDER_INVITATION_TEXT": "(Valfritt) Lägg till en personlig hälsning till invitationen. Berätta något trevligt till din nya projektmedlem ;-)", - "PLACEHOLDER_TYPE_EMAIL": "Skriv in en e-postadress" + "PLACEHOLDER_TYPE_EMAIL": "Skriv in en e-postadress", + "LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "Unfortunately, this project can't have more than {{maxMembers}} members.
If you would like to increase the current limit, please contact the administrator.", + "LIMIT_USERS_WARNING_MESSAGE": "Unfortunately, this project can't have more than {{maxMembers}} members." + }, + "LEAVE_PROJECT_WARNING": { + "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" + }, + "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.", + "BUTTON": "Request project owner change" + } + }, + "CHANGE_OWNER": { + "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" } }, "US": { @@ -1304,12 +1393,18 @@ } }, "WIZARD": { - "SECTION_TITLE_CHOOSE_TEMPLATE": "Välj en mall", - "CHOOSE_TEMPLATE_TEXT": "Vilken mall skulle passa bättre i det här projektet? ", "SECTION_TITLE_CREATE_PROJECT": "Skapa projekt", "CREATE_PROJECT_TEXT": "Fräscht och rent. Så trevligt!", - "PROGRESS_TEMPLATE_SELECTION": "Urval mallar", - "PROGRESS_NAME_DESCRIPTION": "Namn och beskrivning" + "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": "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}}", diff --git a/app/locales/taiga/locale-tr.json b/app/locales/taiga/locale-tr.json index b96d15a3..7969c999 100644 --- a/app/locales/taiga/locale-tr.json +++ b/app/locales/taiga/locale-tr.json @@ -41,7 +41,8 @@ "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!", "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.", - "CAPSLOCK_WARNING": "Dikkat! Büyük harflerle yazıyorsunuz ve bu girdi büyüklük küçüklük duyarlı.", + "OWNER": "Project Owner", + "CAPSLOCK_WARNING": "Be careful! You are using capital letters in an input field that is case sensitive.", "FORM_ERRORS": { "DEFAULT_MESSAGE": "Bu değer geçersiz gözüküyor", "TYPE_EMAIL": "Bu değer geçerli bir e-posta adresi olmalı.", @@ -65,7 +66,9 @@ "MIN_CHECK": "En az %s seçenek belirtmek zorundasınız.", "MAX_CHECK": "%s seçenek ya da daha azını seçmek zorunlu.", "RANGE_CHECK": "%s ve %s seçenekleri arasında bir seçim yapmak zorunludu.", - "EQUAL_TO": "Bu değer aynı olmalı." + "EQUAL_TO": "Bu değer aynı olmalı.", + "LINEWIDTH": "One or more lines is perhaps too long. Try to keep under %s characters.", + "PIKADAY": "Invalid date format, please use DD MMM YYYY (like 23 Mar 1984)" }, "PICKERDATE": { "FORMAT": "DD MM YYYY", @@ -315,7 +318,8 @@ "PLACEHOLDER_FIELD": "Kullanıcı adı veya e-posta", "ACTION_RESET_PASSWORD": "Parolayı Sıfırla", "LINK_CANCEL": "Boşver, geri gidelim. Sanırım hatırladım.", - "SUCCESS": "Gelen kutunuzu kontrol edin!
Yeni parolanızı oluşturabilmeniz için gerekli yönergeleri içeren bir e-posta gönderdik", + "SUCCESS_TITLE": "Check your inbox!", + "SUCCESS_TEXT": "We sent you an email with the instructions to set a new password", "ERROR": "Honki ponkilerimize göre, siz henüz bir kayıt yaptırmamış durumdasınız." }, "CHANGE_PASSWORD": { @@ -373,7 +377,6 @@ "DEPRECATED_FILE": "Kaldırıldı mı?", "ADD": "Yeni ek ekleyin {{maxFileSizeMsg}}", "DROP": "Ekleri buraya bırakın!", - "MAX_FILE_SIZE": "[Max. boyut: {{maxFileSize}}]", "SHOW_DEPRECATED": "+ kaldırılan ekleri göster", "HIDE_DEPRECATED": "- kaldırılan ekleri gizle", "COUNT_DEPRECATED": "({{ counter }} kaldırılmış)", @@ -406,7 +409,9 @@ "TITLE": "Üyeleri yönet", "PAGE_TITLE": "Üyelikler - {{projectName}}", "ADD_BUTTON": "+ Yeni üye", - "ADD_BUTTON_TITLE": "Yeni üye ekle" + "ADD_BUTTON_TITLE": "Yeni üye ekle", + "LIMIT_USERS_WARNING_MESSAGE_FOR_ADMIN": "Unfortunately, this project has reached its limit of ({{members}}) allowed members.", + "LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "This project has reached its limit of ({{members}}) allowed members. If you would like to increase that limit please contact the administrator." }, "PROJECT_EXPORT": { "TITLE": "Dışarı aktar", @@ -428,6 +433,10 @@ "DISABLE": "Pasifleştir", "BACKLOG": "Havuz", "BACKLOG_DESCRIPTION": "Yeni gelen ve önceliklendirilmiş işler için düzenli bir görünüm elde etmek için kullanıcı hikayelerinizi yönetin.", + "NUMBER_SPRINTS": "Expected number of sprints", + "NUMBER_SPRINTS_HELP": "0 for an undetermined number", + "NUMBER_US_POINTS": "Expected total of story points", + "NUMBER_US_POINTS_HELP": "0 for an undetermined number", "KANBAN": "Kanban", "KANBAN_DESCRIPTION": "Bu pano ile projenizi güzel bir şekilde düzenleyin.", "ISSUES": "Sorunlar", @@ -435,9 +444,9 @@ "WIKI": "Wiki", "WIKI_DESCRIPTION": "Diğerleriyle işbirliği yaparak içerik ekleyin, düzenleyin ve silin. Burası projenizin dokümantasyonu için doğru yer.", "MEETUP": "Toplantı", - "MEETUP_DESCRIPTION": "Video konferans sisteminizi seçin. Yazılımcılar bile yüz yüze görüşmeye ihtiyaç duyarlar.", + "MEETUP_DESCRIPTION": "Choose your videoconference system.", "SELECT_VIDEOCONFERENCE": "Bir video konferans sistemi seç", - "SALT_CHAT_ROOM": "Eğer isterseniz sohbet odası adına salt kod ekleyebilirsiniz", + "SALT_CHAT_ROOM": "Add a prefix to the chatroom name", "JITSI_CHAT_ROOM": "Jitsi", "APPEARIN_CHAT_ROOM": "AppearIn", "TALKY_CHAT_ROOM": "Talky", @@ -449,22 +458,31 @@ "PROJECT_DETAILS": "Proje detayları", "PROJECT_NAME": "Proje adı", "PROJECT_SLUG": "Proje satırı", - "NUMBER_SPRINTS": "Koşu sayısı (belirsiz bir miktar için 0)", - "NUMBER_US_POINTS": "KH puanları sayısı (belirlenmemiş miktarlar için 0)", "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", "PUBLIC_PROJECT": "Açık Proje", - "PUBLIC_PROJECT_DESC": "Kullanıcılar projenizi bulabilir ve görebilir", "PRIVATE_PROJECT": "Gizli proje", - "PRIVATE_PROJECT_DESC": "Normalde bu proje gizli olacak", "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" + "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", + "MAX_PRIVATE_PROJECTS_MEMBERS": "The maximum number of members for private projects has been exceeded", + "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", + "REQUEST_OWNERSHIP": "Request ownership", + "REQUEST_OWNERSHIP_CONFIRMATION_TITLE": "Do you want to become the new project owner?", + "REQUEST_OWNERSHIP_DESC": "Request that current project owner {{name}} transfer ownership of this project to you.", + "REQUEST_OWNERSHIP_BUTTON": "Talep", + "REQUEST_OWNERSHIP_SUCCESS": "We'll notify the project owner", + "CHANGE_OWNER": "Change owner", + "CHANGE_OWNER_SUCCESS_TITLE": "Ok, your request has been sent!", + "CHANGE_OWNER_SUCCESS_DESC": "We will notify you by email if the project ownership request is accepted or declined" }, "REPORTS": { "TITLE": "Raporlar", @@ -495,7 +513,8 @@ "ISSUE_ADD": "Sorunlara yeni bir özel alan ekle", "FIELD_TYPE_TEXT": "Metin", "FIELD_TYPE_MULTI": "Çoklu-satır", - "FIELD_TYPE_DATE": "Tarih" + "FIELD_TYPE_DATE": "Tarih", + "FIELD_TYPE_URL": "Url" }, "PROJECT_VALUES": { "PAGE_TITLE": "{{sectionName}} - Proje değerleri- {{projectName}}", @@ -543,7 +562,7 @@ "COUNT_MEMBERS": "bu roldeki üyelerin sayısı {{ role.members_count }} ", "TITLE_DELETE_ROLE": "Rol Sil", "REPLACEMENT_ROLE": "Bu role sahip kullanıcıların taşınacağı", - "WARNING_DELETE_ROLE": "Dikkat lütfen, bütün rol kestirimleri silinecek", + "WARNING_DELETE_ROLE": "Be careful! All role estimations will be removed", "ERROR_DELETE_ALL": "Bütün değerleri silemezsiniz", "EXTERNAL_USER": "Dış kullanıcı" }, @@ -671,6 +690,24 @@ }, "SUBMENU_THIDPARTIES": { "TITLE": "Servisler" + }, + "PROJECT_TRANSFER": { + "DO_YOU_ACCEPT_PROJECT_OWNERNSHIP": "Would you like to become the new project owner?", + "PRIVATE": "Private", + "ACCEPTED_PROJECT_OWNERNSHIP": "Congratulations! You're now the new project owner.", + "REJECTED_PROJECT_OWNERNSHIP": "OK. We'll contact the current project owner", + "ACCEPT": "Kabul et", + "REJECT": "Reject", + "PROPOSE_OWNERSHIP": "{{owner}}, the current owner of the project {{project}} has asked that you become the new project owner.", + "ADD_COMMENT_QUESTION": "Would you like to send a question to the project owner?", + "ADD_COMMENT": "Would you like to add a comment for the project owner?", + "UNLIMITED_PROJECTS": "Unlimited", + "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" + }, + "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" } }, "USER": { @@ -731,6 +768,11 @@ "FANS_COUNTER_TITLE": "{total, plural, one{bir meraklı} other{# meraklı}}", "WATCHERS_COUNTER_TITLE": "{total, plural, one{bir takipçi} other{# takipçi}}", "MEMBERS_COUNTER_TITLE": "{total, plural, one{bir üye} other{# üye}}", + "BLOCKED_PROJECT": { + "BLOCKED": "Blocked project", + "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", @@ -777,6 +819,7 @@ "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" }, @@ -791,7 +834,32 @@ "ERROR_TOO_MANY_REQUEST": "Üzgünüm, bizim honki ponkiler şu anda çok meşgul. Lütfen birkaç dakika içinde yeniden deneyin.", "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ı" + "SYNC_SUCCESS": "Projeniz başarıyla içe aktarıldı", + "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.", + "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 private 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": "The project that you are trying to import is private and has {{members}} members." + }, + "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." + } + } }, "LIKE_BUTTON": { "LIKE": "Beğen", @@ -819,8 +887,11 @@ "DELETE_ACCOUNT": { "SECTION_NAME": "Taiga Hesabını Sil", "CONFIRM": "Taiga hesabınızı silmek istediğinizden emin misiniz?", - "SUBTITLE": "Sizi özleyeceğiz! :-(", - "NEWSLETTER_LABEL_TEXT": "Bundan böyle bülteninizi almak istemiyorum." + "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! :(" }, "DELETE_PROJECT": { "TITLE": "Proje Sil", @@ -876,7 +947,25 @@ }, "CREATE_MEMBER": { "PLACEHOLDER_INVITATION_TEXT": "(Opsiyonel) Davetinize kişiselleştirilmiş bir metin ekleyin. Yeni üyelerinize tatlı bir şeyler söyleyin ;-)", - "PLACEHOLDER_TYPE_EMAIL": "Bir e-posta girin" + "PLACEHOLDER_TYPE_EMAIL": "Bir e-posta girin", + "LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "Unfortunately, this project can't have more than {{maxMembers}} members.
If you would like to increase the current limit, please contact the administrator.", + "LIMIT_USERS_WARNING_MESSAGE": "Unfortunately, this project can't have more than {{maxMembers}} members." + }, + "LEAVE_PROJECT_WARNING": { + "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" + }, + "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.", + "BUTTON": "Request project owner change" + } + }, + "CHANGE_OWNER": { + "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" } }, "US": { @@ -1304,12 +1393,18 @@ } }, "WIZARD": { - "SECTION_TITLE_CHOOSE_TEMPLATE": "Bir şablon seç", - "CHOOSE_TEMPLATE_TEXT": "Hangi şablon sizin projeniz için daha uygun?", "SECTION_TITLE_CREATE_PROJECT": "Proje Oluştur", "CREATE_PROJECT_TEXT": "Taze ve temiz. Heycan verici!", - "PROGRESS_TEMPLATE_SELECTION": "Şablon seçimi", - "PROGRESS_NAME_DESCRIPTION": "İsim ve tanım" + "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}}", diff --git a/app/locales/taiga/locale-zh-hant.json b/app/locales/taiga/locale-zh-hant.json index 3bfd36b7..c1f81f88 100644 --- a/app/locales/taiga/locale-zh-hant.json +++ b/app/locales/taiga/locale-zh-hant.json @@ -41,7 +41,8 @@ "IOCAINE_TEXT": "感到任務的不堪負荷?確認其它人在編輯任務時知道此狀況,可以點選Iocaine。它可能會成為免疫的致命狀況,只要長期小量消耗,但如果你只是偶而挑戰它可有助表現。", "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", - "CAPSLOCK_WARNING": "注意你輸入了大寫符號,大小寫字母有所不同", + "OWNER": "Project Owner", + "CAPSLOCK_WARNING": "Be careful! You are using capital letters in an input field that is case sensitive.", "FORM_ERRORS": { "DEFAULT_MESSAGE": "該數值似乎為無效", "TYPE_EMAIL": "該電子郵件應為有效地址", @@ -65,7 +66,9 @@ "MIN_CHECK": "你必須至少選擇 %s 選項", "MAX_CHECK": "你必須至多選出 %s選項", "RANGE_CHECK": "你必須在%s 與 %s 之間作出選擇", - "EQUAL_TO": "該數值應為一致" + "EQUAL_TO": "該數值應為一致", + "LINEWIDTH": "One or more lines is perhaps too long. Try to keep under %s characters.", + "PIKADAY": "Invalid date format, please use DD MMM YYYY (like 23 Mar 1984)" }, "PICKERDATE": { "FORMAT": "DD MMM YYYY", @@ -315,7 +318,8 @@ "PLACEHOLDER_FIELD": "使用者名稱或電子郵件", "ACTION_RESET_PASSWORD": "重設密碼 ", "LINK_CANCEL": "不,請帶我回去,我記起來了", - "SUCCESS": "檢查你的收信箱
我們送出了一封信
裏面有設定你新電子郵件的相關指示", + "SUCCESS_TITLE": "Check your inbox!", + "SUCCESS_TEXT": "We sent you an email with the instructions to set a new password", "ERROR": "按我們的記錄,你尚未註冊" }, "CHANGE_PASSWORD": { @@ -373,7 +377,6 @@ "DEPRECATED_FILE": "棄用?", "ADD": "加入新附件 {{maxFileSizeMsg}}", "DROP": "在此移除附件 ", - "MAX_FILE_SIZE": "[Max. size: {{maxFileSize}}]", "SHOW_DEPRECATED": "+ 顯示棄用的附件", "HIDE_DEPRECATED": "+ 隱藏棄用的附件", "COUNT_DEPRECATED": "({{ counter }} 遭棄用)", @@ -406,7 +409,9 @@ "TITLE": "管理成員", "PAGE_TITLE": "成員資格 - {{projectName}}", "ADD_BUTTON": "+ 新成員", - "ADD_BUTTON_TITLE": "增加新成員" + "ADD_BUTTON_TITLE": "增加新成員", + "LIMIT_USERS_WARNING_MESSAGE_FOR_ADMIN": "Unfortunately, this project has reached its limit of ({{members}}) allowed members.", + "LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "This project has reached its limit of ({{members}}) allowed members. If you would like to increase that limit please contact the administrator." }, "PROJECT_EXPORT": { "TITLE": "匯出", @@ -428,6 +433,10 @@ "DISABLE": "停用", "BACKLOG": "待辦任務優先表", "BACKLOG_DESCRIPTION": "管理你的 User Story 讓接下來的及優先的工作能被有條理地檢視 ", + "NUMBER_SPRINTS": "Expected number of sprints", + "NUMBER_SPRINTS_HELP": "0 for an undetermined number", + "NUMBER_US_POINTS": "Expected total of story points", + "NUMBER_US_POINTS_HELP": "0 for an undetermined number", "KANBAN": "Kanban(看板)", "KANBAN_DESCRIPTION": "在此看板上組織你的專案", "ISSUES": "問題 ", @@ -435,9 +444,9 @@ "WIKI": "維基", "WIKI_DESCRIPTION": "新增,修正或是刪除與他人合作的內容。這裏正是專案文件記錄區", "MEETUP": "符合", - "MEETUP_DESCRIPTION": "選擇你的視訊系統。有些開發者需要面對面接觸", + "MEETUP_DESCRIPTION": "Choose your videoconference system.", "SELECT_VIDEOCONFERENCE": "選擇一個視訊會議系統 ", - "SALT_CHAT_ROOM": "你可以把聊天室名稱加上salt code亂數密碼 ", + "SALT_CHAT_ROOM": "Add a prefix to the chatroom name", "JITSI_CHAT_ROOM": "Jitsi", "APPEARIN_CHAT_ROOM": "AppearIn", "TALKY_CHAT_ROOM": "Talky", @@ -449,22 +458,31 @@ "PROJECT_DETAILS": "專案細節", "PROJECT_NAME": "專案名稱", "PROJECT_SLUG": "專案代稱", - "NUMBER_SPRINTS": "衝刺任務數目(0為未決定數量)", - "NUMBER_US_POINTS": "使用者故事點數數目 (0 為未決定數目)", "TAGS": "標籤", "DESCRIPTION": "描述", "RECRUITING": "這個專案是否在徵人", "RECRUITING_MESSAGE": "你在找誰?", "RECRUITING_PLACEHOLDER": "定義你要找的資訊", "PUBLIC_PROJECT": "公開專案", - "PUBLIC_PROJECT_DESC": "用戶能夠找到並檢視你的專案", "PRIVATE_PROJECT": "不公開專案", - "PRIVATE_PROJECT_DESC": "本專案預設為私密不公開顯示", "PRIVATE_OR_PUBLIC": "公開專案和私密專案有何差異?", "DELETE": "刪除此專案", "LOGO_HELP": "此圖片將被裁成80x80px.
", "CHANGE_LOGO": "更改圖標", - "ACTION_USE_DEFAULT_LOGO": "使用設預圖片" + "ACTION_USE_DEFAULT_LOGO": "使用設預圖片", + "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", + "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", + "REQUEST_OWNERSHIP": "Request ownership", + "REQUEST_OWNERSHIP_CONFIRMATION_TITLE": "Do you want to become the new project owner?", + "REQUEST_OWNERSHIP_DESC": "Request that current project owner {{name}} transfer ownership of this project to you.", + "REQUEST_OWNERSHIP_BUTTON": "要求", + "REQUEST_OWNERSHIP_SUCCESS": "We'll notify the project owner", + "CHANGE_OWNER": "Change owner", + "CHANGE_OWNER_SUCCESS_TITLE": "Ok, your request has been sent!", + "CHANGE_OWNER_SUCCESS_DESC": "We will notify you by email if the project ownership request is accepted or declined" }, "REPORTS": { "TITLE": "Reports", @@ -495,7 +513,8 @@ "ISSUE_ADD": "在問題中加入客制欄位", "FIELD_TYPE_TEXT": "單行文字", "FIELD_TYPE_MULTI": "多行", - "FIELD_TYPE_DATE": "日期" + "FIELD_TYPE_DATE": "日期", + "FIELD_TYPE_URL": "Url" }, "PROJECT_VALUES": { "PAGE_TITLE": "{{sectionName}} - 專案數值 - {{projectName}}", @@ -543,7 +562,7 @@ "COUNT_MEMBERS": "{{ role.members_count }} 這類角色的成員", "TITLE_DELETE_ROLE": "删除角色", "REPLACEMENT_ROLE": "和此角色有關的使用者都將遭移除 ", - "WARNING_DELETE_ROLE": "小心, 所有角色的估算都將會移除", + "WARNING_DELETE_ROLE": "Be careful! All role estimations will be removed", "ERROR_DELETE_ALL": "你不能刪除所有數值", "EXTERNAL_USER": "外部使用者" }, @@ -671,6 +690,24 @@ }, "SUBMENU_THIDPARTIES": { "TITLE": "服務 " + }, + "PROJECT_TRANSFER": { + "DO_YOU_ACCEPT_PROJECT_OWNERNSHIP": "Would you like to become the new project owner?", + "PRIVATE": "Private", + "ACCEPTED_PROJECT_OWNERNSHIP": "Congratulations! You're now the new project owner.", + "REJECTED_PROJECT_OWNERNSHIP": "OK. We'll contact the current project owner", + "ACCEPT": "接受", + "REJECT": "Reject", + "PROPOSE_OWNERSHIP": "{{owner}}, the current owner of the project {{project}} has asked that you become the new project owner.", + "ADD_COMMENT_QUESTION": "Would you like to send a question to the project owner?", + "ADD_COMMENT": "Would you like to add a comment for the project owner?", + "UNLIMITED_PROJECTS": "Unlimited", + "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" + }, + "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" } }, "USER": { @@ -731,6 +768,11 @@ "FANS_COUNTER_TITLE": "{total, plural, one{一個粉絲} other{# 粉絲}}", "WATCHERS_COUNTER_TITLE": "{total, plural, one{一個觀注者} other{# 觀注者}}", "MEMBERS_COUNTER_TITLE": "{total, plural, one{one member} other{# members}}", + "BLOCKED_PROJECT": { + "BLOCKED": "Blocked project", + "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": "已定義
點數", @@ -777,6 +819,7 @@ "CHANGE_PASSWORD": "更換密碼 ", "DASHBOARD_TITLE": "控制台", "DISCOVER_TITLE": "發現流行專案", + "NEW_ITEM": "新 ", "DISCOVER": "發現", "ACTION_REORDER": "拖移 & 丟到來記錄" }, @@ -791,7 +834,32 @@ "ERROR_TOO_MANY_REQUEST": "抱歉系統繁忙中,請稍後再試試 ", "ERROR_MESSAGE": "我們的系統無法滙入你的資料", "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) 超過系統容量上限, 請重傳小一點的檔案 ({{maxFileSize}})", - "SYNC_SUCCESS": "你的專案已成功滙入" + "SYNC_SUCCESS": "你的專案已成功滙入", + "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.", + "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 private 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": "The project that you are trying to import is private and has {{members}} members." + }, + "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." + } + } }, "LIKE_BUTTON": { "LIKE": "喜歡", @@ -819,8 +887,11 @@ "DELETE_ACCOUNT": { "SECTION_NAME": "刪除Taiga帳戶", "CONFIRM": "你確定要刪除Taiga帳戶嗎?", - "SUBTITLE": "我們會想念你:-(", - "NEWSLETTER_LABEL_TEXT": "不願再收到電子月報" + "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! :(" }, "DELETE_PROJECT": { "TITLE": "刪除專案", @@ -876,7 +947,25 @@ }, "CREATE_MEMBER": { "PLACEHOLDER_INVITATION_TEXT": "(非必要) 加上一段私人文字在邀請信,告訴你的新成員一些好事 ;-)", - "PLACEHOLDER_TYPE_EMAIL": "輸入一個電郵地址" + "PLACEHOLDER_TYPE_EMAIL": "輸入一個電郵地址", + "LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "Unfortunately, this project can't have more than {{maxMembers}} members.
If you would like to increase the current limit, please contact the administrator.", + "LIMIT_USERS_WARNING_MESSAGE": "Unfortunately, this project can't have more than {{maxMembers}} members." + }, + "LEAVE_PROJECT_WARNING": { + "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" + }, + "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.", + "BUTTON": "Request project owner change" + } + }, + "CHANGE_OWNER": { + "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" } }, "US": { @@ -1304,12 +1393,18 @@ } }, "WIZARD": { - "SECTION_TITLE_CHOOSE_TEMPLATE": "選擇外觀 ", - "CHOOSE_TEMPLATE_TEXT": "哪一個樣版最適合你的專案", "SECTION_TITLE_CREATE_PROJECT": "創建專案", "CREATE_PROJECT_TEXT": "新鮮與乾淨,太好了", - "PROGRESS_TEMPLATE_SELECTION": "外觀選擇", - "PROGRESS_NAME_DESCRIPTION": "名稱與描述" + "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}}", diff --git a/app/modules/attachments/attachment-gallery.scss b/app/modules/attachments/attachment-gallery.scss index 029b29a9..adeb7276 100644 --- a/app/modules/attachments/attachment-gallery.scss +++ b/app/modules/attachments/attachment-gallery.scss @@ -13,58 +13,63 @@ opacity: 1; } } - .attachment-image { - display: inline-block; - } - img { - height: 150px; - margin-bottom: .2rem; - width: 200px; - &:hover { - filter: saturate(150%) hue-rotate(60deg); - transition: all .3s cubic-bezier(.01, .7, 1, 1); - } - } - &.deprecated { - img { - opacity: .5; - } - .attachment-name { - color: $gray-light; - } - } - .attachment-data { - align-content: center; - display: flex; - justify-content: space-between; - } .attachment-name { @extend %light; @include ellipsis(175px); display: inline-block; } - .icon-delete { - color: $red-light; - margin-left: auto; - opacity: 0; - transition: opacity .3s ease-in; - transition-delay: .2s; - &:hover { - color: $red; - } - } - .loading-container { - align-items: center; - display: flex; - height: 150px; - justify-content: center; - margin: 0 .5rem .5rem 0; - width: 200px; - } - .loading-spinner { - margin: 0 auto; - max-height: 3rem; - max-width: 3rem; + } + .attachment-image { + display: inline-block; + } + img { + height: 150px; + margin-bottom: .2rem; + width: 200px; + &:hover { + filter: saturate(150%) hue-rotate(60deg); + transition: all .3s cubic-bezier(.01, .7, 1, 1); } } + &.deprecated { + img { + opacity: .5; + } + .attachment-name { + color: $gray-light; + } + } + .attachment-data { + align-content: center; + display: flex; + justify-content: space-between; + } + .icon-delete { + margin-left: auto; + opacity: 0; + transition: opacity .2s ease-in; + transition-delay: .1s; + svg { + fill: $red-light; + } + &:hover { + svg { + color: $red; + } + + } + } + .loading-container { + align-items: center; + display: flex; + height: 150px; + justify-content: center; + margin: 0 .5rem .5rem 0; + width: 200px; + } + .loading-spinner { + margin: 0 auto; + max-height: 3rem; + max-width: 3rem; + } } diff --git a/app/modules/attachments/attachment-list.scss b/app/modules/attachments/attachment-list.scss index dc2e21db..df533f2b 100644 --- a/app/modules/attachments/attachment-list.scss +++ b/app/modules/attachments/attachment-list.scss @@ -47,34 +47,29 @@ flex-shrink: 0; justify-content: space-around; margin-left: auto; - .settings, - .editable-settings { - @extend %large; - color: $gray-light; - &:hover { - color: $primary; - } - } .settings { opacity: 0; } .editable-settings { opacity: 1; } - .icon-delete { + svg { + fill: $gray-light; + } + .icon-edit, + .icon-save { &:hover { - color: $red; + fill: $primary; } } - .icon-drag-v { - cursor: move; + .icon-trash, + .icon-close { + &:hover { + fill: $red; + } } - } - .icon-delete { - @extend %large; - color: $gray-light; - &:hover { - color: $red; + .icon-drag { + cursor: move; } } .editable-attachment-deprecated { diff --git a/app/modules/attachments/attachments.scss b/app/modules/attachments/attachments.scss index 82df8ce6..61b9e15f 100644 --- a/app/modules/attachments/attachments.scss +++ b/app/modules/attachments/attachments.scss @@ -3,7 +3,7 @@ } .attachments-header { - align-content: space-between; + align-content: center; align-items: center; background: $whitish; display: flex; @@ -34,9 +34,9 @@ } svg { fill: $white; - height: 1.25rem; + height: 1.2rem; margin-bottom: -.2rem; - width: 1.25rem; + width: 1.2rem; } } button { @@ -51,7 +51,6 @@ svg { fill: $gray-light; height: 1.6rem; - margin-bottom: -.2rem; width: 1.6rem; } } @@ -78,6 +77,7 @@ .single-attachment { @extend %small; + background: rgba($white, .9); &.ui-sortable-helper { background: lighten($primary, 60%); box-shadow: 1px 1px 10px rgba($black, .1); @@ -90,12 +90,11 @@ .attachment-name { @extend %bold; padding-right: 1rem; - .icon { - margin-right: .25rem; - } svg { - height: 1.2rem; - width: 1.2rem; + fill: $gray; + height: .9rem; + margin-right: .25rem; + width: .9rem; } } .attachment-size { diff --git a/app/modules/components/attachment/attachment-gallery.jade b/app/modules/components/attachment/attachment-gallery.jade index dbb353b1..b6c560a1 100644 --- a/app/modules/components/attachment/attachment-gallery.jade +++ b/app/modules/components/attachment/attachment-gallery.jade @@ -30,8 +30,9 @@ span {{::vm.attachment.getIn(['file', 'name'])}} a.icon-delete( - ng-if="vm.attachment.get('editable')" href="" title="{{'COMMON.DELETE' | translate}}" ng-click="vm.delete()" ) + svg.icon.icon-trash + use(xlink:href="#icon-trash") diff --git a/app/modules/components/attachment/attachment.jade b/app/modules/components/attachment/attachment.jade index 32df1083..b0207960 100644 --- a/app/modules/components/attachment/attachment.jade +++ b/app/modules/components/attachment/attachment.jade @@ -12,8 +12,8 @@ form.single-attachment( target="_blank" download="{{::vm.attachment.getIn(['file', 'name'])}}" ) - span.icon - include ../../../svg/attachment.svg + svg.icon.icon-attachment + use(xlink:href="#icon-attachment") span {{::vm.attachment.getIn(['file', 'name'])}} .attachment-comments(ng-if="!vm.attachment.get('editable') && vm.attachment.getIn(['file', 'description'])") @@ -47,34 +47,44 @@ form.single-attachment( .attachment-settings(ng-if="vm.attachment.get('editable')") div(tg-loading="vm.attachment.get('loading')") - a.editable-settings.icon.icon-floppy( + a.editable-settings( href="" title="{{'COMMON.SAVE' | translate}}" ng-click="vm.save()" ) + svg.drag.icon.icon-save + use(xlink:href="#icon-save") div - a.editable-settings.icon.icon-delete( + a.editable-settings( href="" title="{{'COMMON.CANCEL' | translate}}" ng-click="vm.editMode(false)" ) + svg.drag.icon.icon-close + use(xlink:href="#icon-close") .attachment-settings( ng-if="!vm.attachment.get('editable')" tg-check-permission="modify_{{vm.type}}" ) - a.settings.icon.icon-edit( + a.settings( href="" title="{{'COMMON.EDIT' | translate}}" ng-click="vm.editMode(true)" ) - a.settings.icon.icon-delete( + svg.drag.icon.icon-edit + use(xlink:href="#icon-edit") + a.settings( href="" title="{{'COMMON.DELETE' | translate}}" ng-click="vm.delete()" ) - a.settings.icon.icon-drag-v( + svg.drag.icon.icon-trash + use(xlink:href="#icon-trash") + a.settings( href="" title="{{'COMMON.DRAG' | translate}}" ) + svg.drag.icon.icon-drag + use(xlink:href="#icon-drag") diff --git a/app/modules/components/attachments-full/attachments-full.jade b/app/modules/components/attachments-full/attachments-full.jade index 72d5e97c..1e4e58aa 100644 --- a/app/modules/components/attachments-full/attachments-full.jade +++ b/app/modules/components/attachments-full/attachments-full.jade @@ -11,21 +11,24 @@ section.attachments( ng-click="vm.setMode('gallery')" title="{{ 'ATTACHMENT.GALLERY_VIEW_MODE' | translate }}" ) - include ../../../svg/gallery.svg + svg.icon.icon-gallery + use(xlink:href="#icon-gallery") button.view-list( ng-class="{'is-active': vm.mode == 'list'}" ng-if="vm.attachments.size" ng-click="vm.setMode('list')" title="{{ 'ATTACHMENT.LIST_VIEW_MODE' | translate }}" ) - include ../../../svg/list.svg + svg.icon.icon-list + use(xlink:href="#icon-list") .add-attach( tg-check-permission="modify_{{vm.type}}" title!="{{'ATTACHMENT.ADD' | translate}}" ) label.add-attachment-button(for="add-attach") - include ../../../svg/add.svg + svg.icon.icon-add + use(xlink:href="#icon-add") input( id="add-attach", @@ -52,12 +55,11 @@ section.attachments( .single-attachment(ng-repeat="file in vm.uploadingAttachments()") .attachment-name - span.icon - include ../../../svg/attachment.svg + svg.icon.icon-attachment + use(xlink:href="#icon-attachment") span {{file.name}} .attachment-size span {{file.size | sizeFormat}} - .attachment-comments span {{file.progressMessage}} .percentage(ng-style="{'width': file.progressPercent}") diff --git a/app/modules/components/attachments-simple/attachments-simple.jade b/app/modules/components/attachments-simple/attachments-simple.jade index 461f5ba8..9b4cdcc7 100644 --- a/app/modules/components/attachments-simple/attachments-simple.jade +++ b/app/modules/components/attachments-simple/attachments-simple.jade @@ -5,7 +5,8 @@ section.attachments(tg-attachments-drop="vm.addAttachments(files)") h3.attachments-title #[span.attachments-num {{vm.attachments.size}}] #[span.attachments-text(translate="ATTACHMENT.SECTION_NAME")] .add-attach(title!="{{'ATTACHMENT.ADD' | translate}}") label.add-attachment-button(for="add-attach") - include ../../../svg/add.svg + svg.icon.icon-add + use(xlink:href="#icon-add") input( id="add-attach" type="file" @@ -18,8 +19,8 @@ section.attachments(tg-attachments-drop="vm.addAttachments(files)") .attachment-body.attachment-list .single-attachment(tg-repeat="attachment in vm.attachments track by $index") .attachment-name - span.icon - include ../../../svg/attachment.svg + svg.icon.icon-attachment + use(xlink:href="#icon-attachment") span {{attachment.get('name')}} .attachment-size span {{attachment.get('size') | sizeFormat}} @@ -30,4 +31,5 @@ section.attachments(tg-attachments-drop="vm.addAttachments(files)") title="{{'COMMON.DELETE' | translate}}" ng-click="vm.deleteAttachment(attachment)" ) - include ../../../svg/remove.svg + svg.icon.icon-trash + use(xlink:href="#icon-trash") diff --git a/app/modules/components/attachments-sortable/attachments-sortable.directive.coffee b/app/modules/components/attachments-sortable/attachments-sortable.directive.coffee index c220e9b2..17f62ae6 100644 --- a/app/modules/components/attachments-sortable/attachments-sortable.directive.coffee +++ b/app/modules/components/attachments-sortable/attachments-sortable.directive.coffee @@ -23,7 +23,7 @@ AttachmentSortableDirective = ($parse) -> el.sortable({ items: "div[tg-bind-scope]" - handle: "a.settings.icon.icon-drag-v" + handle: ".settings .icon" containment: ".attachments" dropOnEmpty: true helper: 'clone' diff --git a/app/modules/components/live-announcement/live-announcement.jade b/app/modules/components/live-announcement/live-announcement.jade index 25df0db7..1c2a4225 100644 --- a/app/modules/components/live-announcement/live-announcement.jade +++ b/app/modules/components/live-announcement/live-announcement.jade @@ -9,4 +9,5 @@ href="" title="{{ COMMON.CLOSE | translate }}" ) - include ../../../svg/remove.svg + svg.icon.icon-close + use(xlink:href="#icon-close") diff --git a/app/modules/components/project-menu/project-menu.controller.coffee b/app/modules/components/project-menu/project-menu.controller.coffee index cf5710a3..23fc3591 100644 --- a/app/modules/components/project-menu/project-menu.controller.coffee +++ b/app/modules/components/project-menu/project-menu.controller.coffee @@ -95,25 +95,28 @@ class ProjectMenuController return sectionName _videoConferenceUrl: () -> + # Get base url if @.project.get("videoconferences") == "appear-in" baseUrl = "https://appear.in/" else if @.project.get("videoconferences") == "talky" baseUrl = "https://talky.io/" else if @.project.get("videoconferences") == "jitsi" baseUrl = "https://meet.jit.si/" - url = @.project.get("slug") + "-" + taiga.slugify(@.project.get("videoconferences_extra_data")) - url = url.replace(/-/g, "") - return baseUrl + url else if @.project.get("videoconferences") == "custom" return @.project.get("videoconferences_extra_data") else return "" + # Add prefix to the chat room name if exist if @.project.get("videoconferences_extra_data") - url = @.project.get("slug") + "-" + @.project.get("videoconferences_extra_data") + url = @.project.get("slug") + "-" + taiga.slugify(@.project.get("videoconferences_extra_data")) else url = @.project.get("slug") + # Some special cases + if @.project.get("videoconferences") == "jitsi" + url = url.replace(/-/g, "") + return baseUrl + url angular.module("taigaComponents").controller("ProjectMenu", ProjectMenuController) diff --git a/app/modules/components/project-menu/project-menu.jade b/app/modules/components/project-menu/project-menu.jade index e411f98a..6b845c6e 100644 --- a/app/modules/components/project-menu/project-menu.jade +++ b/app/modules/components/project-menu/project-menu.jade @@ -12,8 +12,9 @@ nav.menu( aria-label="{{'PROJECT.SECTION.SEARCH' | translate}}" tabindex="1" ) - span.icon.icon-search - span.helper(translate="PROJECT.SECTION.SEARCH") + svg.icon.icon-search + use(xlink:href="#icon-search") + span.helper(translate="PROJECT.SECTION.SEARCH") li(id="nav-timeline") a( @@ -22,7 +23,8 @@ nav.menu( aria-label="{{'PROJECT.SECTION.TIMELINE' | translate}}" tabindex="2" ) - include ../../../svg/timeline.svg + svg.icon.icon-timeline + use(xlink:href="#icon-timeline") span.helper(translate="PROJECT.SECTION.TIMELINE") li(id="nav-backlog", ng-if="vm.menu.get('backlog')") @@ -32,7 +34,8 @@ nav.menu( aria-label="{{'PROJECT.SECTION.BACKLOG' | translate}}" tabindex="2" ) - span.icon.icon-scrum + svg.icon.icon-scrum + use(xlink:href="#icon-scrum") span.helper(translate="PROJECT.SECTION.BACKLOG") li(id="nav-kanban", ng-if="vm.menu.get('kanban')") @@ -42,7 +45,8 @@ nav.menu( aria-label="{{'PROJECT.SECTION.KANBAN' | translate}}" tabindex="3" ) - span.icon.icon-kanban + svg.icon.icon-kanban + use(xlink:href="#icon-kanban") span.helper(translate="PROJECT.SECTION.KANBAN") li(id="nav-issues", ng-if="vm.menu.get('issues')") @@ -52,7 +56,8 @@ nav.menu( aria-label="{{'PROJECT.SECTION.ISSUES' | translate}}" tabindex="4" ) - span.icon.icon-issues + svg.icon.icon-issues + use(xlink:href="#icon-issues") span.helper(translate="PROJECT.SECTION.ISSUES") li(id="nav-wiki", ng-if="vm.menu.get('wiki')") @@ -62,7 +67,8 @@ nav.menu( aria-label="{{'PROJECT.SECTION.WIKI' | translate}}" tabindex="5" ) - span.icon.icon-wiki + svg.icon.icon-wiki + use(xlink:href="#icon-wiki") span.helper(translate="PROJECT.SECTION.WIKI") li(id="nav-team") @@ -72,7 +78,8 @@ nav.menu( aria-label="{{'PROJECT.SECTION.TEAM' | translate}}" tabindex="6" ) - span(class="icon icon-team") + svg.icon.icon-team + use(xlink:href="#icon-team") span.helper(translate="PROJECT.SECTION.TEAM") li(id="nav-video", ng-if="vm.project.get('videoconferenceUrl')") @@ -82,15 +89,17 @@ nav.menu( aria-label="{{'PROJECT.SECTION.MEETUP' | translate}}" tabindex="7" ) - span.icon.icon-video + svg.icon.icon-bubble + use(xlink:href="#icon-bubble") span.helper(translate="PROJECT.SECTION.MEETUP") - li(id="nav-admin", ng-if="vm.project.get('i_am_owner')") + li(id="nav-admin", ng-if="vm.project.get('i_am_admin')") a( tg-nav="project-admin-home:project=vm.project.get('slug')" ng-class="{active: vm.active == 'admin'}" aria-label="{{'PROJECT.SECTION.ADMIN' | translate}}" tabindex="8" ) - span.icon.icon-settings + svg.icon.icon-settings + use(xlink:href="#icon-settings") span.helper(translate="PROJECT.SECTION.ADMIN") diff --git a/app/modules/components/vote-button/vote-button.jade b/app/modules/components/vote-button/vote-button.jade index 24d63b04..f0b07a4c 100644 --- a/app/modules/components/vote-button/vote-button.jade +++ b/app/modules/components/vote-button/vote-button.jade @@ -9,7 +9,8 @@ a.vote-inner( ng-mouseleave="vm.showTextWhenMouseIsLeave()" ) span.track-icon - include ../../../svg/upvote.svg + svg.icon.icon-upvote + use(xlink:href="#icon-upvote") span.track-button-counter( title="{{ 'COMMON.VOTE_BUTTON.COUNTER_TITLE'|translate:{total:vm.item.total_voters||0}:'messageformat' }}", tg-loading="vm.loading" @@ -18,7 +19,8 @@ a.vote-inner( //- Anonymous user button span.vote-inner(ng-if="::!vm.user") span.track-icon - include ../../../svg/upvote.svg + svg.icon.icon-upvote + use(xlink:href="#icon-upvote") span.track-button-counter( title="{{ 'COMMON.VOTE_BUTTON.COUNTER_TITLE'|translate:{total:vm.item.total_voters||0}:'messageformat' }}" ) {{ ::vm.item.total_voters }} diff --git a/app/modules/components/watch-button/watch-button-ticket.jade b/app/modules/components/watch-button/watch-button-ticket.jade index e54d36fd..661be69b 100644 --- a/app/modules/components/watch-button/watch-button-ticket.jade +++ b/app/modules/components/watch-button/watch-button-ticket.jade @@ -13,20 +13,18 @@ div.ticket-watch-inner ng-mouseover="vm.showTextWhenMouseIsOver()" ng-mouseleave="vm.showTextWhenMouseIsLeave()" ) - span.track-icon - include ../../../svg/watch.svg - span( - ng-if="!vm.item.is_watcher", - translate="COMMON.WATCH_BUTTON.WATCH" - ) - span( - ng-if="vm.item.is_watcher && !vm.isMouseOver", - translate="COMMON.WATCH_BUTTON.WATCHING" - ) - span( - ng-if="vm.item.is_watcher && vm.isMouseOver", - translate="COMMON.WATCH_BUTTON.UNWATCH" - ) + span(ng-if="!vm.item.is_watcher") + svg.icon.icon-watch + use(xlink:href="#icon-watch") + | {{'COMMON.WATCH_BUTTON.WATCH' | translate}} + span(ng-if="vm.item.is_watcher && !vm.isMouseOver",) + svg.icon.icon-watch + use(xlink:href="#icon-watch") + | {{'COMMON.WATCH_BUTTON.WATCHING' | translate}} + span(ng-if="vm.item.is_watcher && vm.isMouseOver") + svg.icon.icon-unwatch + use(xlink:href="#icon-unwatch") + | {{'COMMON.WATCH_BUTTON.UNWATCH' | translate}} a.add-watcher( href="" diff --git a/app/modules/components/watch-button/watch-button.jade b/app/modules/components/watch-button/watch-button.jade index 2d25bbde..842f0d60 100644 --- a/app/modules/components/watch-button/watch-button.jade +++ b/app/modules/components/watch-button/watch-button.jade @@ -2,8 +2,7 @@ mixin counter span.track-button-counter( title="{{ 'COMMON.WATCH_BUTTON.COUNTER_TITLE'|translate:{total:vm.item.watchers.length||0}:'messageformat' }}", tg-loading="vm.loading" - ) - | {{ vm.item.watchers.length }} + ) {{ vm.item.watchers.length }} //- Registered user button @@ -17,8 +16,8 @@ a.track-button.watch-button.watch-container( ng-mouseleave="vm.showTextWhenMouseIsLeave()" ) span.track-inner - span.track-icon - include ../../../svg/watch.svg + svg.icon.icon-watch + use(xlink:href="#icon-watch") span( ng-if="!vm.item.is_watcher", translate="COMMON.WATCH_BUTTON.WATCH" @@ -39,6 +38,7 @@ span.track-button.watch-button.watch-container( ) span.track-inner span.track-icon - include ../../../svg/watch.svg + svg.icon.icon-watch + use(xlink:href="#icon-watch") span(translate="COMMON.WATCH_BUTTON.WATCHERS") +counter diff --git a/app/modules/discover/components/discover-home-order-by/discover-home-order-by.jade b/app/modules/discover/components/discover-home-order-by/discover-home-order-by.jade index fbaaa04c..9379c7d0 100644 --- a/app/modules/discover/components/discover-home-order-by/discover-home-order-by.jade +++ b/app/modules/discover/components/discover-home-order-by/discover-home-order-by.jade @@ -3,7 +3,8 @@ href="#" ng-click="vm.open()" ) {{vm.currentText()}} - span.icon-arrow-bottom + svg.icon.icon-arrow-down + use(xlink:href="#icon-arrow-down") ul.filter-list(ng-if="vm.is_open") li(ng-click="vm.orderBy('week')") {{ 'DISCOVER.FILTERS.WEEK' | translate }} diff --git a/app/modules/discover/components/discover-search-bar/discover-search-bar.jade b/app/modules/discover/components/discover-search-bar/discover-search-bar.jade index 201c6bca..436c92af 100644 --- a/app/modules/discover/components/discover-search-bar/discover-search-bar.jade +++ b/app/modules/discover/components/discover-search-bar/discover-search-bar.jade @@ -18,12 +18,12 @@ div.discover-header placeholder="{{ 'DISCOVER.SEARCH.INPUT_PLACEHOLDER' | translate }}" ng-model="vm.q" ) - a.search-button( + svg.search-button.icon.icon-search( ng-click="vm.submitFilter()" href="#" title="{{ 'DISCOVER.SEARCH.ACTION_TITLE' | translate }}" ) - include ../../../../svg/search.svg + use(xlink:href="#icon-search") fieldset.searchbox-filters(ng-if="vm.filter") input( diff --git a/app/modules/discover/components/discover-search-bar/discover-search-bar.scss b/app/modules/discover/components/discover-search-bar/discover-search-bar.scss index a45705b2..888a06b8 100644 --- a/app/modules/discover/components/discover-search-bar/discover-search-bar.scss +++ b/app/modules/discover/components/discover-search-bar/discover-search-bar.scss @@ -36,19 +36,15 @@ } } .search-button { + @include svg-size(1.5rem); + fill: $gray-light; position: absolute; right: 1rem; top: 1rem; + transition: fill .2s; &:hover { - svg { - fill: $primary; - } + cursor: pointer; + fill: $primary; } } - svg { - fill: $gray-light; - height: 1.5rem; - transition: all .2; - width: 1.5rem; - } } diff --git a/app/modules/discover/components/discover-search-list-header/discover-search-list-header.jade b/app/modules/discover/components/discover-search-list-header/discover-search-list-header.jade index b480a619..42c854fb 100644 --- a/app/modules/discover/components/discover-search-list-header/discover-search-list-header.jade +++ b/app/modules/discover/components/discover-search-list-header/discover-search-list-header.jade @@ -1,7 +1,8 @@ .discover-results-header .discover-results-header-inner .title - include ../../../../svg/search.svg + svg.icon.icon-search + use(xlink:href="#icon-search") h2 {{ 'DISCOVER.SEARCH.RESULTS' | translate }} .filter-discover-search(ng-mouseleave="vm.toggleClose()") @@ -10,14 +11,16 @@ ng-click="vm.openLike()" ng-class="{active: vm.like_is_open}" ) - include ../../../../svg/like.svg + svg.icon.icon-like + use(xlink:href="#icon-like") span {{ 'DISCOVER.MOST_LIKED' | translate }} a.discover-search-filter( href="#" ng-click="vm.openActivity()" ng-class="{active: vm.activity_is_open}" ) - include ../../../../svg/activity.svg + svg.icon.icon-activity + use(xlink:href="#icon-activity") span {{ 'DISCOVER.MOST_ACTIVE' | translate }} .discover-search-subfilter.most-liked-subfilter(ng-if="vm.like_is_open") diff --git a/app/modules/discover/components/discover-search-list-header/discover-search-list-header.scss b/app/modules/discover/components/discover-search-list-header/discover-search-list-header.scss index d3112c54..6f265a9a 100644 --- a/app/modules/discover/components/discover-search-list-header/discover-search-list-header.scss +++ b/app/modules/discover/components/discover-search-list-header/discover-search-list-header.scss @@ -5,8 +5,9 @@ justify-content: space-between; } svg { - @include svg-size(1.1rem); + @include svg-size(1.2rem); fill: $gray-light; + margin-right: .25rem; } .title { @extend %bold; @@ -23,8 +24,14 @@ margin-right: 1rem; &.active { color: $primary; + svg { + fill: $primary; + } } } + svg { + @include svg-size(.8rem); + } } .discover-search-subfilter { diff --git a/app/modules/discover/components/featured-projects/featured-projects.jade b/app/modules/discover/components/featured-projects/featured-projects.jade index 4ad7d167..6811847e 100644 --- a/app/modules/discover/components/featured-projects/featured-projects.jade +++ b/app/modules/discover/components/featured-projects/featured-projects.jade @@ -26,28 +26,31 @@ tg-nav="project:project=project.get('slug')" title="{{::project.get('name')}}" ) {{::project.get('name')}} - span.look-for-people( + svg.look-for-people.icon.icon-recruit( ng-if="project.get('is_looking_for_people')" - title="{{ ::project.get('looking_for_people_note') }}" ) - include ../../../../svg/recruit.svg + use(xlink:href="#icon-recruit") + title="{{ ::project.get('looking_for_people_note') }}" p.project-card-description {{ ::project.get('description') | limitTo:100 }}{{ ::project.get('description').length < 100 ? '' : '...'}} .project-card-statistics span.statistic( ng-class="{'active': project.get('is_fan')}" title="{{ 'PROJECT.FANS_COUNTER_TITLE'|translate:{total:project.get('total_fans')||0}:'messageformat' }}" ) - include ../../../../svg/like.svg + svg.icon.icon-like + use(xlink:href="#icon-like") span {{::project.get('total_fans')}} span.statistic( ng-class="{'active': project.get('is_watcher')}" title="{{ 'PROJECT.WATCHERS_COUNTER_TITLE'|translate:{total:project.get('total_watchers')||0}:'messageformat' }}" ) - include ../../../../svg/eye.svg + svg.icon.icon-watch + use(xlink:href="#icon-watch") span {{::project.get('total_watchers')}} span.statistic( ng-class="{'active': project.get('i_am_member')}" title="{{ 'PROJECT.MEMBERS_COUNTER_TITLE'|translate:{total:project.get('members').size||0}:'messageformat' }}" ) - include ../../../../svg/team.svg + svg.icon.icon-team + use(xlink:href="#icon-team") span.statistics-num {{ ::project.get('members').size }} diff --git a/app/modules/discover/components/highlighted/highlighted.jade b/app/modules/discover/components/highlighted/highlighted.jade index 4559e647..3f29e101 100644 --- a/app/modules/discover/components/highlighted/highlighted.jade +++ b/app/modules/discover/components/highlighted/highlighted.jade @@ -24,29 +24,30 @@ tg-nav="project:project=project.get('slug')" title="{{::project.get('name')}}" ) {{::project.get('name')}} - span.look-for-people( - ng-if="project.get('is_looking_for_people')" - title="{{ ::project.get('looking_for_people_note') }}" - ) - include ../../../../svg/recruit.svg + svg.look-for-people.icon.icon-recruit(ng-if="project.get('is_looking_for_people')") + use(xlink:href="#icon-recruit") + title="{{ ::project.get('looking_for_people_note') }}" .project-statistics span.statistic( ng-class="{'active': project.get('is_fan')}" title="{{ 'PROJECT.FANS_COUNTER_TITLE'|translate:{total:project.get('total_fans')||0}:'messageformat' }}" ) - include ../../../../svg/like.svg + svg.icon.icon-like + use(xlink:href="#icon-like") span {{::project.get('total_fans')}} span.statistic( ng-class="{'active': project.get('is_watcher')}" title="{{ 'PROJECT.WATCHERS_COUNTER_TITLE'|translate:{total:project.get('total_watchers')||0}:'messageformat' }}" ) - include ../../../../svg/eye.svg + svg.icon.icon-watch + use(xlink:href="#icon-watch") span {{::project.get('total_watchers')}} span.statistic( ng-class="{'active': project.get('i_am_member')}" title="{{ 'PROJECT.MEMBERS_COUNTER_TITLE'|translate:{total:project.get('members').size||0}:'messageformat' }}" ) - include ../../../../svg/team.svg + svg.icon.icon-team + use(xlink:href="#icon-team") span.statistics-num {{ ::project.get('members').size }} p.project-description {{ ::project.get('description') | limitTo:150 }}{{ ::project.get('description').length < 150 ? '' : '...'}} diff --git a/app/modules/discover/components/highlighted/highlighted.scss b/app/modules/discover/components/highlighted/highlighted.scss index fb2091b9..8dced746 100644 --- a/app/modules/discover/components/highlighted/highlighted.scss +++ b/app/modules/discover/components/highlighted/highlighted.scss @@ -34,14 +34,19 @@ justify-content: space-between; margin-bottom: 1rem; svg { - @include svg-size(1.5rem); + @include svg-size(.8rem); fill: $gray-light; - margin: .5rem; + margin-left: .5rem; } } .title-wrapper { align-items: center; display: flex; + svg { + @include svg-size(1.25rem); + fill: $gray-light; + margin-right: .5rem; + } } .title { @extend %bold; @@ -97,6 +102,11 @@ position: relative; top: .2rem; } + &:hover { + svg { + fill: currentColor; + } + } } .filter-list { background: $black; @@ -163,11 +173,9 @@ } } .look-for-people { - svg { - @include svg-size(); - fill: $gray-light; - margin-left: .5rem; - } + @include svg-size(); + fill: $gray-light; + margin-left: .5rem; } .project-description { @extend %small; @@ -179,8 +187,9 @@ flex-basis: 140px; justify-content: flex-end; svg { - @include svg-size(.8rem); + @include svg-size(.75rem); fill: $gray-light; + margin-right: .25rem; } .svg-eye-closed { display: none; diff --git a/app/modules/discover/components/most-active/most-active.jade b/app/modules/discover/components/most-active/most-active.jade index 37e58cdf..e90666af 100644 --- a/app/modules/discover/components/most-active/most-active.jade +++ b/app/modules/discover/components/most-active/most-active.jade @@ -1,7 +1,8 @@ .most-active(ng-if="vm.highlighted.size") .header .title-wrapper - include ../../../../svg/activity.svg + svg.icon.icon-activity + use(xlink:href="#icon-activity") h1.title {{ 'DISCOVER.MOST_ACTIVE' | translate }} tg-discover-home-order-by(on-change="vm.orderBy(orderBy)", order-by="vm.currentOrderBy") @@ -14,5 +15,6 @@ .empty-highlighted-project( ng-if="!vm.highlighted.size" ) - include ../../../../svg/activity.svg + svg.icon.icon-activity + use(xlink:href="#icon-activity") span {{ 'DISCOVER.MOST_ACTIVE_EMPTY' | translate }} diff --git a/app/modules/discover/components/most-liked/most-liked.jade b/app/modules/discover/components/most-liked/most-liked.jade index e3967aa0..031f35c3 100644 --- a/app/modules/discover/components/most-liked/most-liked.jade +++ b/app/modules/discover/components/most-liked/most-liked.jade @@ -1,7 +1,8 @@ .most-liked(ng-if="vm.highlighted.size") .header .title-wrapper - include ../../../../svg/like.svg + svg.icon.icon-like + use(xlink:href="#icon-like") h1.title {{ 'DISCOVER.MOST_LIKED' | translate }} tg-discover-home-order-by(on-change="vm.orderBy(orderBy)", order-by="vm.currentOrderBy") tg-highlighted( @@ -13,5 +14,6 @@ .empty-highlighted-project( ng-if="!vm.highlighted.size" ) - include ../../../../svg/like.svg + svg.icon.icon-like + use(xlink:href="#icon-like") span {{ 'DISCOVER.MOST_LIKED_EMPTY' | translate }} diff --git a/app/modules/discover/discover-search/discover-search.jade b/app/modules/discover/discover-search/discover-search.jade index 0e8579ab..3422ad60 100644 --- a/app/modules/discover/discover-search/discover-search.jade +++ b/app/modules/discover/discover-search/discover-search.jade @@ -43,11 +43,9 @@ div(tg-discover-search) tg-nav="project:project=project.get('slug')" title="{{ ::project.get('name') }}" ) {{project.get('name')}} - span.look-for-people( - ng-if="project.get('is_looking_for_people')" - title="{{ ::project.get('looking_for_people_note') }}" - ) - include ../../../svg/recruit.svg + svg.look-for-people.icon.icon-recruit(ng-if="project.get('is_looking_for_people')") + use(xlink:href="#icon-recruit") + title="{{ ::project.get('looking_for_people_note') }}" p {{ ::project.get('description') | limitTo:300 }} span(ng-if="::project.get('description').length > 300") ... .list-itemtype-project-right.project-statistics @@ -55,19 +53,22 @@ div(tg-discover-search) ng-class="{'active': project.get('is_fan')}" title="{{ 'PROJECT.FANS_COUNTER_TITLE'|translate:{total:project.get('total_fans')||0}:'messageformat' }}" ) - include ../../../svg/like.svg + svg.icon.icon-like + use(xlink:href="#icon-like") span {{::project.get('total_fans')}} span.statistic( ng-class="{'active': project.get('is_watcher')}" title="{{ 'PROJECT.WATCHERS_COUNTER_TITLE'|translate:{total:project.get('total_watchers')||0}:'messageformat' }}" ) - include ../../../svg/eye.svg + svg.icon.icon-watch + use(xlink:href="#icon-watch") span {{::project.get('total_watchers')}} span.statistic( ng-class="{'active': project.get('i_am_member')}" title="{{ 'PROJECT.MEMBERS_COUNTER_TITLE'|translate:{total:project.get('members').size||0}:'messageformat' }}" ) - include ../../../svg/team.svg + svg.icon.icon-team + use(xlink:href="#icon-team") span.statistics-num {{ ::project.get('members').size }} a.button-green.more-results( diff --git a/app/modules/discover/discover-search/discover-search.scss b/app/modules/discover/discover-search/discover-search.scss index 9cc13527..b97b58e8 100644 --- a/app/modules/discover/discover-search/discover-search.scss +++ b/app/modules/discover/discover-search/discover-search.scss @@ -4,7 +4,6 @@ margin: 0 8rem; position: relative; } - .search-button { left: 1rem; right: auto; @@ -73,19 +72,17 @@ vertical-align: middle; } .look-for-people { + fill: $gray-light; margin-left: .5rem; - svg { - @include svg-size(1rem); - fill: $gray-light; - } } .project-statistics { display: flex; flex-basis: 300px; justify-content: flex-end; svg { - @include svg-size(.8rem); + @include svg-size(.7rem); fill: $gray-light; + margin-right: .2rem; } .svg-eye-closed { display: none; diff --git a/app/modules/home/duties/duty.jade b/app/modules/home/duties/duty.jade index ee04e0b8..c0678e0a 100644 --- a/app/modules/home/duties/duty.jade +++ b/app/modules/home/duties/duty.jade @@ -1,7 +1,7 @@ a.list-itemtype-ticket( href="{{ ::vm.duty.get('url') }}" title="{{ ::duty.get('subject') }}" - ng-class="{'blocked': vm.duty.get('is_blocked')}" + ng-class="{'blocked': vm.duty.get('is_blocked'), 'blocked-project': vm.duty.get('blockedProject')}" ) div.list-itemtype-avatar(ng-if="::vm.duty.get('assigned_to_extra_info')") img( @@ -16,8 +16,12 @@ a.list-itemtype-ticket( div.list-itemtype-ticket-data p span.ticket-project {{ ::vm.duty.get('projectName')}} + span.ticket-type {{ ::vm.getDutyType() }} span.ticket-status(ng-style="{'color': vm.duty.get('status_extra_info').get('color')}") {{ ::vm.duty.get('status_extra_info').get('name') }} + svg.icon.icon-blocked-project(ng-if="vm.duty.get('blockedProject')") + use(xlink:href="#icon-blocked-project") + title(translate="PROJECT.BLOCKED_PROJECT.BLOCKED") h2 span.ticket-id(tg-bo-ref="duty.get('ref')") diff --git a/app/modules/home/home.service.coffee b/app/modules/home/home.service.coffee index 625b31a2..47aa069f 100644 --- a/app/modules/home/home.service.coffee +++ b/app/modules/home/home.service.coffee @@ -41,6 +41,7 @@ class HomeService extends taiga.Service duty = duty.set('url', url) duty = duty.set('projectName', project.get('name')) + duty = duty.set('blockedProject', project.get('blocked_code')) duty = duty.set("_name", objType) return duty diff --git a/app/modules/home/home.service.spec.coffee b/app/modules/home/home.service.spec.coffee index 24b1f01f..41b162ff 100644 --- a/app/modules/home/home.service.spec.coffee +++ b/app/modules/home/home.service.spec.coffee @@ -128,6 +128,7 @@ describe "tgHome", -> project: '1', url: '/testing-project/us/1', projectName: 'fake1', + blockedProject: undefined, _name: 'userstories' }] tasks: [{ @@ -136,6 +137,7 @@ describe "tgHome", -> project: '1', url: '/testing-project/tasks/1', projectName: 'fake1', + blockedProject: undefined, _name: 'tasks' }] issues: [{ @@ -144,6 +146,7 @@ describe "tgHome", -> project: '1', url: '/testing-project/issues/1', projectName: 'fake1', + blockedProject: undefined, _name: 'issues' }] } @@ -154,6 +157,7 @@ describe "tgHome", -> project: '1', url: '/testing-project/us/1', projectName: 'fake1', + blockedProject: undefined, _name: 'userstories' }] tasks: [{ @@ -162,6 +166,7 @@ describe "tgHome", -> project: '1', url: '/testing-project/tasks/1', projectName: 'fake1', + blockedProject: undefined, _name: 'tasks' }] issues: [{ @@ -170,6 +175,7 @@ describe "tgHome", -> project: '1', url: '/testing-project/issues/1', projectName: 'fake1', + blockedProject: undefined, _name: 'issues' }] } diff --git a/app/modules/home/projects/home-project-list.jade b/app/modules/home/projects/home-project-list.jade index 15d2775e..7bb4820a 100644 --- a/app/modules/home/projects/home-project-list.jade +++ b/app/modules/home/projects/home-project-list.jade @@ -1,6 +1,10 @@ section.home-project-list(ng-if="vm.projects.size") - .home-project(tg-bind-scope, tg-repeat="project in vm.projects") + .home-project( + tg-bind-scope + tg-repeat="project in vm.projects" + ng-class="{'blocked-project': project.get('blocked_code')}" + ) .tags-container .project-tag( style="background: {{tag.get('color')}}" @@ -19,16 +23,18 @@ section.home-project-list(ng-if="vm.projects.size") alt="{{::project.get('name')}}" ) h2.project-card-name - a( + a.project-title( href="#" tg-nav="project:project=project.get('slug')" title="{{::project.get('name')}}" ) {{::project.get('name')}} - span.look-for-people( - ng-if="project.get('is_looking_for_people')" - title="{{ ::project.get('looking_for_people_note') }}" - ) - include ../../../svg/recruit.svg + svg.look-for-people.icon.icon-recruit(ng-if="project.get('is_looking_for_people')") + use(xlink:href="#icon-recruit") + title="{{ ::project.get('looking_for_people_note') }}" + svg.icon.icon-blocked-project(ng-if="project.get('blocked_code')") + use(xlink:href="#icon-blocked-project") + title(translate="PROJECT.BLOCKED_PROJECT.BLOCKED") + p.project-card-description {{::project.get('description')| limitTo:100 }} span(ng-if="::project.get('description').length > 100") ... .project-card-statistics @@ -36,25 +42,29 @@ section.home-project-list(ng-if="vm.projects.size") ng-class="{'active': project.get('is_fan')}" title="{{ 'PROJECT.FANS_COUNTER_TITLE'|translate:{total:project.get('total_fans')||0}:'messageformat' }}" ) - include ../../../svg/like.svg + svg.icon.icon-like + use(xlink:href="#icon-like") span {{::project.get('total_fans')}} span.statistic( ng-class="{'active': project.get('is_watcher')}" title="{{ 'PROJECT.WATCHERS_COUNTER_TITLE'|translate:{total:project.get('total_watchers')||0}:'messageformat' }}" ) - include ../../../svg/eye.svg + svg.icon.icon-watch + use(xlink:href="#icon-watch") span {{::project.get('total_watchers')}} span.statistic( ng-class="{'active': project.get('i_am_member')}" title="{{ 'PROJECT.MEMBERS_COUNTER_TITLE'|translate:{total:project.get('members').size||0}:'messageformat' }}" ) - include ../../../svg/team.svg + svg.icon.icon-team + use(xlink:href="#icon-team") span.statistics-num {{ ::project.get('members').size }} span.statistic( ng-if="::project.get('is_private')" title="{{ 'PROJECT.PRIVATE' | translate }}" ) - include ../../../svg/lock.svg + svg.icon.icon-lock + use(xlink:href="#icon-lock") a.see-more-projects-btn.button-gray( href="#", @@ -65,7 +75,8 @@ section.home-project-list(ng-if="vm.projects.size") ) section.projects-empty(ng-if="vm.projects != undefined && vm.projects.size === 0") - include ../../../svg/empty-project.svg + svg.icon.icon-project + use(xlink:href="#icon-project") p(translate="HOME.EMPTY_PROJECT_LIST") a.create-project-button.button-green(href="#", ng-click="vm.newProject()", title="{{'PROJECT.NAVIGATION.TITLE_CREATE_PROJECT' | translate}}", diff --git a/app/modules/home/projects/home-project-list.scss b/app/modules/home/projects/home-project-list.scss index c73826b0..e5dd7028 100644 --- a/app/modules/home/projects/home-project-list.scss +++ b/app/modules/home/projects/home-project-list.scss @@ -4,23 +4,36 @@ @include project-card; cursor: pointer; margin-bottom: 1rem; - transition: .2s; - transition-delay: .1s; + transition: all .2s; &:hover { - border: 1px solid $primary-light; + border: 1px solid rgba($primary-light, .2); + box-shadow: 0 0 5px $whitish; + } + &.blocked-project { + border: $whitish; + &:hover { + border: $whitish; + box-shadow: none; + } + .tags-container, + .project-card-logo, + .project-card-name a, + .icon-recruit, + .project-card-description, + .project-card-statistics { + opacity: .3; + } } } .projects-empty { text-align: center; svg { + fill: $whitish; height: 100px; margin: 1rem auto; text-align: center; width: 100%; - path { - fill: $whitish; - } } p { @extend %small; diff --git a/app/modules/home/working-on/working-on.jade b/app/modules/home/working-on/working-on.jade index 62e3d755..6b301ba8 100644 --- a/app/modules/home/working-on/working-on.jade +++ b/app/modules/home/working-on/working-on.jade @@ -20,7 +20,11 @@ section.watching-container .title-bar.watching-title(translate="HOME.WATCHING_SECTION") .watching(ng-if="vm.watching.size") - .duty-single(tg-duty="duty", tg-repeat="duty in vm.watching", ng-class="{'blocked': duty.is_blocked}") + .duty-single( + tg-duty="duty" + tg-repeat="duty in vm.watching" + ng-class="{'blocked': duty.is_blocked}" + ) .watching-empty(ng-if="vm.watching != undefined && vm.watching.size === 0") p(translate="HOME.EMPTY_WATCHING") diff --git a/app/modules/navigation-bar/dropdown-organization-list/dropdown-organization-list.jade b/app/modules/navigation-bar/dropdown-organization-list/dropdown-organization-list.jade deleted file mode 100644 index e0b23904..00000000 --- a/app/modules/navigation-bar/dropdown-organization-list/dropdown-organization-list.jade +++ /dev/null @@ -1,10 +0,0 @@ -#TODO: fill correctly when implemented -a(href="#", title="Organizations") - include ../../../svg/organizations.svg - -div.navbar-dropdown.dropdown-organization-list - ul - - for (var x = 0; x < 4; x++) - li - a(href="#", title="{{ project.title }}") Organization 1 - a.create-organization-btn.button-green(href="#", title="Create Organization") Create Organization 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 13b7097a..10374374 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 @@ -1,10 +1,19 @@ a(href="", title="Projects", tg-nav="projects") - include ../../../svg/projects.svg + svg.icon.icon-project + use(xlink:href="#icon-project") div.navbar-dropdown.dropdown-project-list ul li(tg-repeat="project in vm.projects track by project.get('id')") - a(href="#", tg-nav="project:project=project.get('slug')") {{::project.get("name")}} + a( + href="#" + tg-nav="project:project=project.get('slug')" + ng-class="{'blocked-project': project.get('blocked_code')}" + ) + span {{::project.get("name")}} + svg.icon.icon-blocked-project(ng-if="project.get('blocked_code')") + use(xlink:href="#icon-blocked-project") + title(translate="PROJECT.BLOCKED_PROJECT.BLOCKED") a.see-more-projects-btn.button-gray( href="#", @@ -20,6 +29,10 @@ div.navbar-dropdown.dropdown-project-list 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}}") - span.icon.icon-upload - input.import-file.hidden(type="file") + a.button-blackish.import-project-button( + href="" + title="{{'PROJECT.NAVIGATION.TITLE_IMPORT_PROJECT' | translate}}" + ) + svg.icon.icon-upload + use(xlink:href="#icon-upload") + input.import-file.hidden(type="file") \ No newline at end of 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 ac09365c..6602996e 100644 --- a/app/modules/navigation-bar/dropdown-user/dropdown-user.directive.coffee +++ b/app/modules/navigation-bar/dropdown-user/dropdown-user.directive.coffee @@ -18,7 +18,7 @@ ### DropdownUserDirective = (authService, configService, locationService, - navUrlsService, feedbackService) -> + navUrlsService, feedbackService, $rootScope) -> link = (scope, el, attrs, ctrl) -> scope.vm = {} @@ -33,6 +33,8 @@ DropdownUserDirective = (authService, configService, locationService, scope.vm.sendFeedback = -> feedbackService.sendFeedback() + scope.vm.userSettingsPlugins = _.filter($rootScope.userSettingsPlugins, {userMenu: true}) + directive = { templateUrl: "navigation-bar/dropdown-user/dropdown-user.html" scope: {} @@ -46,7 +48,8 @@ DropdownUserDirective.$inject = [ "$tgConfig", "$tgLocation", "$tgNavUrls", - "tgFeedbackService" + "tgFeedbackService", + "$rootScope" ] angular.module("taigaNavigationBar").directive("tgDropdownUser", DropdownUserDirective) diff --git a/app/modules/navigation-bar/dropdown-user/dropdown-user.jade b/app/modules/navigation-bar/dropdown-user/dropdown-user.jade index 7d3d275e..535d20ed 100644 --- a/app/modules/navigation-bar/dropdown-user/dropdown-user.jade +++ b/app/modules/navigation-bar/dropdown-user/dropdown-user.jade @@ -22,6 +22,16 @@ div.navbar-dropdown.dropdown-user tg-nav="user-settings-user-profile", title="{{'PROJECT.NAVIGATION.EDIT_PROFILE_TITLE' | translate}}", translate="PROJECT.NAVIGATION.EDIT_PROFILE") + + li.plugin(ng-repeat="plugin in vm.userSettingsPlugins") + a( + href="" + tg-nav="user-settings-contrib:plugin=plugin.slug" + ng-class="{active: plugin.slug == currentPlugin.slug}" + ) + span.title {{ plugin.name }} + span.new(translate="PROJECT.NAVIGATION.NEW_ITEM") + li a( href="#", diff --git a/app/modules/navigation-bar/navigation-bar.directive.spec.coffee b/app/modules/navigation-bar/navigation-bar.directive.spec.coffee index 36041e2f..1e746290 100644 --- a/app/modules/navigation-bar/navigation-bar.directive.spec.coffee +++ b/app/modules/navigation-bar/navigation-bar.directive.spec.coffee @@ -49,6 +49,13 @@ describe "navigationBarDirective", () -> provide.value "$tgLocation", mocks.locationService + _mocksConfig = () -> + mocks.config = Immutable.fromJS({ + publicRegisterEnabled: true + }) + + provide.value "$tgConfig", mocks.config + _mockTgNavUrls = () -> mocks.navUrls = { resolve: sinon.stub() @@ -76,6 +83,8 @@ describe "navigationBarDirective", () -> _mockTranslateFilter() _mockTgDropdownProjectListDirective() _mockTgDropdownUserDirective() + _mocksConfig() + return null beforeEach -> @@ -120,6 +129,7 @@ describe "navigationBarDirective", () -> expect(mocks.locationService.search.callCount).to.be.equal(1) expect(mocks.locationService.url.calledWith("/login")).to.be.true expect(mocks.locationService.search.calledWith({next: encodeURIComponent(nextUrl)})).to.be.true + expect(vm.publicRegisterEnabled).to.be.true it "navigation bar register", () -> mocks.navUrls.resolve.withArgs("register").returns("/register") @@ -135,3 +145,4 @@ describe "navigationBarDirective", () -> expect(mocks.locationService.search.callCount).to.be.equal(1) expect(mocks.locationService.url.calledWith("/register")).to.be.true expect(mocks.locationService.search.calledWith({next: encodeURIComponent(nextUrl)})).to.be.true + expect(vm.publicRegisterEnabled).to.be.true diff --git a/app/modules/navigation-bar/navigation-bar.jade b/app/modules/navigation-bar/navigation-bar.jade index 0c05e416..e81794cc 100644 --- a/app/modules/navigation-bar/navigation-bar.jade +++ b/app/modules/navigation-bar/navigation-bar.jade @@ -34,14 +34,16 @@ nav.navbar(ng-if="vm.isEnabledHeader") ng-class="{active: vm.active}", title="{{'PROJECT.NAVIGATION.DASHBOARD_TITLE' | translate}}") - include ../../svg/dashboard.svg + svg.icon.icon-dashboard + use(xlink:href="#icon-dashboard") a( href="#", tg-nav="discover", title="{{'PROJECT.NAVIGATION.DISCOVER_TITLE' | translate}}", ) - include ../../svg/discover.svg + svg.icon.icon-discover + use(xlink:href="#icon-discover") div.topnav-dropdown-wrapper(ng-show="vm.projects.size", tg-dropdown-project-list) //- div.topnav-dropdown-wrapper(tg-dropdown-organization-list) diff --git a/app/modules/navigation-bar/navigation-bar.scss b/app/modules/navigation-bar/navigation-bar.scss index 440784c0..5d0796a2 100644 --- a/app/modules/navigation-bar/navigation-bar.scss +++ b/app/modules/navigation-bar/navigation-bar.scss @@ -52,13 +52,14 @@ $dropdown-width: 350px; color: $white; display: inline-block; transition: all .2s linear; - svg path { - fill: darken($primary-dark, 8%); + svg { + fill: rgba($primary-dark, .8); + transition: all .2s linear; } &:hover { background: rgba($black, .2); color: $primary-light; - svg path { + svg { fill: $white; } @@ -84,10 +85,6 @@ $dropdown-width: 350px; max-height: 1.2rem; max-width: 1.2rem; width: 1.2rem; - path { - fill: $top-icon-color; - transition: all .2s; - } } .topnav-dropdown-wrapper { position: relative; @@ -132,6 +129,20 @@ $dropdown-width: 350px; margin-bottom: .5rem; padding: 0; } + .plugin { + &:hover { + .new { + color: $white; + } + } + .new { + @extend %small; + background: $red-light; + float: right; + margin-left: auto; + padding: .1rem .25rem; + } + } a { color: $gray-light; display: block; @@ -152,14 +163,30 @@ $dropdown-width: 350px; &.see-more-projects-btn { margin-bottom: .3rem; } + &.import-project-button { + padding: .8rem 1rem; + } &.create-project-btn { flex: 1; } - &.import-project-button { - padding-left: .75rem; - padding-right: .75rem; + &.blocked-project { + color: $gray; + svg { + margin-left: .5rem; + position: relative; + top: .25rem; + } + } + } + .import-project-button { + &:hover { + svg { + fill: $primary-light; + } + } + svg { + fill: $white; } - } .create-options { display: flex; diff --git a/app/modules/profile/profile-bar/profile-bar.jade b/app/modules/profile/profile-bar/profile-bar.jade index 3c16c794..8a53a4ad 100644 --- a/app/modules/profile/profile-bar/profile-bar.jade +++ b/app/modules/profile/profile-bar/profile-bar.jade @@ -2,19 +2,10 @@ section.profile-bar div.profile-image-wrapper(ng-class="::{'is-current-user': vm.isCurrentUser}") img.profile-img(ng-src="{{::vm.user.get('big_photo')}}", alt="{{::vm.user.get('full_name')}}") a.profile-edition(title="{{ 'USER.PROFILE.EDIT' | translate }}", tg-nav="user-settings-user-profile", translate="USER.PROFILE.EDIT") - // a.button-green - // span(translate="USER.PROFILE.FOLLOW") div.profile-data h1(ng-class="{'not-full-name': !vm.user.get('full_name')}") {{::vm.user.get("full_name_display")}} .username @{{::vm.user.get("username")}} h2 {{::vm.stats.get('roles').join(", ")}} - // div.location - // include ../../../svg/location.svg - // span Madrid - // Remove Abuse Flag when a user is seeing itself - // a.flag(href="", title="{{ 'USER.PROFILE.REPORT' | translate }}") - // include ../../../svg/flag.svg - // These values in profile stats are not defined yet in UX. Please ask div.profile-stats div.stat span.stat-number {{::vm.stats.get('total_num_projects')}} @@ -25,14 +16,6 @@ section.profile-bar div.stat span.stat-number {{::vm.stats.get('total_num_contacts')}} span.stat-name(translate="USER.PROFILE.CONTACTS") - // TODO Hide until organizations come - // div.profile-organizations - // h3 Organizations - // div.profile-organizations-wrapper - // div.organization - // div.organization - // div.organization - // div.organization div.profile-quote(ng-if="::vm.user.get('bio')") span {{::vm.user.get("bio") | limitTo:210 }}{{vm.user.get("bio").length < 210 ? '' : '...'}} diff --git a/app/modules/profile/profile-contacts/profile-contacts.jade b/app/modules/profile/profile-contacts/profile-contacts.jade index 08ffe638..b752325e 100644 --- a/app/modules/profile/profile-contacts/profile-contacts.jade +++ b/app/modules/profile/profile-contacts/profile-contacts.jade @@ -4,7 +4,8 @@ section.profile-contacts img(src="/#{v}/svg/spinner-circle.svg", alt="Loading...") div.empty-tab(ng-if="vm.contacts && !vm.contacts.size") - include ../../../svg/hide.svg + svg.icon.icon-unwatch + use(xlink:href="#icon-unwatch") div(ng-if="!vm.isCurrentUser") p(translate="USER.PROFILE.CONTACTS_EMPTY", translate-values="{username: vm.user.get('full_name_display')}") diff --git a/app/modules/profile/profile-favs/items/project.jade b/app/modules/profile/profile-favs/items/project.jade index 3b7a3913..7e4521be 100644 --- a/app/modules/profile/profile-favs/items/project.jade +++ b/app/modules/profile/profile-favs/items/project.jade @@ -1,7 +1,6 @@ -.list-itemtype-project +.list-itemtype-project(ng-class="{'blocked-project': vm.item.get('project_blocked_code')}") .list-itemtype-project-left .list-itemtype-project-data-wrapper - a.list-itemtype-project-image( href="#" tg-nav="project:project=vm.item.get('slug')" @@ -14,34 +13,32 @@ .list-itemtype-project-data h2 - a( + a.list-itemtype-project-name( href="#" tg-nav="project:project=vm.item.get('slug')" title="{{ ::vm.item.get('name') }}" ) {{ ::vm.item.get('name') }} - span.private(ng-if="::project.get('is_private')", title="{{'PROJECT.PRIVATE' | translate}}") - p {{ ::vm.item.get('description') }} - - .list-itemtype-project-tags.tags-container(ng-if="::vm.item.get('tags_colors').size") - span.tag( - tg-repeat="tag in ::vm.item.get('tags_colors')" - style='border-left: 5px solid {{ ::tag.get("color") }};' - ) - span.tag-name {{ ::tag.get('name') }} + svg.icon.icon-lock.private(ng-if="::vm.item.get('project_is_private')") + use(xlink:href="#icon-lock") + title {{'PROJECT.PRIVATE' | translate}}" + svg.icon.icon-blocked-project(ng-if="vm.item.get('project_blocked_code')") + use(xlink:href="#icon-blocked-project") + title(translate="PROJECT.BLOCKED_PROJECT.BLOCKED") + p.list-itemtype-project-description {{ ::vm.item.get('description') }} .list-itemtype-track span.list-itemtype-track-likers( ng-class="{'active': vm.item.get('is_fan')}" title="{{ 'PROJECT.LIKE_BUTTON.COUNTER_TITLE'|translate:{total:vm.item.get(\"total_fans\")||0}:'messageformat' }}" ) - span.icon - include ../../../../svg/like.svg + svg.icon.icon-like + use(xlink:href="#icon-like") span {{ ::vm.item.get('total_fans') }} span.list-itemtype-track-watchers( ng-class="{'active': vm.item.get('is_watcher')}" title="{{ 'PROJECT.WATCH_BUTTON.COUNTER_TITLE'|translate:{total:vm.item.get(\"total_watchers\")||0}:'messageformat' }}" ) - span.icon - include ../../../../svg/watch.svg + svg.icon.icon-watch + use(xlink:href="#icon-watch") span {{ ::vm.item.get('total_watchers') }} diff --git a/app/modules/profile/profile-favs/items/ticket.jade b/app/modules/profile/profile-favs/items/ticket.jade index a55ec8d0..599fd041 100644 --- a/app/modules/profile/profile-favs/items/ticket.jade +++ b/app/modules/profile/profile-favs/items/ticket.jade @@ -1,4 +1,4 @@ -div.list-itemtype-ticket +div.list-itemtype-ticket(ng-class="{'blocked-project': vm.item.get('project_blocked_code')}") a.list-itemtype-avatar( href="" ng-if="::vm.item.get('assigned_to')" @@ -38,6 +38,9 @@ div.list-itemtype-ticket ) span.ticket-status(ng-style="::{'color': vm.item.get('status_color')}") | {{:: vm.item.get('status') }} + svg.icon.icon-blocked-project(ng-if="vm.item.get('project_blocked_code')") + use(xlink:href="#icon-blocked-project") + title(translate="PROJECT.BLOCKED_PROJECT.BLOCKED") h2 span.ticket-id(tg-bo-ref="vm.item.get('ref')") a.ticket-title( @@ -45,36 +48,33 @@ div.list-itemtype-ticket ng-if="::vm.item.get('type') === 'userstory'" tg-nav="project-userstories-detail:project=vm.item.get('project_slug'),ref=vm.item.get('ref')" title="#{{ ::vm.item.get('ref') }} {{ ::vm.item.get('subject') }}" - ) - | {{ ::vm.item.get('subject') }} + ) {{ ::vm.item.get('subject') }} a.ticket-title( href="#" ng-if="::vm.item.get('type') === 'task'" tg-nav="project-tasks-detail:project=vm.item.get('project_slug'),ref=vm.item.get('ref')" title="#{{ ::vm.item.get('ref') }} {{ ::vm.item.get('subject') }}" - ) - | {{ ::vm.item.get('subject') }} + ) {{ ::vm.item.get('subject') }} a.ticket-title( href="#" ng-if="::vm.item.get('type') === 'issue'" tg-nav="project-issues-detail:project=vm.item.get('project_slug'),ref=vm.item.get('ref')" title="#{{ ::vm.item.get('ref') }} {{ ::vm.item.get('subject') }}" - ) - | {{ ::vm.item.get('subject') }} + ) {{ ::vm.item.get('subject') }} div.list-itemtype-track span.list-itemtype-track-likers( ng-class="{'active': vm.item.get('is_voter')}", title="{{ 'COMMON.VOTE_BUTTON.COUNTER_TITLE'|translate:{total:vm.item.get(\"total_voters\")||0}:'messageformat' }}" ) - span.icon - include ../../../../svg/upvote.svg + svg.icon.icon-upvote + use(xlink:href="#icon-upvote") span {{ ::vm.item.get('total_voters') }} span.list-itemtype-track-watchers( ng-class="{'active': vm.item.get('is_watcher')}" title="{{ 'COMMON.WATCH_BUTTON.COUNTER_TITLE'|translate:{total:vm.item.get(\"total_watchers\")||0}:'messageformat' }}" ) - span.icon - include ../../../../svg/watch.svg + svg.icon.icon-watch + use(xlink:href="#icon-watch") span {{ ::vm.item.get('total_watchers') }} diff --git a/app/modules/profile/profile-favs/profile-favs.controller.coffee b/app/modules/profile/profile-favs/profile-favs.controller.coffee index 2022ee4a..5bd5917d 100644 --- a/app/modules/profile/profile-favs/profile-favs.controller.coffee +++ b/app/modules/profile/profile-favs/profile-favs.controller.coffee @@ -184,4 +184,3 @@ class ProfileWatchedController extends FavsBaseController angular.module("taigaProfile") .controller("ProfileWatched", ProfileWatchedController) - diff --git a/app/modules/profile/profile-favs/profile-favs.jade b/app/modules/profile/profile-favs/profile-favs.jade index 3b1ece60..9ec621c7 100644 --- a/app/modules/profile/profile-favs/profile-favs.jade +++ b/app/modules/profile/profile-favs/profile-favs.jade @@ -1,7 +1,8 @@ section.profile-favs div.profile-filter div.searchbox(ng-if="::vm.enableFilterByTextQuery") - span.icon-search + svg.icon.icon-search + use(xlink:href="#icon-search") input( type="text" ng-model="vm.q" @@ -59,10 +60,26 @@ section.profile-favs tg-repeat="item in vm.items track by $index" ng-switch="item.get('type')" ) - div(ng-switch-when="project", tg-fav-item="item", item-type="project") - div(ng-switch-when="userstory", tg-fav-item="item", item-type="userstory") - div(ng-switch-when="task", tg-fav-item="item", item-type="task") - div(ng-switch-when="issue", tg-fav-item="item", item-type="issue") + div( + ng-switch-when="project" + tg-fav-item="item" + item-type="project" + ) + div( + ng-switch-when="userstory" + tg-fav-item="item" + item-type="userstory" + ) + div( + ng-switch-when="task" + tg-fav-item="item" + item-type="task" + ) + div( + ng-switch-when="issue" + tg-fav-item="item" + item-type="issue" + ) div(ng-if="vm.isLoading") div.spin diff --git a/app/modules/profile/profile-favs/profile-favs.scss b/app/modules/profile/profile-favs/profile-favs.scss index e37d4542..dce9d08c 100644 --- a/app/modules/profile/profile-favs/profile-favs.scss +++ b/app/modules/profile/profile-favs/profile-favs.scss @@ -14,7 +14,7 @@ display: flex; flex: 1; .icon-search { - color: grayer; + fill: $gray; margin-right: .5rem; } input { diff --git a/app/modules/profile/profile-hints/profile-hints.jade b/app/modules/profile/profile-hints/profile-hints.jade index fceb5fd9..364a9066 100644 --- a/app/modules/profile/profile-hints/profile-hints.jade +++ b/app/modules/profile/profile-hints/profile-hints.jade @@ -1,5 +1,6 @@ h4 - span.icon.icon-help + svg.icon.icon-question + use(xlink:href="#icon-question") span(translate="HINTS.SECTION_NAME") p {{::vm.hint.title}} diff --git a/app/modules/profile/profile-projects/profile-projects.jade b/app/modules/profile/profile-projects/profile-projects.jade index 30861ed5..5e3ff52d 100644 --- a/app/modules/profile/profile-projects/profile-projects.jade +++ b/app/modules/profile/profile-projects/profile-projects.jade @@ -4,14 +4,17 @@ section.profile-projects img(src="/#{v}/svg/spinner-circle.svg", alt="Loading...") .empty-tab(ng-if="vm.projects && !vm.projects.size") - include ../../../svg/hide.svg + svg.icon.icon-unwatch + use(xlink:href="#icon-unwatch") p( translate="USER.PROFILE.PROJECTS_EMPTY" translate-values="{username: vm.user.get('full_name_display')}" ) - - .list-itemtype-project(tg-repeat="project in vm.projects") + .list-itemtype-project( + tg-repeat="project in vm.projects" + ng-class="{'blocked-project': project.get('blocked_code')}" + ) .list-itemtype-project-left .project-list-single-title-wrapper a.list-itemtype-project-image( @@ -25,19 +28,15 @@ section.profile-projects ) .project-list-single-title h2 - a( + a.project-title( href="#" tg-nav="project:project=project.get('slug')" title="{{ ::project.get('name') }}" ) {{::project.get('name')}} - p {{ ::project.get('description') | limitTo:300 }} - - .list-itemtype-project-tags.tags-container(ng-if="::project.get('tags').size") - span.tag( - style='border-left: 5px solid {{::tag.get("color")}};' - tg-repeat="tag in ::project.get('colorized_tags')" - ) - span.tag-name {{::tag.get('name')}} + svg.icon.icon-blocked-project(ng-if="project.get('blocked_code')") + use(xlink:href="#icon-blocked-project") + title(translate="PROJECT.BLOCKED_PROJECT.BLOCKED") + p.project-description {{ ::project.get('description') | limitTo:300 }} .list-itemtype-project-right @@ -46,16 +45,16 @@ section.profile-projects ng-class="{'active': project.get('is_fan')}" title="{{ 'PROJECT.LIKE_BUTTON.COUNTER_TITLE'|translate:{total:project.get(\"total_fans\")||0}:'messageformat' }}" ) - span.icon - include ../../../svg/like.svg + svg.icon.icon-like + use(xlink:href="#icon-like") span {{ ::project.get('total_fans') }} span.list-itemtype-track-watchers( ng-class="{'active': project.get('is_watcher')}" title="{{ 'PROJECT.WATCH_BUTTON.COUNTER_TITLE'|translate:{total:project.get(\"total_watchers\")||0}:'messageformat' }}" ) - span.icon - include ../../../svg/watch.svg + svg.icon.icon-watch + use(xlink:href="#icon-watch") span {{ ::project.get('total_watchers') }} .list-itemtype-project-members diff --git a/app/modules/profile/profile-tab/profile-tab.directive.coffee b/app/modules/profile/profile-tab/profile-tab.directive.coffee index 308a97ba..252e7282 100644 --- a/app/modules/profile/profile-tab/profile-tab.directive.coffee +++ b/app/modules/profile/profile-tab/profile-tab.directive.coffee @@ -28,6 +28,7 @@ ProfileTabDirective = () -> scope.tab.title = title scope.tab.icon = attrs.tabIcon + scope.tab.iconName = '#' + attrs.tabIcon scope.tab.active = !!attrs.tabActive if scope.$eval(attrs.tabDisabled) != true diff --git a/app/modules/profile/profile-tabs/profile-tabs.jade b/app/modules/profile/profile-tabs/profile-tabs.jade index ba10af3a..c7965c2f 100644 --- a/app/modules/profile/profile-tabs/profile-tabs.jade +++ b/app/modules/profile/profile-tabs/profile-tabs.jade @@ -7,7 +7,8 @@ div ng-click="vm.toggleTab(tab)" ng-class="{active: tab.active}" ) - span.icon(ng-class="::tab.icon") + svg.icon(ng-class="::tab.icon") + use(xlink:href="{{::tab.iconName}}") span {{::tab.name}} ng-transclude diff --git a/app/modules/profile/profile.jade b/app/modules/profile/profile.jade index dc5ce3f7..3b6caf8e 100644 --- a/app/modules/profile/profile.jade +++ b/app/modules/profile/profile.jade @@ -21,21 +21,21 @@ div.profile.centered(ng-if="vm.user") div( tg-profile-tab="{{'USER.PROFILE.TABS.LIKES_TAB' | translate}}" tab-title="{{'USER.PROFILE.TABS.LIKES_TAB_TITLE' | translate}}" - tab-icon="icon-heart" + tab-icon="icon-like" ) div(tg-profile-liked, user="vm.user") div( tg-profile-tab="{{'USER.PROFILE.TABS.VOTES_TAB' | translate}}" tab-title="{{'USER.PROFILE.TABS.VOTES_TAB_TITLE' | translate}}" - tab-icon="icon-caret-up" + tab-icon="icon-upvote" ) div(tg-profile-voted, user="vm.user") div( tg-profile-tab="{{'USER.PROFILE.TABS.WATCHED_TAB' | translate}}" tab-title="{{'USER.PROFILE.TABS.WATCHED_TAB_TITLE' | translate}}" - tab-icon="icon-eye" + tab-icon="icon-watch" ) div(tg-profile-watched, user="vm.user") diff --git a/app/modules/profile/profile.scss b/app/modules/profile/profile.scss index 0dcec0dc..a2b22bb7 100644 --- a/app/modules/profile/profile.scss +++ b/app/modules/profile/profile.scss @@ -11,7 +11,6 @@ padding: 0; } .timeline-wrapper { - background: lighten($whitish, 10%); margin-right: 3.5rem; width: 768px; > div { @@ -50,12 +49,16 @@ padding: 5vh; text-align: center; svg { + fill: $whitish; + height: 10rem; margin: 2rem auto; - max-width: 160px; text-align: center; + width: 10rem; } p { + color: $gray-light; font-size: .9rem; + margin: 0; } } } diff --git a/app/modules/profile/styles/profile-content-tabs.scss b/app/modules/profile/styles/profile-content-tabs.scss index 6b5340be..b63ec85e 100644 --- a/app/modules/profile/styles/profile-content-tabs.scss +++ b/app/modules/profile/styles/profile-content-tabs.scss @@ -7,8 +7,11 @@ padding: 1rem; &:hover, &.active { - color: $grayer; + color: $gray; transition: color .2s linear; + .icon { + fill: $primary-light; + } } &.active { background: $white; @@ -19,11 +22,13 @@ transition: color .2s linear; .icon { color: $primary; - transition: color .2s linear; } } } .icon { - margin-right: .4rem; + fill: $gray-light; + height: .8rem; + margin-right: .5rem; + transition: fill .2s linear; } } diff --git a/app/modules/profile/styles/profile-sidebar.scss b/app/modules/profile/styles/profile-sidebar.scss index 944c813c..964b3322 100644 --- a/app/modules/profile/styles/profile-sidebar.scss +++ b/app/modules/profile/styles/profile-sidebar.scss @@ -6,9 +6,10 @@ margin-bottom: .5rem; padding: .5rem; .icon { - color: $gray-light; + fill: $gray-light; margin-right: .3rem; - vertical-align: text-bottom; + margin-top: -3px; + vertical-align: middle; } } p { diff --git a/app/modules/projects/components/blocked-project-explanation.directive.coffee b/app/modules/projects/components/blocked-project-explanation.directive.coffee new file mode 100644 index 00000000..fac3ed91 --- /dev/null +++ b/app/modules/projects/components/blocked-project-explanation.directive.coffee @@ -0,0 +1,25 @@ +### +# Copyright (C) 2014-2016 Taiga Agile LLC +# +# 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: blocked-project-explanation.directive.coffee +### + +BlockedProjectExplanationDirective = () -> + return { + templateUrl: "projects/project/blocked-project-explanation.html" + } + +angular.module("taigaProjects").directive("tgBlockedProjectExplanation", BlockedProjectExplanationDirective) 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 7faad550..176c25fd 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 @@ -8,7 +8,8 @@ a.track-button.like-button.like-container( ) span.track-inner span.track-icon - include ../../../../svg/like.svg + svg.icon.icon-like + use(xlink:href="#icon-like") span( ng-if="!vm.project.get('is_fan')" translate="PROJECT.LIKE_BUTTON.LIKE" 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 508922fd..1c2671a5 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 @@ -6,10 +6,12 @@ a.track-button.watch-button.watch-container( ) span.track-inner span.track-icon - include ../../../../svg/watch.svg + svg.icon.icon-watch + use(xlink:href="#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.icon.icon-arrow-up + svg.icon.icon-arrow-down + use(xlink:href="#icon-arrow-down") span.track-button-counter( title="{{ 'PROJECT.WATCH_BUTTON.COUNTER_TITLE'|translate:{total:vm.project.get(\"total_watchers\")||0}:'messageformat' }}", @@ -35,7 +37,8 @@ ul.watch-options( ) span(translate="PROJECT.WATCH_BUTTON.OPTIONS.NOTIFY_ALL") span.watch-check(ng-if="vm.project.get('is_watcher') && vm.project.get('notify_level') == 2") - include ../../../../svg/check.svg + svg.icon.icon-check-empty + use(xlink:href="#icon-check-empty") li a( href="", @@ -45,7 +48,8 @@ ul.watch-options( ) span(translate="PROJECT.WATCH_BUTTON.OPTIONS.NOTIFY_INVOLVED") span.watch-check(ng-if="vm.project.get('is_watcher') && vm.project.get('notify_level') == 1") - include ../../../../svg/check.svg + svg.icon.icon-check-empty + use(xlink:href="#icon-check-empty") li(ng-if="vm.project.get('is_watcher')") a( diff --git a/app/modules/projects/listing/projects-listing.jade b/app/modules/projects/listing/projects-listing.jade index 529d620f..be8ad939 100644 --- a/app/modules/projects/listing/projects-listing.jade +++ b/app/modules/projects/listing/projects-listing.jade @@ -13,7 +13,8 @@ href="" title="{{'PROJECT.NAVIGATION.TITLE_IMPORT_PROJECT' | translate}}" ) - span.icon.icon-upload + svg.icon.icon-upload + use(xlink:href="#icon-upload") input.import-file.hidden(type="file") section.project-list-section @@ -22,6 +23,7 @@ li.list-itemtype-project( tg-bind-scope tg-repeat="project in vm.projects track by project.get('id')" + ng-class="{'blocked-project': project.get('blocked_code')}" ) .list-itemtype-project-left @@ -37,27 +39,28 @@ ) .list-itemtype-project-data h2 - a( + a.project-title( href="#" tg-nav="project:project=project.get('slug')" title="{{ ::project.get('name') }}" ) {{project.get('name')}} - span.private( - ng-if="project.get('is_private')" - title="{{'PROJECT.PRIVATE' | translate}}" - ) - include ../../../svg/lock.svg - p {{ ::project.get('description') | limitTo:300 }} + svg.icon.icon-lock.private(ng-if="project.get('is_private')") + use(xlink:href="#icon-lock") + title {{'PROJECT.PRIVATE' | translate}}" + + svg.icon.icon-badge(ng-if="project.get('i_am_owner')") + use(xlink:href="#icon-badge") + title(translate="COMMON.OWNER") + svg.icon.icon-blocked-project(ng-if="project.get('blocked_code')") + use(xlink:href="#icon-blocked-project") + title(translate="PROJECT.BLOCKED_PROJECT.BLOCKED") + + + p.project-description {{ ::project.get('description') | limitTo:300 }} span(ng-if="::project.get('description').length > 300") ... - .list-itemtype-project-tags.tag-container(ng-if="::project.get('tags').size") - span.tag( - style='border-left: 5px solid {{::tag.get("color")}};' - tg-repeat="tag in ::project.get('colorized_tags')" - ) - span.tag-name {{::tag.get('name')}} - - span.drag.icon.icon-drag-v + svg.drag.icon.icon-drag + use(xlink:href="#icon-drag") aside.help-area p(translate="PROJECT.HELP") diff --git a/app/modules/projects/listing/styles/profile-projects.scss b/app/modules/projects/listing/styles/profile-projects.scss index e068e7c7..2a2a6041 100644 --- a/app/modules/projects/listing/styles/profile-projects.scss +++ b/app/modules/projects/listing/styles/profile-projects.scss @@ -3,7 +3,16 @@ .list-itemtype-project { display: flex; justify-content: space-between; - min-height: 10rem; + min-height: 9rem; + padding: .75rem; + &.blocked-project { + .list-itemtype-project-image, + .project-title, + .project-description, + .list-itemtype-project-right { + opacity: .4; + } + } .project-list-single-title-wrapper { display: flex; } @@ -14,7 +23,11 @@ display: flex; flex-direction: column; flex-shrink: 0; + justify-content: space-between; width: 200px; } + .icon-blocked-project { + @include svg-size(); + } } } diff --git a/app/modules/projects/listing/styles/project-list.scss b/app/modules/projects/listing/styles/project-list.scss index b9f68b93..d22945ad 100644 --- a/app/modules/projects/listing/styles/project-list.scss +++ b/app/modules/projects/listing/styles/project-list.scss @@ -13,20 +13,29 @@ margin: 0; } } - .create-options a { - &.create-project-btn { - margin-right: .25rem; - padding: .6rem 2.5rem; - } - &.import-project-button { - padding: .53rem .8rem; - &:hover { - background: $grayer; - } + .icon-lock, + .icon-badge, + .icon-blocked-project { + @include svg-size(); + } + .icon-badge { + margin-left: .5rem; + } + .create-project-btn { + margin-right: .25rem; + padding: .6rem 2.5rem; + } + .import-project-button { + padding: .53rem .8rem; + &:hover { .icon-upload { - margin: 0; + fill: $primary-light; } } + .icon-upload { + fill: $white; + } + } .project-list-section { display: flex; @@ -47,13 +56,27 @@ .list-itemtype-project { background: rgba($white, .6); &:hover { - background: lighten($primary, 63%); + background: rgba($primary-light, .1); cursor: move; transition: background .3s; .drag { opacity: 1; } } + &.blocked-project { + .list-itemtype-project-image, + .project-title, + .private, + .project-description, + .icon-badge { + opacity: .25; + } + } + &.blocked-project:hover { + .icon-drag { + opacity: 1; + } + } .list-itemtype-project-data-wrapper { display: flex; } @@ -63,10 +86,12 @@ } } .drag { - @extend %large; align-self: center; - color: $gray-light; + fill: $gray-light; + height: 1.1rem; + margin-right: .5rem; opacity: 0; transition: opacity .2s; + width: 1.1rem; } } diff --git a/app/modules/projects/project/blocked-project-explanation.jade b/app/modules/projects/project/blocked-project-explanation.jade new file mode 100644 index 00000000..0ce3441b --- /dev/null +++ b/app/modules/projects/project/blocked-project-explanation.jade @@ -0,0 +1,5 @@ +div(ng-if="!vm.project.get('i_am_owner')") + div {{'PROJECT.BLOCKED_PROJECT.THIS_PROJECT_IS_BLOCKED' | translate}} + +div(ng-if="vm.project.get('i_am_owner')") + div {{'PROJECT.BLOCKED_PROJECT.TO_UNBLOCK_CONTACT_THE_ADMIN_STAFF' | translate}} diff --git a/app/modules/projects/project/blocked-project.jade b/app/modules/projects/project/blocked-project.jade new file mode 100644 index 00000000..be6b75b8 --- /dev/null +++ b/app/modules/projects/project/blocked-project.jade @@ -0,0 +1,15 @@ +.blocked-project-detail + .blocked-project-inner + .blocked-project-title + .project-image + img( + tg-project-logo-small-src="vm.project" + alt="{{::vm.project.get('name')}}" + ) + svg.icon.icon-blocked-project + use(xlink:href="#icon-blocked-project") + title(translate="PROJECT.BLOCKED_PROJECT.BLOCKED") + span.project-title {{::vm.project.get("name")}} + .blocked-project-message + h1.project-block-title {{'PROJECT.BLOCKED_PROJECT.BLOCKED' | translate}} + tg-blocked-project-explanation.project-block-message diff --git a/app/modules/projects/project/blocked-project.scss b/app/modules/projects/project/blocked-project.scss new file mode 100644 index 00000000..c53b7d04 --- /dev/null +++ b/app/modules/projects/project/blocked-project.scss @@ -0,0 +1,45 @@ +.blocked-project-detail { + align-items: center; + background: url('../images/discover.png') bottom center repeat-x; + display: flex; + height: calc(100vh - 40px); + justify-content: center; + min-height: calc(100vh - 40px); + min-width: 100vw; + width: 100vw; +} + +.blocked-project-inner { + width: 330px; +} + +.blocked-project-title { + align-items: center; + display: flex; + .project-image { + flex-basis: 6rem; + margin-right: 1rem; + max-width: 6rem; + position: relative; + } + img { + width: 100%; + } + .icon-blocked-project { + @include svg-size(1.5rem); + position: absolute; + right: -.5rem; + top: -.5rem; + } + .project-title { + @extend %larger; + } +} + +.blocked-project-message { + margin-top: 4rem; + text-align: center; + .project-block-title { + @extend %xlarge; + } +} diff --git a/app/modules/projects/project/project.jade b/app/modules/projects/project/project.jade index 6820cc8b..44c479ee 100644 --- a/app/modules/projects/project/project.jade +++ b/app/modules/projects/project/project.jade @@ -16,11 +16,10 @@ div.wrapper .intro-title h1 span.project-name {{::vm.project.get("name")}} - span.private( - ng-if="::vm.project.get('is_private')" - title="{{'PROJECT.PRIVATE' | translate}}" - ) - include ../../../svg/lock.svg + + svg.icon.icon-lock.private(ng-if="::vm.project.get('is_private')") + use(xlink:href="#icon-lock") + title {{'PROJECT.PRIVATE' | translate}}" div.track-buttons-container(ng-if="vm.user") tg-like-project-button(project="vm.project") @@ -31,15 +30,15 @@ div.wrapper span.list-itemtype-track-likers( title="{{ 'PROJECT.LIKE_BUTTON.COUNTER_TITLE'|translate:{total:vm.project.get(\"total_fans\")||0}:'messageformat' }}" ) - span.icon - include ../../../svg/like.svg + svg.icon.icon-like + use(xlink:href="#icon-like") span {{ ::vm.project.get('total_fans') }} span.list-itemtype-track-watchers( title="{{ 'PROJECT.WATCH_BUTTON.COUNTER_TITLE'|translate:{total:vm.project.get(\"total_watchers\")||0}:'messageformat' }}" ) - span.icon - include ../../../svg/watch.svg + svg.icon.icon-watche + use(xlink:href="#icon-watch") span {{ ::vm.project.get('total_watchers') }} p.description {{vm.project.get('description')}} @@ -62,7 +61,7 @@ div.wrapper 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')}}" + p(ng-if="vm.project.get('looking_for_people_note')") {{::vm.project.get('looking_for_people_note')}} h2.title {{"PROJECT.SECTION.TEAM" | translate}} ul.involved-team li(tg-repeat="member in vm.members") @@ -71,3 +70,6 @@ div.wrapper title="{{::member.get('full_name')}}" ) img(ng-src="{{::member.get('photo')}}", alt="{{::member.get('full_name')}}") + svg.icon.icon-badge(ng-if="member.get('id') == vm.project.getIn(['owner', 'id'])") + use(xlink:href="#icon-badge") + title(translate="COMMON.OWNER") diff --git a/app/modules/projects/projects.service.coffee b/app/modules/projects/projects.service.coffee index a7c2ab65..ab3973a3 100644 --- a/app/modules/projects/projects.service.coffee +++ b/app/modules/projects/projects.service.coffee @@ -57,10 +57,20 @@ class ProjectsService extends taiga.Service newProject: -> @lightboxFactory.create("tg-lb-create-project", { - "class": "wizard-create-project" + "class": "wizard-create-project lightbox" }) bulkUpdateProjectsOrder: (sortData) -> return @rs.projects.bulkUpdateOrder(sortData) + transferValidateToken: (projectId, token) -> + return @rs.projects.transferValidateToken(projectId, token) + + transferAccept: (projectId, token, reason) -> + return @rs.projects.transferAccept(projectId, token, reason) + + transferReject: (projectId, token, reason) -> + return @rs.projects.transferReject(projectId, token, reason) + + angular.module("taigaProjects").service("tgProjectsService", ProjectsService) diff --git a/app/modules/projects/projects.service.spec.coffee b/app/modules/projects/projects.service.spec.coffee index 046d1d23..1829e8a8 100644 --- a/app/modules/projects/projects.service.spec.coffee +++ b/app/modules/projects/projects.service.spec.coffee @@ -79,7 +79,7 @@ describe "tgProjectsService", -> projectsService.newProject() expect(mocks.lightboxFactory.create).to.have.been.calledWith("tg-lb-create-project", { - "class": "wizard-create-project" + "class": "wizard-create-project lightbox" }) it "bulkUpdateProjectsOrder and then fetch projects again", () -> @@ -163,3 +163,16 @@ describe "tgProjectsService", -> ]) done() + + it "validateTransferToken", (done) -> + projectId = 3 + + tokenValidation = Immutable.fromJS({}) + + mocks.resources.projects = {} + mocks.resources.projects.transferValidateToken = sinon.stub() + mocks.resources.projects.transferValidateToken.withArgs(projectId).promise().resolve(tokenValidation) + + projectsService.transferValidateToken(projectId).then (projects) -> + expect(projects.toJS()).to.be.eql({}) + done() diff --git a/app/modules/projects/transfer/cant-own-project-explanation.directive.coffee b/app/modules/projects/transfer/cant-own-project-explanation.directive.coffee new file mode 100644 index 00000000..a6ea655c --- /dev/null +++ b/app/modules/projects/transfer/cant-own-project-explanation.directive.coffee @@ -0,0 +1,25 @@ +### +# Copyright (C) 2014-2016 Taiga Agile LLC +# +# 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: cant-own-project-explanation.directive.coffee +### + +CantOwnProjectExplanationDirective = () -> + return { + templateUrl: "projects/transfer/cant-own-project-explanation.html" + } + +angular.module("taigaProjects").directive("tgCantOwnProjectExplanation", CantOwnProjectExplanationDirective) diff --git a/app/modules/projects/transfer/cant-own-project-explanation.jade b/app/modules/projects/transfer/cant-own-project-explanation.jade new file mode 100644 index 00000000..6f6be740 --- /dev/null +++ b/app/modules/projects/transfer/cant-own-project-explanation.jade @@ -0,0 +1,3 @@ +p( + translate="ADMIN.PROJECT_TRANSFER.CANT_BE_OWNED" +) diff --git a/app/modules/projects/transfer/transfer-page.jade b/app/modules/projects/transfer/transfer-page.jade new file mode 100644 index 00000000..58cc9c2e --- /dev/null +++ b/app/modules/projects/transfer/transfer-page.jade @@ -0,0 +1,4 @@ +tg-transfer-project.transfer-project( + ng-if="vm.project" + project="vm.project" +) diff --git a/app/modules/projects/transfer/transfer-project.controler.spec.coffee b/app/modules/projects/transfer/transfer-project.controler.spec.coffee new file mode 100644 index 00000000..6d6af88c --- /dev/null +++ b/app/modules/projects/transfer/transfer-project.controler.spec.coffee @@ -0,0 +1,275 @@ +### +# Copyright (C) 2014-2016 Taiga Agile LLC +# +# 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: transfer-project.controller.spec.coffee +### + +describe "TransferProject", -> + $controller = null + $q = null + provide = null + $rootScope = null + mocks = {} + + _mockRouteParams = () -> + mocks.routeParams = {} + provide.value "$routeParams", mocks.routeParams + + _mockProjectsService = () -> + mocks.projectsService = { + transferValidateToken: sinon.stub() + transferAccept: sinon.stub() + transferReject: sinon.stub() + } + + provide.value "tgProjectsService", mocks.projectsService + + _mockLocation = () -> + mocks.location = { + path: sinon.stub() + } + provide.value "$location", mocks.location + + _mockAuth = () -> + mocks.auth = { + refresh: sinon.stub() + } + + provide.value "$tgAuth", mocks.auth + + _mockCurrentUserService = () -> + mocks.currentUserService = { + getUser: sinon.stub() + canOwnProject: sinon.stub() + } + + provide.value "tgCurrentUserService", mocks.currentUserService + + _mockTgNavUrls = () -> + mocks.tgNavUrls = { + resolve: sinon.stub() + } + + provide.value "$tgNavUrls", mocks.tgNavUrls + + _mockTranslate = () -> + mocks.translate = { + instant: sinon.stub() + } + + provide.value "$translate", mocks.translate + + _mockTgConfirm = -> + mocks.tgConfirm = { + notify: sinon.stub() + } + + provide.value("$tgConfirm", mocks.tgConfirm) + + _mocks = () -> + module ($provide) -> + provide = $provide + _mockRouteParams() + _mockProjectsService() + _mockLocation() + _mockAuth() + _mockCurrentUserService() + _mockTgNavUrls() + _mockTranslate() + _mockTgConfirm() + return null + + _inject = (callback) -> + inject (_$controller_, _$q_, _$rootScope_) -> + $q = _$q_ + $rootScope = _$rootScope_ + $controller = _$controller_ + + beforeEach -> + module "taigaProjects" + _mocks() + _inject() + + it "invalid token", (done) -> + project = Immutable.fromJS({ + id: 1 + }) + + user = Immutable.fromJS({}) + + mocks.auth.refresh.promise().resolve() + mocks.routeParams.token = "BAD_TOKEN" + mocks.currentUserService.getUser.returns(user) + mocks.projectsService.transferValidateToken.withArgs(1, "BAD_TOKEN").promise().reject() + mocks.tgNavUrls.resolve.withArgs("not-found").returns("/not-found") + + ctrl = $controller("TransferProjectController") + ctrl.project = project + ctrl.initialize().then () -> + expect(mocks.location.path).to.be.calledWith("/not-found") + done() + + it "valid token private project with max projects for user", (done) -> + project = Immutable.fromJS({ + id: 1 + is_private: true + }) + + user = Immutable.fromJS({ + max_private_projects: 1 + total_private_projects: 1 + max_memberships_private_projects: 25 + }) + + mocks.auth.refresh.promise().resolve() + mocks.routeParams.token = "TOKEN" + mocks.currentUserService.getUser.returns(user) + mocks.projectsService.transferValidateToken.withArgs(1, "TOKEN").promise().resolve() + + ctrl = $controller("TransferProjectController") + ctrl.project = project + ctrl.initialize().then () -> + expect(ctrl.ownerMessage).to.be.equal("ADMIN.PROJECT_TRANSFER.OWNER_MESSAGE.PRIVATE") + expect(ctrl.maxProjects).to.be.equal(1) + expect(ctrl.currentProjects).to.be.equal(1) + done() + + it "valid token private project without max projects for user", (done) -> + project = Immutable.fromJS({ + id: 1 + is_private: true + }) + + user = Immutable.fromJS({ + max_private_projects: null + total_private_projects: 1 + max_memberships_private_projects: 25 + }) + + mocks.auth.refresh.promise().resolve() + mocks.routeParams.token = "TOKEN" + mocks.currentUserService.getUser.returns(user) + mocks.projectsService.transferValidateToken.withArgs(1, "TOKEN").promise().resolve() + mocks.translate.instant.withArgs("ADMIN.PROJECT_TRANSFER.UNLIMITED_PROJECTS").returns("UNLIMITED_PROJECTS") + + ctrl = $controller("TransferProjectController") + ctrl.project = project + ctrl.initialize().then () -> + expect(ctrl.ownerMessage).to.be.equal("ADMIN.PROJECT_TRANSFER.OWNER_MESSAGE.PRIVATE") + expect(ctrl.maxProjects).to.be.equal("UNLIMITED_PROJECTS") + expect(ctrl.currentProjects).to.be.equal(1) + done() + + it "valid token public project with max projects for user", (done) -> + project = Immutable.fromJS({ + id: 1 + is_public: true + }) + + user = Immutable.fromJS({ + max_public_projects: 1 + total_public_projects: 1 + max_memberships_public_projects: 25 + }) + + mocks.auth.refresh.promise().resolve() + mocks.routeParams.token = "TOKEN" + mocks.currentUserService.getUser.returns(user) + mocks.projectsService.transferValidateToken.withArgs(1, "TOKEN").promise().resolve() + + ctrl = $controller("TransferProjectController") + ctrl.project = project + ctrl.initialize().then () -> + expect(ctrl.ownerMessage).to.be.equal("ADMIN.PROJECT_TRANSFER.OWNER_MESSAGE.PUBLIC") + expect(ctrl.maxProjects).to.be.equal(1) + expect(ctrl.currentProjects).to.be.equal(1) + done() + + it "valid token public project without max projects for user", (done) -> + project = Immutable.fromJS({ + id: 1 + is_public: true + }) + + user = Immutable.fromJS({ + max_public_projects: null + total_public_projects: 1 + max_memberships_public_projects: 25 + }) + + mocks.auth.refresh.promise().resolve() + mocks.routeParams.token = "TOKEN" + mocks.currentUserService.getUser.returns(user) + mocks.projectsService.transferValidateToken.withArgs(1, "TOKEN").promise().resolve() + mocks.translate.instant.withArgs("ADMIN.PROJECT_TRANSFER.UNLIMITED_PROJECTS").returns("UNLIMITED_PROJECTS") + + ctrl = $controller("TransferProjectController") + ctrl.project = project + ctrl.initialize().then () -> + expect(ctrl.ownerMessage).to.be.equal("ADMIN.PROJECT_TRANSFER.OWNER_MESSAGE.PUBLIC") + expect(ctrl.maxProjects).to.be.equal("UNLIMITED_PROJECTS") + expect(ctrl.currentProjects).to.be.equal(1) + done() + + it "transfer accept", (done) -> + project = Immutable.fromJS({ + id: 1 + slug: "slug" + }) + + user = Immutable.fromJS({}) + + mocks.auth.refresh.promise().resolve() + mocks.routeParams.token = "TOKEN" + mocks.currentUserService.getUser.returns(user) + mocks.projectsService.transferValidateToken.withArgs(1, "TOKEN").promise().resolve() + mocks.projectsService.transferAccept.withArgs(1, "TOKEN", "this is my reason").promise().resolve() + mocks.tgNavUrls.resolve.withArgs("project-admin-project-profile-details", {project: "slug"}).returns("/project/slug/") + mocks.translate.instant.withArgs("ADMIN.PROJECT_TRANSFER.ACCEPTED_PROJECT_OWNERNSHIP").returns("ACCEPTED_PROJECT_OWNERNSHIP") + + ctrl = $controller("TransferProjectController") + ctrl.project = project + ctrl.initialize().then () -> + ctrl.transferAccept("TOKEN", "this is my reason").then -> + expect(mocks.location.path).to.be.calledWith("/project/slug/") + expect(mocks.tgConfirm.notify).to.be.calledWith("success", "ACCEPTED_PROJECT_OWNERNSHIP", '', 5000) + + done() + + it "transfer reject", (done) -> + project = Immutable.fromJS({ + id: 1 + slug: "slug" + }) + + user = Immutable.fromJS({}) + + mocks.auth.refresh.promise().resolve() + mocks.routeParams.token = "TOKEN" + mocks.currentUserService.getUser.returns(user) + mocks.projectsService.transferValidateToken.withArgs(1, "TOKEN").promise().resolve() + mocks.projectsService.transferReject.withArgs(1, "TOKEN", "this is my reason").promise().resolve() + mocks.tgNavUrls.resolve.withArgs("project-admin-project-profile-details", {project: "slug"}).returns("/project/slug/") + mocks.translate.instant.withArgs("ADMIN.PROJECT_TRANSFER.REJECTED_PROJECT_OWNERNSHIP").returns("REJECTED_PROJECT_OWNERNSHIP") + + ctrl = $controller("TransferProjectController") + ctrl.project = project + ctrl.initialize().then () -> + ctrl.transferReject("TOKEN", "this is my reason").then -> + expect(mocks.location.path).to.be.calledWith("/project/slug/") + expect(mocks.tgConfirm.notify).to.be.calledWith("success", "REJECTED_PROJECT_OWNERNSHIP", '', 5000) + + done() diff --git a/app/modules/projects/transfer/transfer-project.controller.coffee b/app/modules/projects/transfer/transfer-project.controller.coffee new file mode 100644 index 00000000..7e9bb914 --- /dev/null +++ b/app/modules/projects/transfer/transfer-project.controller.coffee @@ -0,0 +1,104 @@ +### +# Copyright (C) 2014-2016 Taiga Agile LLC +# +# 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: transfer-project.directive.coffee +### + +module = angular.module('taigaProjects') + +class TransferProject + @.$inject = [ + "$routeParams", + "tgProjectsService" + "$location", + "$tgAuth", + "tgCurrentUserService", + "$tgNavUrls", + "$translate", + "$tgConfirm" + ] + + constructor: (@routeParams, @projectService, @location, @authService, @currentUserService, @navUrls, @translate, @confirmService) -> + + initialize: () -> + @.projectId = @.project.get("id") + @.token = @routeParams.token + @.showAddComment = false + return @._refreshUserData() + + _validateToken: () -> + return @projectService.transferValidateToken(@.projectId, @.token).then null, (data, status) => + @location.path(@navUrls.resolve("not-found")) + + _refreshUserData: () -> + return @authService.refresh().then () => + @._validateToken() + @._setProjectData() + @._checkOwnerData() + + _setProjectData: () -> + @.canBeOwnedByUser = @currentUserService.canOwnProject(@.project) + + _checkOwnerData: () -> + currentUser = @currentUserService.getUser() + if(@.project.get('is_private')) + @.ownerMessage = 'ADMIN.PROJECT_TRANSFER.OWNER_MESSAGE.PRIVATE' + @.maxProjects = currentUser.get('max_private_projects') + if @.maxProjects == null + @.maxProjects = @translate.instant('ADMIN.PROJECT_TRANSFER.UNLIMITED_PROJECTS') + @.currentProjects = currentUser.get('total_private_projects') + maxMemberships = currentUser.get('max_memberships_private_projects') + + else + @.ownerMessage = 'ADMIN.PROJECT_TRANSFER.OWNER_MESSAGE.PUBLIC' + @.maxProjects = currentUser.get('max_public_projects') + if @.maxProjects == null + @.maxProjects = @translate.instant('ADMIN.PROJECT_TRANSFER.UNLIMITED_PROJECTS') + @.currentProjects = currentUser.get('total_public_projects') + maxMemberships = currentUser.get('max_memberships_public_projects') + + @.validNumberOfMemberships = maxMemberships == null || @.project.get('total_memberships') <= maxMemberships + + transferAccept: (token, reason) -> + return @projectService.transferAccept(@.project.get("id"), token, reason).then () => + newUrl = @navUrls.resolve("project-admin-project-profile-details", { + project: @.project.get("slug") + }) + @location.path(newUrl) + + @confirmService.notify("success", @translate.instant("ADMIN.PROJECT_TRANSFER.ACCEPTED_PROJECT_OWNERNSHIP"), '', 5000) + + return + + transferReject: (token, reason) -> + return @projectService.transferReject(@.project.get("id"), token, reason).then () => + newUrl = @navUrls.resolve("project-admin-project-profile-details", { + project: @project.get("slug") + }) + @location.path(newUrl) + @confirmService.notify("success", @translate.instant("ADMIN.PROJECT_TRANSFER.REJECTED_PROJECT_OWNERNSHIP"), '', 5000) + + return + + addComment: () -> + @.showAddComment = true + + hideComment: () -> + @.showAddComment = false + @.reason = '' + + +module.controller("TransferProjectController", TransferProject) diff --git a/app/modules/projects/transfer/transfer-project.directive.coffee b/app/modules/projects/transfer/transfer-project.directive.coffee new file mode 100644 index 00000000..5a117d27 --- /dev/null +++ b/app/modules/projects/transfer/transfer-project.directive.coffee @@ -0,0 +1,37 @@ +### +# Copyright (C) 2014-2016 Taiga Agile LLC +# +# 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: transfer-project.directive.coffee +### + +module = angular.module('taigaProjects') + +TransferProjectDirective = () -> + link = (scope, el, attrs, ctrl) -> + ctrl.initialize() + + return { + link: link, + scope: {}, + bindToController: { + project: "=" + }, + templateUrl: "projects/transfer/transfer-project.html", + controller: 'TransferProjectController', + controllerAs: 'vm' + } + +module.directive('tgTransferProject', TransferProjectDirective) diff --git a/app/modules/projects/transfer/transfer-project.jade b/app/modules/projects/transfer/transfer-project.jade new file mode 100644 index 00000000..87f3ac12 --- /dev/null +++ b/app/modules/projects/transfer/transfer-project.jade @@ -0,0 +1,69 @@ +.transfer-project-wrapper + h2.transfer-title(translate="ADMIN.PROJECT_TRANSFER.DO_YOU_ACCEPT_PROJECT_OWNERNSHIP") + .transfer-project-detail + img.transfer-project-image( + tg-project-logo-small-src="vm.project" + alt="{{vm.project.get('name')}}" + ) + .transfer-project-data + h3.transfer-project-title {{::vm.project.get("name")}} + .transfer-project-statistics + span.transfer-project-private(ng-if="vm.project.get('is_private')") + svg.icon.icon-lock + use(xlink:href="#icon-lock") + span(translate="ADMIN.PROJECT_TRANSFER.PRIVATE") + span.transfer-project-members + svg.icon.icon-team + use(xlink:href="#icon-team") + span {{::vm.project.get("total_memberships")}} + + p( + translate="ADMIN.PROJECT_TRANSFER.PROPOSE_OWNERSHIP" + translate-values="{owner: vm.project.getIn(['owner', 'full_name_display']), project: vm.project.get('name')}" + ) + + div(ng-if="vm.canBeOwnedByUser.valid") + + p( + translate="{{vm.ownerMessage}}" + translate-values="{maxProjects: vm.maxProjects, currentProjects: vm.currentProjects}" + ) + + a.transfer-project-comment-link.ng-animate-disabled( + href="" + ng-click="vm.addComment()" + ng-if="!vm.showAddComment" + translate="ADMIN.PROJECT_TRANSFER.ADD_COMMENT_QUESTION" + ) + + fieldset.transfer-project-comment-form( + ng-if="vm.showAddComment" + ng-class="{'open': vm.showAddComment}" + ) + .transfer-project-comment-header + label.transfer-project-comment-label( + translate="ADMIN.PROJECT_TRANSFER.ADD_COMMENT" + ) + svg.icon.icon-close(ng-click="vm.hideComment()") + use(xlink:href="#icon-close") + textarea.transfer-project-comment( + name="reason" + ng-model="vm.reason" + ) + + .transfer-project-options + a.button.button-gray( + ng-click="vm.transferReject(vm.token, vm.reason)" + href="#" + title="{{'ADMIN.PROJECT_TRANSFER.REJECT' | translate}}" + translate="ADMIN.PROJECT_TRANSFER.REJECT" + ) + + a.button.button-green( + ng-click="vm.transferAccept(vm.token, vm.reason)" + href="#" + title="{{'ADMIN.PROJECT_TRANSFER.ACCEPT' | translate}}" + translate="ADMIN.PROJECT_TRANSFER.ACCEPT" + ) + + div(ng-if="!vm.canBeOwnedByUser.valid", tg-cant-own-project-explanation) diff --git a/app/modules/projects/transfer/transfer-project.scss b/app/modules/projects/transfer/transfer-project.scss new file mode 100644 index 00000000..99921eb5 --- /dev/null +++ b/app/modules/projects/transfer/transfer-project.scss @@ -0,0 +1,93 @@ +.transfer-project-wrapper { + max-width: 500px; + width: 90%; +} + +.transfer-project { + align-items: center; + background: url('../images/discover.png') bottom center repeat-x; + display: flex; + justify-content: center; + min-height: calc(100vh - 40px); + .transfer-title { + @extend %light; + } + &-detail { + align-items: center; + border-bottom: 1px solid $whitish; + border-top: 1px solid $whitish; + display: flex; + flex-direction: row; + justify-content: center; + margin: 1rem 0 3rem; + padding: 1rem 0; + } + &-image { + margin-right: 1rem; + width: 4rem; + } + &-title { + @extend %light; + @extend %larger; + margin-bottom: .25rem; + } + &-statistics { + span { + color: $gray-light; + margin-right: .5rem; + } + svg { + fill: $gray-light; + margin-right: .25rem; + } + } + &-private { + text-transform: uppercase; + } + &-comment-link { + color: $primary; + cursor: pointer; + display: block; + margin-bottom: 1rem; + &:hover { + color: $primary-light; + } + } + &-comment-header { + display: flex; + justify-content: space-between; + .icon-close { + cursor: pointer; + fill: $gray-light; + &:hover { + fill: $red-light; + transition: fill .2s; + } + } + } + &-comment-form { + &.ng-enter { + animation: dropdownFade .2s; + } + } + &-comment-label { + display: block; + margin-bottom: .5rem; + } + &-comment { + margin-bottom: 1rem; + min-height: 6rem; + } + &-options { + display: flex; + a { + @extend %large; + display: block; + flex: 1; + padding: .75rem; + &:first-child { + margin-right: .5rem; + } + } + } +} diff --git a/app/modules/resources/projects-resource.service.coffee b/app/modules/resources/projects-resource.service.coffee index d18fc96e..226534ff 100644 --- a/app/modules/resources/projects-resource.service.coffee +++ b/app/modules/resources/projects-resource.service.coffee @@ -108,6 +108,42 @@ Resource = (urlsService, http, paginateResponseService) -> url = urlsService.resolve("project-unwatch", projectId) return http.post(url) + service.transferValidateToken = (projectId, token) -> + data = { + token: token + } + url = urlsService.resolve("project-transfer-validate-token", projectId) + return http.post(url, data) + + service.transferAccept = (projectId, token, reason) -> + data = { + token: token + reason: reason + } + url = urlsService.resolve("project-transfer-accept", projectId) + return http.post(url, data) + + service.transferReject = (projectId, token, reason) -> + data = { + token: token + reason: reason + } + url = urlsService.resolve("project-transfer-reject", projectId) + return http.post(url, data) + + service.transferRequest = (projectId) -> + url = urlsService.resolve("project-transfer-request", projectId) + return http.post(url) + + service.transferStart = (projectId, userId, reason) -> + data = { + user: userId, + reason: reason + } + + url = urlsService.resolve("project-transfer-start", projectId) + return http.post(url, data) + return () -> return {"projects": service} diff --git a/app/modules/services/app-meta.service.coffee b/app/modules/services/app-meta.service.coffee index d0a4febf..e3382e7e 100644 --- a/app/modules/services/app-meta.service.coffee +++ b/app/modules/services/app-meta.service.coffee @@ -33,7 +33,7 @@ class AppMetaService return if not key if key == "title" - meta = $("title") + meta = $("head title") if meta.length == 0 meta = $("") @@ -41,7 +41,7 @@ class AppMetaService meta.text(value or "") else if key.indexOf("og:") == 0 - meta = $("meta[property='#{key}']") + meta = $("head meta[property='#{key}']") if meta.length == 0 meta = $("") @@ -49,7 +49,7 @@ class AppMetaService meta.attr("content", value or "") else - meta = $("meta[name='#{key}']") + meta = $("head meta[name='#{key}']") if meta.length == 0 meta = $("") @@ -91,7 +91,7 @@ class AppMetaService ) removeMobileViewport: () -> - $("meta[name=\"viewport\"]").remove() + $("head meta[name=\"viewport\"]").remove() setfn: (fn) -> @._listener() if @.listener diff --git a/app/modules/services/current-user.service.coffee b/app/modules/services/current-user.service.coffee index 568c53f3..60985801 100644 --- a/app/modules/services/current-user.service.coffee +++ b/app/modules/services/current-user.service.coffee @@ -118,4 +118,37 @@ class CurrentUserService return @.projects + 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: true} + + canCreatePublicProjects: () -> + 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: true} + + canOwnProject: (project) -> + user = @.getUser() + if project.get('is_private') + 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'} + + 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'} + + return {valid: true} + angular.module("taigaCommon").service("tgCurrentUserService", CurrentUserService) diff --git a/app/modules/services/current-user.service.spec.coffee b/app/modules/services/current-user.service.spec.coffee index a3fe43b7..fba99a7f 100644 --- a/app/modules/services/current-user.service.spec.coffee +++ b/app/modules/services/current-user.service.spec.coffee @@ -203,3 +203,227 @@ describe "tgCurrentUserService", -> expect(config).to.be.eql(joyride) done() + + it "the user can't create private projects if they reach the maximum number of private projects", () -> + user = Immutable.fromJS({ + id: 1, + name: "fake1", + max_private_projects: 1, + total_private_projects: 1 + }) + + currentUserService._user = user + + result = currentUserService.canCreatePrivateProjects() + + expect(result).to.be.eql({ + valid: false, + reason: 'max_private_projects', + type: 'private_project' + }) + + it "the user can create private projects", () -> + user = Immutable.fromJS({ + id: 1, + name: "fake1", + max_private_projects: 10, + total_private_projects: 1, + max_memberships_private_projects: 20 + }) + + currentUserService._user = user + + result = currentUserService.canCreatePrivateProjects(10) + + expect(result).to.be.eql({ + valid: true + }) + + it "the user can't create public projects if they reach the maximum number of private projects", () -> + user = Immutable.fromJS({ + id: 1, + name: "fake1", + max_public_projects: 1, + total_public_projects: 1 + }) + + currentUserService._user = user + + result = currentUserService.canCreatePublicProjects(0) + + expect(result).to.be.eql({ + valid: false, + reason: 'max_public_projects', + type: 'public_project' + }) + + it "the user can create public projects", () -> + user = Immutable.fromJS({ + id: 1, + name: "fake1", + max_public_projects: 10, + total_public_projects: 1, + max_memberships_public_projects: 20 + }) + + currentUserService._user = user + + result = currentUserService.canCreatePublicProjects(10) + + expect(result).to.be.eql({ + valid: true + }) + + it "the user can own public project", () -> + user = Immutable.fromJS({ + id: 1, + name: "fake1", + max_public_projects: 10, + total_public_projects: 1, + max_memberships_public_projects: 20 + }) + + currentUserService._user = user + + project = Immutable.fromJS({ + id: 2, + name: "fake2", + total_memberships: 5, + is_private: false + }) + + result = currentUserService.canOwnProject(project) + + expect(result).to.be.eql({ + valid: true + }) + + it "the user can't own public project because of max projects", () -> + user = Immutable.fromJS({ + id: 1, + name: "fake1", + max_public_projects: 1, + total_public_projects: 1, + max_memberships_public_projects: 20 + }) + + currentUserService._user = user + + project = Immutable.fromJS({ + id: 2, + name: "fake2", + total_memberships: 5, + is_private: false + }) + + result = currentUserService.canOwnProject(project) + + expect(result).to.be.eql({ + valid: false + reason: 'max_public_projects' + type: 'public_project' + }) + + + it "the user can't own public project because of max memberships", () -> + user = Immutable.fromJS({ + id: 1, + name: "fake1", + max_public_projects: 5, + total_public_projects: 1, + max_memberships_public_projects: 4 + }) + + currentUserService._user = user + + project = Immutable.fromJS({ + id: 2, + name: "fake2", + total_memberships: 5, + is_private: false + }) + + result = currentUserService.canOwnProject(project) + + expect(result).to.be.eql({ + valid: false + reason: 'max_members_public_projects' + type: 'public_project' + }) + + it "the user can own private project", () -> + user = Immutable.fromJS({ + id: 1, + name: "fake1", + max_private_projects: 10, + total_private_projects: 1, + max_memberships_private_projects: 20 + }) + + currentUserService._user = user + + project = Immutable.fromJS({ + id: 2, + name: "fake2", + total_memberships: 5, + is_private: true + }) + + result = currentUserService.canOwnProject(project) + + expect(result).to.be.eql({ + valid: true + }) + + it "the user can't own private project because of max projects", () -> + user = Immutable.fromJS({ + id: 1, + name: "fake1", + max_private_projects: 1, + total_private_projects: 1, + max_memberships_private_projects: 20 + }) + + currentUserService._user = user + + project = Immutable.fromJS({ + id: 2, + name: "fake2", + total_memberships: 5, + is_private: true + }) + + result = currentUserService.canOwnProject(project) + + expect(result).to.be.eql({ + valid: false + reason: 'max_private_projects' + type: 'private_project' + }) + + + it "the user can't own private project because of max memberships", () -> + user = Immutable.fromJS({ + id: 1, + name: "fake1", + max_private_projects: 10, + total_private_projects: 1, + max_memberships_private_projects: 4 + }) + + currentUserService._user = user + + project = Immutable.fromJS({ + id: 2, + name: "fake2", + total_memberships: 5, + is_private: true + }) + + result = currentUserService.canOwnProject(project) + + expect(result).to.be.eql({ + valid: false + reason: 'max_members_private_projects' + type: 'private_project' + }) diff --git a/app/modules/services/project.service.coffee b/app/modules/services/project.service.coffee index ca118352..a6640ac5 100644 --- a/app/modules/services/project.service.coffee +++ b/app/modules/services/project.service.coffee @@ -75,4 +75,5 @@ class ProjectService return @projectsService.getProjectBySlug(pslug).then (project) => @.setProject(project) + angular.module("taigaCommon").service("tgProjectService", ProjectService) diff --git a/app/modules/user-timeline/user-timeline-attachment/user-timeline-attachment.jade b/app/modules/user-timeline/user-timeline-attachment/user-timeline-attachment.jade index a2f83b04..8c086e97 100644 --- a/app/modules/user-timeline/user-timeline-attachment/user-timeline-attachment.jade +++ b/app/modules/user-timeline/user-timeline-attachment/user-timeline-attachment.jade @@ -1,5 +1,6 @@ div.single-attachment blockquote a(ng-href="{{ attachment.get('url') }}", title="Click to download {{ attachment.get('filename') }}", target="_blank") - span.icon.icon-document + svg.icon.icon-attachment + use(xlink:href="#icon-attachment") span {{attachment.get('filename')}} diff --git a/app/modules/user-timeline/user-timeline/user-timeline.scss b/app/modules/user-timeline/user-timeline/user-timeline.scss index fc41472a..181109b4 100644 --- a/app/modules/user-timeline/user-timeline/user-timeline.scss +++ b/app/modules/user-timeline/user-timeline/user-timeline.scss @@ -86,11 +86,12 @@ max-width: 95%; overflow: hidden; text-overflow: ellipsis; - vertical-align: middle; + vertical-align: sub; white-space: nowrap; } .icon { - margin-right: .3rem; + fill: $grayer; + margin-right: .5rem; } } .spin { diff --git a/app/partials/admin/admin-memberships-row-checkbox.jade b/app/partials/admin/admin-memberships-row-checkbox.jade index efa25b23..828dd28e 100644 --- a/app/partials/admin/admin-memberships-row-checkbox.jade +++ b/app/partials/admin/admin-memberships-row-checkbox.jade @@ -1,4 +1,4 @@ -.check +.check.js-check input(type="checkbox", id!="<%- inputId %>") div span.check-text.check-yes(translate="COMMON.YES") diff --git a/app/partials/admin/admin-memberships.jade b/app/partials/admin/admin-memberships.jade index 1944fb21..46064518 100644 --- a/app/partials/admin/admin-memberships.jade +++ b/app/partials/admin/admin-memberships.jade @@ -1,25 +1,30 @@ doctype html -div.wrapper.memberships(ng-controller="MembershipsController as ctrl", - ng-init="section='admin'; sectionName='ADMIN.MEMBERSHIPS.TITLE'", tg-memberships) +div.wrapper.memberships( + ng-controller="MembershipsController as ctrl" + ng-init="section='admin'; sectionName='ADMIN.MEMBERSHIPS.TITLE'" + tg-memberships +) tg-project-menu sidebar.menu-secondary.sidebar.settings-nav(tg-admin-navigation="memberships") include ../includes/modules/admin-menu - section.main.admin-membership + section.main.admin-membership.admin-common .header-with-actions header include ../includes/components/mainTitle + tg-no-more-memberships-explanation(ng-if="canAddUsers == false", project="project") .action-buttons - a.button-green(href="", title="{{ ADMIN.MEMBERSHIPS.ADD_BUTTON_TITLE | translate }}", - ng-click="ctrl.addNewMembers()") - span.text(translate="ADMIN.MEMBERSHIPS.ADD_BUTTON") + button.button-green( + translate="ADMIN.MEMBERSHIPS.ADD_BUTTON" + title="{{ ADMIN.MEMBERSHIPS.ADD_BUTTON_TITLE | translate }}", + ng-click="ctrl.addNewMembers()" + ng-disabled="canAddUsers == false" + ) + include ../includes/modules/admin/admin-membership-table div.paginator.memberships-paginator - - div.lightbox.lightbox-add-member(tg-lb-create-members) - include ../includes/modules/lightbox-add-member diff --git a/app/partials/admin/admin-project-change-owner.jade b/app/partials/admin/admin-project-change-owner.jade new file mode 100644 index 00000000..b7a4766a --- /dev/null +++ b/app/partials/admin/admin-project-change-owner.jade @@ -0,0 +1,11 @@ +.owner-avatar + img(ng-src="{{owner.photo || '/#{v}/images/user-noimage.png'}}", alt="{{::owner.full_name_display}}") + +.owner-info + .owner-info-title {{ 'ADMIN.PROJECT_PROFILE.PROJECT_OWNER' | translate }} + .owner-name {{::owner.full_name_display}} + +a.request( + href="", + ng-click="changeOwner()", + ng-if="members > 1") {{ 'ADMIN.PROJECT_PROFILE.CHANGE_OWNER' | translate }} diff --git a/app/partials/admin/admin-project-export.jade b/app/partials/admin/admin-project-export.jade index 04fd1af4..024e49da 100644 --- a/app/partials/admin/admin-project-export.jade +++ b/app/partials/admin/admin-project-export.jade @@ -26,5 +26,6 @@ div.wrapper(ng-controller="ProjectProfileController as ctrl", p.result-message a.help-button(href="https://taiga.io/support/import-export-projects/", target="_blank") - span.icon.icon-help + svg.icon.icon-question + use(xlink:href="#icon-question") span(translate="ADMIN.HELP") diff --git a/app/partials/admin/admin-project-modules.jade b/app/partials/admin/admin-project-modules.jade index ab4ade35..93ae5d6b 100644 --- a/app/partials/admin/admin-project-modules.jade +++ b/app/partials/admin/admin-project-modules.jade @@ -1,7 +1,10 @@ doctype html -div.wrapper(tg-project-modules, ng-controller="ProjectProfileController as ctrl", - ng-init="section='admin'; sectionName='ADMIN.MODULES.TITLE'") +div.wrapper( + tg-project-modules + ng-controller="ProjectProfileController as ctrl" + ng-init="section='admin'; sectionName='ADMIN.MODULES.TITLE'" +) tg-project-menu sidebar.menu-secondary.sidebar.settings-nav(tg-admin-navigation="project-profile") include ../includes/modules/admin-menu @@ -13,89 +16,159 @@ div.wrapper(tg-project-modules, ng-controller="ProjectProfileController as ctrl" header include ../includes/components/mainTitle - form - div.functionality(ng-class="{true:'active', false:''}[project.is_backlog_activated]") - div.icon.icon-scrum - div.desc - p - span.title(translate="ADMIN.MODULES.BACKLOG") - span(translate="ADMIN.MODULES.BACKLOG_DESCRIPTION") - div.activate - input.activate-input(type="checkbox", id="functionality-backlog", - ng-model="project.is_backlog_activated") - label.button.button-gray(ng-switch="project.is_backlog_activated", - for="functionality-backlog") - span(ng-switch-when="true", translate="ADMIN.MODULES.DISABLE") - span(ng-switch-when="false", translate="ADMIN.MODULES.ENABLE") + form.module-container + .module.module-scrum(ng-class="{true:'active', false:''}[project.is_backlog_activated]") + .module-icon + svg.icon.icon-scrum + use(xlink:href="#icon-scrum") + .module-name(translate="ADMIN.MODULES.BACKLOG") + .module-desc + p(translate="ADMIN.MODULES.BACKLOG_DESCRIPTION") + .module-desc-options(ng-if="project.is_backlog_activated") + fieldset + label(for="total-sprints") {{ 'ADMIN.MODULES.NUMBER_SPRINTS' | translate }} + input( + id="total-sprints" + name="total-sprints" + type="number" + min="0" + placeholder="{{'ADMIN.MODULES.NUMBER_SPRINTS_HELP' | translate}}" + ng-model="project.total_milestones" + data-type="digits" + ) - div.functionality(ng-class="{true:'active', false:''}[project.is_kanban_activated]") - div.icon.icon-kanban - div.desc - p - span.title(translate="ADMIN.MODULES.KANBAN") - span(translate="ADMIN.MODULES.KANBAN_DESCRIPTION") - div.activate - input.activate-input(type="checkbox", id="functionality-kanban", - ng-model="project.is_kanban_activated") - label.button.button-gray(ng-switch="project.is_kanban_activated", - for="functionality-kanban") - span(ng-switch-when="true", translate="ADMIN.MODULES.DISABLE") - span(ng-switch-when="false", translate="ADMIN.MODULES.ENABLE") + fieldset + label(for="total-story-points") {{ 'ADMIN.MODULES.NUMBER_US_POINTS' | translate }} + input( + id="total-story-points" + name="total-story-points" + type="number" + min="0" + placeholder="{{'ADMIN.MODULES.NUMBER_US_POINTS_HELP' | translate}}" + ng-model="project.total_story_points" + data-type="digits" + ) + svg.icon.icon-save(ng-if="project.is_backlog_activated") + use(xlink:href="#icon-save") + .module-activation.module-direct-active + div.check + input.activate-input( + id="functionality-backlog" + name="functionality-backlog" + type="checkbox" + ng-checked="project.is_backlog_activated" + ng-model="project.is_backlog_activated" + ) + div + span.check-text.check-yes(translate="COMMON.YES") + span.check-text.check-no(translate="COMMON.NO") - div.functionality(ng-class="{true:'active', false:''}[project.is_issues_activated]") - div.icon.icon-issues - div.desc - p - span.title(translate="ADMIN.MODULES.ISSUES") - span(translate="ADMIN.MODULES.ISSUES_DESCRIPTION") - div.activate - input.activate-input(type="checkbox", id="functionality-issues", - ng-model="project.is_issues_activated") - label.button.button-gray(ng-switch="project.is_issues_activated", - for="functionality-issues") - span(ng-switch-when="true", translate="ADMIN.MODULES.DISABLE") - span(ng-switch-when="false", translate="ADMIN.MODULES.ENABLE") + .module.module-kanban(ng-class="{true:'active', false:''}[project.is_kanban_activated]") + .module-icon + svg.icon.icon-kanban + use(xlink:href="#icon-kanban") + .module-name(translate="ADMIN.MODULES.KANBAN") + .module-desc(translate="ADMIN.MODULES.KANBAN_DESCRIPTION") + .module-activation.module-direct-active + div.check + input.activate-input( + id="functionality-kanban" + name="functionality-kanban" + type="checkbox" + ng-checked="project.is_kanban_activated" + ng-model="project.is_kanban_activated" + ) + div + span.check-text.check-yes(translate="COMMON.YES") + span.check-text.check-no(translate="COMMON.NO") - div.functionality(ng-class="{true:'active', false:''}[project.is_wiki_activated]") - div.icon.icon-wiki - div.desc - p - span.title(translate="ADMIN.MODULES.WIKI") - span(translate="ADMIN.MODULES.WIKI_DESCRIPTION") - div.activate - input.activate-input(type="checkbox", id="functionality-wiki", - ng-model="project.is_wiki_activated") - label.button.button-gray(ng-switch="project.is_wiki_activated", - for="functionality-wiki") - span(ng-switch-when="true", translate="ADMIN.MODULES.DISABLE") - span(ng-switch-when="false", translate="ADMIN.MODULES.ENABLE") + .module.module-issues(ng-class="{true:'active', false:''}[project.is_issues_activated]") + .module-icon + svg.icon.icon-issues + use(xlink:href="#icon-issues") + .module-name(translate="ADMIN.MODULES.ISSUES") + .module-desc(translate="ADMIN.MODULES.ISSUES_DESCRIPTION") + .module-activation.module-direct-active + div.check + input.activate-input( + id="functionality-issues" + name="functionality-issues" + type="checkbox" + ng-checked="project.is_issues_activated" + ng-model="project.is_issues_activated" + ) + div + span.check-text.check-yes(translate="COMMON.YES") + span.check-text.check-no(translate="COMMON.NO") - div.functionality(ng-class="{true:'active', false:''}[isVideoconferenceActivated]") - div.icon.icon-video - div.desc - p - span.title(translate="ADMIN.MODULES.MEETUP") - span(translate="ADMIN.MODULES.MEETUP_DESCRIPTION") - div.activate - input.activate-input(type="checkbox", id="functionality-video", - ng-model="isVideoconferenceActivated") - label.button.button-gray(ng-switch="isVideoconferenceActivated", - for="functionality-video") - span(ng-switch-when="true", translate="ADMIN.MODULES.DISABLE") - span(ng-switch-when="false", translate="ADMIN.MODULES.ENABLE") + .module.module-wiki(ng-class="{true:'active', false:''}[project.is_wiki_activated]") + .module-icon + svg.icon.icon-wiki + use(xlink:href="#icon-wiki") + .module-name(translate="ADMIN.MODULES.WIKI") + .module-desc(translate="ADMIN.MODULES.WIKI_DESCRIPTION") + .module-activation.module-direct-active + div.check + input.activate-input( + id="functionality-wiki" + name="functionality-wiki" + type="checkbox" + ng-checked="project.is_wiki_activated" + ng-model="project.is_wiki_activated" + ) + div + span.check-text.check-yes(translate="COMMON.YES") + span.check-text.check-no(translate="COMMON.NO") - div.videoconference-attributes.hidden - select(ng-model="project.videoconferences", - ng-options="e.id as e.name|translate for e in [{'id':'appear-in', 'name':'ADMIN.MODULES.APPEARIN_CHAT_ROOM'},{'id':'jitsi', 'name': 'ADMIN.MODULES.JITSI_CHAT_ROOM'},{'id':'talky', 'name': 'ADMIN.MODULES.TALKY_CHAT_ROOM'},{'id':'custom', 'name': 'ADMIN.MODULES.CUSTOM_CHAT_ROOM'}]") - option(value="", translate="ADMIN.MODULES.SELECT_VIDEOCONFERENCE") - input(ng-if="project.videoconferences && project.videoconferences != 'custom'", - type="text", - ng-model="project.videoconferences_extra_data", - data-maxlength="255", - placeholder="{{'ADMIN.MODULES.SALT_CHAT_ROOM' | translate}}") - input(ng-if="project.videoconferences == 'custom'", - type="text", - ng-model="project.videoconferences_extra_data", - data-maxlength="255", - placeholder="{{'ADMIN.MODULES.URL_CHAT_ROOM' | translate}}") - button.button-green.submit-button(type="submit", title="{{'COMMON.SAVE' | translate}}", translate="COMMON.SAVE") + .module.module-videoconference(ng-class="{true:'active', false:''}[isVideoconferenceActivated]") + .module-icon + svg.icon.icon-bubble-empty + use(xlink:href="#icon-bubble-empty") + .module-name(translate="ADMIN.MODULES.MEETUP") + .module-desc + p(translate="ADMIN.MODULES.MEETUP_DESCRIPTION") + div.videoconference-attributes(ng-if="isVideoconferenceActivated") + select( + id="videoconference-type" + name="videoconference-type" + ng-model="project.videoconferences" + ng-options="e.id as e.name|translate for e in [{'id':'appear-in', 'name':'ADMIN.MODULES.APPEARIN_CHAT_ROOM'},{'id':'jitsi', 'name': 'ADMIN.MODULES.JITSI_CHAT_ROOM'},{'id':'talky', 'name': 'ADMIN.MODULES.TALKY_CHAT_ROOM'},{'id':'custom', 'name': 'ADMIN.MODULES.CUSTOM_CHAT_ROOM'}]") + option( + value="" + translate="ADMIN.MODULES.SELECT_VIDEOCONFERENCE" + ) + fieldset(ng-if="project.videoconferences && project.videoconferences != 'custom'") + input( + id="videoconference-prefix" + name="videoconference-prefix" + type="text" + ng-model="project.videoconferences_extra_data" + data-maxlength="250" + placeholder="{{'ADMIN.MODULES.SALT_CHAT_ROOM' | translate}}" + ) + fieldset(ng-if="project.videoconferences == 'custom'") + input( + id="videoconference-url" + name="videoconference-url" + type="url" + ng-model="project.videoconferences_extra_data" + data-maxlength="250" + placeholder="{{'ADMIN.MODULES.URL_CHAT_ROOM' | translate}}" + data-type="url" + data-required="true" + ) + svg.icon.icon-save(ng-if="project.videoconferences") + use(xlink:href="#icon-save") + + .module-activation + div.check + input.activate-input( + id="functionality-video" + name="functionality-video" + type="checkbox" + ng-checked="project.isVideoconferenceActivated" + ng-model="isVideoconferenceActivated" + ) + div + span.check-text.check-yes(translate="COMMON.YES") + span.check-text.check-no(translate="COMMON.NO") diff --git a/app/partials/admin/admin-project-profile.jade b/app/partials/admin/admin-project-profile.jade index a44a1e8d..7cd2f329 100644 --- a/app/partials/admin/admin-project-profile.jade +++ b/app/partials/admin/admin-project-profile.jade @@ -78,37 +78,26 @@ div.wrapper( ng-model="project.tags" ) - fieldset - label(for="project-sprints") {{ 'ADMIN.PROJECT_PROFILE.NUMBER_SPRINTS' | translate }} - input( - type="number" - name="total_milestones" - min="0" - placeholder="{{'ADMIN.PROJECT_PROFILE.NUMBER_SPRINTS' | translate}}" - id="project-sprints" - ng-model="project.total_milestones" - data-type="digits" + fieldset(ng-if="project.owner.id != user.id") + tg-admin-project-request-ownership.admin-project-profile-owner-actions( + owner="project.owner", + project-id="project.id" ) - fieldset - label(for="total-story-points") {{ 'ADMIN.PROJECT_PROFILE.NUMBER_US_POINTS' | translate }} - input( - type="number" - name="total_story_points" - min="0" - placeholder="{{'ADMIN.PROJECT_PROFILE.NUMBER_US_POINTS' | translate}}" - id="total-story-points" - ng-model="project.total_story_points" - data-type="digits" + fieldset(ng-if="project.owner.id == user.id") + tg-admin-project-change-owner.admin-project-profile-owner-actions( + members="project.members.length" + owner="project.owner", + project-id="project.id" + active-users="activeUsers" ) fieldset.looking-for-people .looking-for-people-selector span {{ 'ADMIN.PROJECT_PROFILE.RECRUITING' | translate }} - span( - title="{{ 'ADMIN.PROJECT_PROFILE.RECRUITING_MESSAGE' | translate }}" - ) - include ../../svg/recruit.svg + svg.icon.icon-recruit + use(xlink:href="#icon-recruit") + title {{ 'ADMIN.PROJECT_PROFILE.RECRUITING_MESSAGE' | translate }}" div.check input( type="checkbox", @@ -127,10 +116,13 @@ div.wrapper( placeholder="{{ 'ADMIN.PROJECT_PROFILE.RECRUITING_PLACEHOLDER' | translate }}" ) + tg-admin-project-restrictions(project="project") + fieldset .project-privacy-settings div.privacy-option input.privacy-project( + ng-disabled="project.is_private && !project.is_private_extra_info.can_be_updated" type="radio" id="private-project" name="privacy-project" @@ -138,11 +130,10 @@ div.wrapper( ng-value="false" ) label.trans-button(for="private-project") {{ 'ADMIN.PROJECT_PROFILE.PUBLIC_PROJECT' | translate }} - span(title="{{ 'ADMIN.PROJECT_PROFILE.PUBLIC_PROJECT_DESC' | translate }}") - include ../../svg/help.svg div.privacy-option input.privacy-project( + ng-disabled="!project.is_private && !project.is_private_extra_info.can_be_updated" type="radio" id="public-project" name="privacy-project" @@ -150,15 +141,14 @@ div.wrapper( ng-value="true" ) label.trans-button(for="public-project") {{'ADMIN.PROJECT_PROFILE.PRIVATE_PROJECT' | translate }} - span(title="{{ 'ADMIN.PROJECT_PROFILE.PRIVATE_PROJECT_DESC' | translate }}") - include ../../svg/help.svg a.private-or-public( href="https://taiga.io/support/whats-the-difference-between-public-and-private-projects/" target="_blank" ) - span(title="{{ 'ADMIN.PROJECT_PROFILE.PRIVATE_OR_PUBLIC' | translate }}") - include ../../svg/help.svg + svg.icon.icon-question + use(xlink:href="#icon-question") + title {{ 'ADMIN.PROJECT_PROFILE.PRIVATE_OR_PUBLIC' | translate }} span {{'ADMIN.PROJECT_PROFILE.PRIVATE_OR_PUBLIC' | translate }} button.button-green.submit-button( type="submit" diff --git a/app/partials/admin/admin-project-reports.jade b/app/partials/admin/admin-project-reports.jade index ffbb8ca5..bde79213 100644 --- a/app/partials/admin/admin-project-reports.jade +++ b/app/partials/admin/admin-project-reports.jade @@ -22,5 +22,6 @@ div.wrapper(ng-controller="ProjectProfileController as ctrl", div a.help-button(href="https://taiga.io/support/csv-reports/", target="_blank") - span.icon.icon-help + svg.icon.icon-question + use(xlink:href="#icon-question") span(translate="ADMIN.REPORTS.HELP") diff --git a/app/partials/admin/admin-project-request-ownership.jade b/app/partials/admin/admin-project-request-ownership.jade new file mode 100644 index 00000000..713bd6b6 --- /dev/null +++ b/app/partials/admin/admin-project-request-ownership.jade @@ -0,0 +1,8 @@ +.owner-avatar + img(ng-src="{{owner.photo || '/#{v}/images/user-noimage.png'}}", alt="{{::owner.full_name_display}}") + +.owner-info + .title {{ 'ADMIN.PROJECT_PROFILE.PROJECT_OWNER' | translate }} + .owner-name {{::owner.full_name_display}} + +a.request(href="", ng-click="requestOwnership()") {{ 'ADMIN.PROJECT_PROFILE.REQUEST_OWNERSHIP' | translate }} diff --git a/app/partials/admin/admin-project-restrictions.jade b/app/partials/admin/admin-project-restrictions.jade new file mode 100644 index 00000000..f0895c9f --- /dev/null +++ b/app/partials/admin/admin-project-restrictions.jade @@ -0,0 +1,8 @@ +fieldset(ng-if="!project.is_private_extra_info.can_be_updated && project.i_am_owner" ng-switch="project.is_private_extra_info.reason") + span(ng-switch-when="max_private_projects") {{ 'ADMIN.PROJECT_PROFILE.MAX_PRIVATE_PROJECTS' | translate }} + + span(ng-switch-when="max_private_projects_memberships") {{ 'ADMIN.PROJECT_PROFILE.MAX_PRIVATE_PROJECTS_MEMBERS' | translate }} + + span(ng-switch-when="max_public_projects") {{ 'ADMIN.PROJECT_PROFILE.MAX_PUBLIC_PROJECTS' | translate }} + + span(ng-switch-when="max_public_projects_memberships") {{ 'ADMIN.PROJECT_PROFILE.MAX_PUBLIC_PROJECTS_MEMBERS' | translate }} diff --git a/app/partials/admin/admin-roles.jade b/app/partials/admin/admin-roles.jade index 2af066c0..1afdcc9b 100644 --- a/app/partials/admin/admin-roles.jade +++ b/app/partials/admin/admin-roles.jade @@ -18,25 +18,27 @@ div.wrapper.roles(ng-controller="RolesController as ctrl", span(translate="COMMON.DELETE") - div(ng-if="!role.external_user") - div(tg-edit-role) - .edit-role - input(type="text", value="{{ role.name }}") - a.save.icon-floppy(href="", title="{{'COMMON.SAVE' | translate}}") + tg-edit-role(ng-if="!role.external_user") + .edit-role + input(type="text", value="{{ role.name }}") + a.save(href="", title="{{'COMMON.SAVE' | translate}}") + svg.icon.icon-save + use(xlink:href="#icon-save") + p.total + span.role-name(title="{{'ADMIN.ROLES.COUNT_MEMBERS' | translate}}") {{ role.name }} + a.edit-value + svg.icon.icon-edit + use(xlink:href="#icon-edit") - p.total - span.role-name(title="{{'ADMIN.ROLES.COUNT_MEMBERS' | translate}}") {{ role.name }} - a.edit-value.icon.icon-edit + div.any-computable-role(ng-hide="anyComputableRole", translate="ADMIN.ROLES.WARNING_NO_ROLE") - div.any-computable-role(ng-hide="anyComputableRole", translate="ADMIN.ROLES.WARNING_NO_ROLE") - - div.general-category - span(translate="ADMIN.ROLES.HELP_ROLE_ENABLED") - div.check - input(type="checkbox", ng-model="role.computable", ng-change="ctrl.toggleComputable()") - div - span.check-text.check-yes(translate="COMMON.YES") - span.check-text.check-no(translate="COMMON.NO") + div.general-category + span(translate="ADMIN.ROLES.HELP_ROLE_ENABLED") + div.check + input(type="checkbox", ng-model="role.computable", ng-change="ctrl.toggleComputable()") + div + span.check-text.check-yes(translate="COMMON.YES") + span.check-text.check-no(translate="COMMON.NO") div(ng-if="role.external_user") p.total diff --git a/app/partials/admin/admin-third-parties-bitbucket.jade b/app/partials/admin/admin-third-parties-bitbucket.jade index 6aa26207..b56beb19 100644 --- a/app/partials/admin/admin-third-parties-bitbucket.jade +++ b/app/partials/admin/admin-third-parties-bitbucket.jade @@ -24,7 +24,8 @@ div.wrapper.roles(tg-bitbucket-webhooks, ng-controller="BitbucketController as c .field-with-option input(type="text", ng-model="bitbucket.webhooks_url", name="payload-url", readonly="readonly", placeholder="{{'ADMIN.THIRD_PARTIES.PAYLOAD_URL' | translate}}", id="payload-url") .option-wrapper.select-input-content - .icon.icon-copy + svg.icon.icon-clipboard + use(xlink:href="#icon-clipboard") .help-copy(translate="COMMON.COPY_TO_CLIPBOARD") fieldset @@ -34,5 +35,6 @@ div.wrapper.roles(tg-bitbucket-webhooks, ng-controller="BitbucketController as c button.button-green.submit-button(type="submit", title="{{'COMMON.SAVE' | translate}}", translate="COMMON.SAVE") a.help-button(href="https://taiga.io/support/bitbucket-integration/", target="_blank") - span.icon.icon-help + svg.icon.icon-question + use(xlink:href="#icon-question") span(translate="ADMIN.HELP") diff --git a/app/partials/admin/admin-third-parties-github.jade b/app/partials/admin/admin-third-parties-github.jade index 9154d42b..3500c73a 100644 --- a/app/partials/admin/admin-third-parties-github.jade +++ b/app/partials/admin/admin-third-parties-github.jade @@ -23,11 +23,13 @@ div.wrapper.roles(tg-github-webhooks, ng-controller="GithubController as ctrl", .field-with-option input(type="text", ng-model="github.webhooks_url", name="payload-url", readonly="readonly", placeholder="{{'ADMIN.THIRD_PARTIES.PAYLOAD_URL' | translate}}", id="payload-url") .option-wrapper.select-input-content - .icon.icon-copy + svg.icon.icon-clipboard + use(xlink:href="#icon-clipboard") .help-copy(translate="COMMON.COPY_TO_CLIPBOARD") button.button-green.submit-button(type="submit", title="{{'COMMON.SAVE' | translate}}", translate="COMMON.SAVE") a.help-button(href="https://taiga.io/support/github-integration/", target="_blank") - span.icon.icon-help + svg.icon.icon-question + use(xlink:href="#icon-question") span(translate="ADMIN.HELP") diff --git a/app/partials/admin/admin-third-parties-gitlab.jade b/app/partials/admin/admin-third-parties-gitlab.jade index 6bc1fcbe..8867eee3 100644 --- a/app/partials/admin/admin-third-parties-gitlab.jade +++ b/app/partials/admin/admin-third-parties-gitlab.jade @@ -23,7 +23,8 @@ div.wrapper.roles(tg-gitlab-webhooks, ng-controller="GitlabController as ctrl", .field-with-option input(type="text", ng-model="gitlab.webhooks_url", name="payload-url", readonly="readonly", placeholder="{{'ADMIN.THIRD_PARTIES.PAYLOAD_URL' | translate}}", id="payload-url") .option-wrapper.select-input-content - .icon.icon-copy + svg.icon.icon-clipboard + use(xlink:href="#icon-clipboard") .help-copy(translate="COMMON.COPY_TO_CLIPBOARD") fieldset @@ -33,5 +34,6 @@ div.wrapper.roles(tg-gitlab-webhooks, ng-controller="GitlabController as ctrl", button.button-green.submit-button(type="submit", title="{{'COMMON.SAVE' | translate}}", translate="COMMON.SAVE") a.help-button(href="https://taiga.io/support/gitlab-integration/", target="_blank") - span.icon.icon-help + svg.icon.icon-question + use(xlink:href="#icon-question") span(translate="ADMIN.HELP") diff --git a/app/partials/admin/admin-third-parties-webhooks.jade b/app/partials/admin/admin-third-parties-webhooks.jade index b890b2a0..0b9349e6 100644 --- a/app/partials/admin/admin-third-parties-webhooks.jade +++ b/app/partials/admin/admin-third-parties-webhooks.jade @@ -31,12 +31,29 @@ div.wrapper.roles(ng-controller="WebhooksController as ctrl", div.webhook-url div.webhook-url-inputs fieldset - input(type="text", name="url", data-type="url", placeholder="{{'ADMIN.WEBHOOKS.TYPE_PAYLOAD_URL' | translate}}", data-required="true", ng-model="webhook.url") + input( + type="text" + name="url" + data-type="url" + placeholder="{{'ADMIN.WEBHOOKS.TYPE_PAYLOAD_URL' | translate}}" + data-required="true" + ng-model="webhook.url" + ) fieldset - input(type="text", name="key", placeholder="{{'ADMIN.WEBHOOKS.TYPE_SERVICE_SECRET' | translate}}", data-required="true", ng-model="webhook.key") + input( + type="text" + name="key" + placeholder="{{'ADMIN.WEBHOOKS.TYPE_SERVICE_SECRET' | translate}}" + data-required="true" + ng-model="webhook.key" + ) div.webhook-options - a.edit-existing.icon.icon-floppy(href="", title="{{'ADMIN.WEBHOOKS.SAVE' | translate}}") - a.cancel-existing.icon.icon-delete(href="", title="{{'ADMIN.WEBHOOKS.CANCEL' | translate}}") + a.edit-existing(href="", title="{{'ADMIN.WEBHOOKS.SAVE' | translate}}") + svg.icon.icon-save + use(xlink:href="#icon-save") + a.cancel-existing(href="", title="{{'ADMIN.WEBHOOKS.CANCEL' | translate}}") + svg.icon.icon-close + use(xlink:href="#icon-close") div.visualization-mode div.row @@ -48,9 +65,15 @@ div.wrapper.roles(ng-controller="WebhooksController as ctrl", div.webhook-options div.webhook-options-wrapper - a.test-webhook.icon.icon-check-square(href="", title="{{'ADMIN.WEBHOOKS.TEST' | translate}}") - a.edit-webhook.icon.icon-edit(href="", title="{{'ADMIN.WEBHOOKS.EDIT' | translate}}") - a.delete-webhook.icon.icon-delete(href="", title="{{'ADMIN.WEBHOOKS.DELETE' | translate}}") + a.test-webhook(href="", title="{{'ADMIN.WEBHOOKS.TEST' | translate}}") + svg.icon.icon-check-empty + use(xlink:href="#icon-check-empty") + a.edit-webhook(href="", title="{{'ADMIN.WEBHOOKS.EDIT' | translate}}") + svg.icon.icon-edit + use(xlink:href="#icon-edit") + a.delete-webhook(href="", title="{{'ADMIN.WEBHOOKS.DELETE' | translate}}") + svg.icon.icon-trash + use(xlink:href="#icon-trash") div.webhooks-history(ng-show="webhook.logs") div.history-single-wrapper(ng-repeat="log in webhook.logs") @@ -58,13 +81,15 @@ div.wrapper.roles(ng-controller="WebhooksController as ctrl", div span.history-response-icon(ng-class="log.validStatus ? 'history-success' : 'history-error'", title="{{log.status}}") span.history-date(ng-bind="log.prettyDate") - span.toggle-log.icon.icon-arrow-bottom + svg.toggle-log.icon.icon-arrow-down + use(xlink:href="#icon-arrow-down") div.history-single-response div.history-single-request-header span(translate="ADMIN.WEBHOOKS.REQUEST") a.resend-request(href="", title="{{'ADMIN.WEBHOOKS.RESEND_REQUEST' | translate}}", data-log="{{log.id}}") - span.icon.icon-reload + svg.icon.icon-reload + use(xlink:href="#icon-reload") span(translate="ADMIN.WEBHOOKS.RESEND_REQUEST") div.history-single-request-body div.response-container @@ -91,9 +116,14 @@ div.wrapper.roles(ng-controller="WebhooksController as ctrl", fieldset input(type="text", name="key", placeholder="{{'ADMIN.WEBHOOKS.TYPE_SERVICE_SECRET' | translate}}", data-required="true", ng-model="newValue.key") div.webhook-options - a.add-new.icon.icon-floppy(href="", title="{{'ADMIN.WEBHOOKS.SAVE' | translate}}") - a.cancel-new.icon.icon-delete(href="", title="{{'ADMIN.WEBHOOKS.CANCEL' | translate}}") + a.add-new(href="", title="{{'ADMIN.WEBHOOKS.SAVE' | translate}}") + svg.icon.icon-save + use(xlink:href="#icon-save") + a.cancel-new(href="", title="{{'ADMIN.WEBHOOKS.CANCEL' | translate}}") + svg.icon.icon-close + use(xlink:href="#icon-close") a.help-button(href="https://taiga.io/support/webhooks/", target="_blank") - span.icon.icon-help + svg.icon.icon-question + use(xlink:href="#icon-question") span(translate="ADMIN.HELP") diff --git a/app/partials/admin/lightbox-add-members-no-more=memberships-warning-message.jade b/app/partials/admin/lightbox-add-members-no-more=memberships-warning-message.jade new file mode 100644 index 00000000..304e5f09 --- /dev/null +++ b/app/partials/admin/lightbox-add-members-no-more=memberships-warning-message.jade @@ -0,0 +1,11 @@ +p.member-limit-warning( + ng-if="project.i_am_owner == true" + translate="LIGHTBOX.CREATE_MEMBER.LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER" + translate-values="{maxMembers: project.max_memberships}" +) + +p.member-limit-warning( + ng-if="project.i_am_owner == false" + translate="LIGHTBOX.CREATE_MEMBER.LIMIT_USERS_WARNING_MESSAGE" + translate-values="{maxMembers: project.max_memberships}" +) diff --git a/app/partials/admin/lightbox-add-members.jade b/app/partials/admin/lightbox-add-members.jade new file mode 100644 index 00000000..5ba1f1b0 --- /dev/null +++ b/app/partials/admin/lightbox-add-members.jade @@ -0,0 +1,66 @@ +a.close( + href="" + title="close" +) + svg.icon.icon-close + use(xlink:href="#icon-close") +.add-member-wrapper + h2.title(translate="LIGHTBOX.ADD_MEMBER.TITLE") + form.add-member-form(ng-submit="vm.submit()") + .add-single-member(ng-repeat="member in vm.memberInvites") + fieldset + input( + ng-if="$first" + type="email" + required + placeholder="{{'LIGHTBOX.CREATE_MEMBER.PLACEHOLDER_TYPE_EMAIL' | translate}}" + data-required="true" + data-type="email" + ng-model="member.email" + ) + input( + ng-if="!$first" + type="email" + placeholder="{{'LIGHTBOX.CREATE_MEMBER.PLACEHOLDER_TYPE_EMAIL' | translate}}" + data-type="email" + ng-model="member.email" + ) + fieldset + select( + ng-if="vm.project" + ng-model="member.role_id" + ng-options="role.id as role.name for role in vm.project.roles" + ) + fieldset + a.add-fieldset.ng-animate-disabled( + href="" + ng-click="vm.addSingleMember()" + ng-if="$last && vm.canAddUsers" + ) + svg.icon.icon-add + use(xlink:href="#icon-add") + a.remove-fieldset.ng-animate-disabled( + href="" + ng-click="vm.removeSingleMember($index)" + ng-if="!$last || ($last && !vm.canAddUsers && vm.membersLimit > 1)" + ) + svg.icon.icon-trash + use(xlink:href="#icon-trash") + + tg-lightbox-add-members-warning-message(ng-if="vm.showWarningMessage", project="vm.project") + + fieldset.invitation-text + textarea( + ng-attr-placeholder="{{'LIGHTBOX.CREATE_MEMBER.PLACEHOLDER_INVITATION_TEXT' | translate}}" + maxlength="255" + ng-model="vm.invitationText" + ) + + button.button-green.submit-button( + type="submit" + title="{{'COMMON.CREATE' | translate}}" + translate="COMMON.CREATE" + tg-loading="vm.submitInvites" + ) + + p.help-text(translate="LIGHTBOX.ADD_MEMBER.HELP_TEXT") diff --git a/app/partials/admin/memberships-row-avatar.jade b/app/partials/admin/memberships-row-avatar.jade index 838f44cc..294a0143 100644 --- a/app/partials/admin/memberships-row-avatar.jade +++ b/app/partials/admin/memberships-row-avatar.jade @@ -2,6 +2,11 @@ figure.avatar img(src!="<%- imgurl %>", alt!="<%- full_name %>") figcaption span.name <%- full_name %> + <% if (isOwner) { %> + svg.icon.icon-badge + use(xlink:href="#icon-badge") + title(translate="COMMON.OWNER") + <% } %> div span.pending <%- pending %> span.email <%- email %> diff --git a/app/partials/admin/no-more-memberships-explanation.jade b/app/partials/admin/no-more-memberships-explanation.jade new file mode 100644 index 00000000..704fa69e --- /dev/null +++ b/app/partials/admin/no-more-memberships-explanation.jade @@ -0,0 +1,11 @@ +p.admin-subtitle( + ng-if="project.i_am_owner == true" + translate="ADMIN.MEMBERSHIPS.LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER" + translate-values="{members: project.total_memberships}" +) + +p.admin-subtitle( + ng-if="project.i_am_owner == false" + translate="ADMIN.MEMBERSHIPS.LIMIT_USERS_WARNING_MESSAGE_FOR_ADMIN" + translate-values="{members: project.total_memberships}" +) diff --git a/app/partials/admin/project-csv.jade b/app/partials/admin/project-csv.jade index 8e709dd9..559b1fd0 100644 --- a/app/partials/admin/project-csv.jade +++ b/app/partials/admin/project-csv.jade @@ -10,11 +10,14 @@ section.project-csv(tg-select-input-text) input(type="text", placeholder="{{'ADMIN.CSV.URL_FIELD_PLACEHOLDER' | translate}}", readonly, ng-model="csvUrl") div.option-wrapper.select-input-content - div.icon.icon-copy + svg.icon.icon-clipboard + use(xlink:href="#icon-clipboard") a(href="", title="{{'ADMIN.CSV.TITLE_REGENERATE_URL' | translate}}", ng-click="ctrl.regenerateUuid()") - span.icon.icon-plus(ng-hide="csvUrl") + svg.icon.icon-add(ng-hide="csvUrl") + use(xlink:href="#icon-add") span(ng-hide="csvUrl", translate="ADMIN.CSV.ACTION_GENERATE_URL") - span.icon.icon-reload(ng-Show="csvUrl") + svg.icon.icon-reload(ng-Show="csvUrl") + use(xlink:href="#icon-reload") span(ng-Show="csvUrl", translate="ADMIN.CSV.ACTION_REGENERATE") diff --git a/app/partials/auth/forgot-password.jade b/app/partials/auth/forgot-password.jade index ceca6a3e..b9d64138 100644 --- a/app/partials/auth/forgot-password.jade +++ b/app/partials/auth/forgot-password.jade @@ -1,6 +1,5 @@ doctype html -include ../includes/components/beta div.wrapper div.auth div.auth-container diff --git a/app/partials/auth/login.jade b/app/partials/auth/login.jade index b5182527..554023f7 100644 --- a/app/partials/auth/login.jade +++ b/app/partials/auth/login.jade @@ -1,8 +1,5 @@ doctype html -div - include ../includes/components/beta - div.wrapper div.auth div.auth-container diff --git a/app/partials/backlog/backlog.jade b/app/partials/backlog/backlog.jade index 76d1d9a2..11556f1a 100644 --- a/app/partials/backlog/backlog.jade +++ b/app/partials/backlog/backlog.jade @@ -11,12 +11,12 @@ div.wrapper(tg-backlog, ng-controller="BacklogController as ctrl", div.backlog-summary(tg-toggle-burndown-visibility) include ../includes/components/summary - div.empty-burndown(ng-if="showGraphPlaceholder && project.i_am_owner") - div.graph-icon - include ../../svg/graph.svg + div.empty-burndown(ng-if="showGraphPlaceholder && project.i_am_admin") + svg.icon.icon-graph + use(xlink:href="#icon-graph") div.empty-text p.title(translate="BACKLOG.CUSTOMIZE_GRAPH") - p {{'BACKLOG.CUSTOMIZE_GRAPH_TEXT' | translate}} #[a(href="", tg-nav="project-admin-project-profile-details:project=project.slug", title="{{'BACKLOG.CUSTOMIZE_GRAPH_TITLE' | translate}}") {{'BACKLOG.CUSTOMIZE_GRAPH_ADMIN' | translate}}] + p {{'BACKLOG.CUSTOMIZE_GRAPH_TEXT' | translate}} #[a(href="", tg-nav="project-admin-project-profile-modules:project=project.slug", title="{{'BACKLOG.CUSTOMIZE_GRAPH_TITLE' | translate}}") {{'BACKLOG.CUSTOMIZE_GRAPH_ADMIN' | translate}}] div.graphics-container.js-burndown-graph div.burndown(tg-burndown-backlog-graph) @@ -30,7 +30,8 @@ div.wrapper(tg-backlog, ng-controller="BacklogController as ctrl", title="{{'BACKLOG.MOVE_US_TO_CURRENT_SPRINT' | translate}}" id="move-to-current-sprint" ) - span.icon.icon-move + svg.icon.icon-move + use(xlink:href="#icon-move") span.text(translate="BACKLOG.MOVE_US_TO_CURRENT_SPRINT") a.trans-button.move-to-latest-sprint.move-to-sprint( ng-if="!currentSprint" @@ -38,7 +39,8 @@ div.wrapper(tg-backlog, ng-controller="BacklogController as ctrl", title="{{'BACKLOG.MOVE_US_TO_LATEST_SPRINT' | translate}}" id="move-to-latest-sprint" ) - span.icon.icon-move + svg.icon.icon-move + use(xlink:href="#icon-move") span.text(translate="BACKLOG.MOVE_US_TO_LATEST_SPRINT") a.trans-button( ng-if="userstories.length" diff --git a/app/partials/backlog/filter-selected.jade b/app/partials/backlog/filter-selected.jade index d9550028..860c8423 100644 --- a/app/partials/backlog/filter-selected.jade +++ b/app/partials/backlog/filter-selected.jade @@ -2,5 +2,6 @@ a.single-filter.selected(data-type!="<%- f.type %>", data-id!="<%- f.id %>") span.name(style!="<%- f.style %>") | <%- f.name %> - span.icon.icon-delete + svg.icon.icon-close.remove-filter + use(xlink:href="#icon-close") <% }) %> diff --git a/app/partials/backlog/sprint-header.jade b/app/partials/backlog/sprint-header.jade index f6bd89fd..fb24bf95 100644 --- a/app/partials/backlog/sprint-header.jade +++ b/app/partials/backlog/sprint-header.jade @@ -1,9 +1,12 @@ .sprint-name - a.icon.icon-arrow-up(href="", title="{{'BACKLOG.COMPACT_SPRINT' | translate}}") + a.compact-sprint(href="", title="{{'BACKLOG.COMPACT_SPRINT' | translate}}") + svg.icon.icon-arrow-right + use(xlink:href="#icon-arrow-right") a(ng-if="::isVisible", href="{{::taskboardUrl}}", title="{{'BACKLOG.GO_TO_TASKBOARD' | translate}}") span {{::name}} - a.icon.icon-edit(ng-if="::isEditable", href="", title="{{'BACKLOG.EDIT_SPRINT' | translate}}") + svg.icon.icon-edit.edit-sprint(ng-if="::isEditable", href="", title="{{'BACKLOG.EDIT_SPRINT' | translate}}") + use(xlink:href="#icon-edit") .sprint-summary .sprint-date {{::estimatedDateRange}} diff --git a/app/partials/common/components/add-button.jade b/app/partials/common/components/add-button.jade index a510e0a1..22606398 100644 --- a/app/partials/common/components/add-button.jade +++ b/app/partials/common/components/add-button.jade @@ -1,4 +1,5 @@ a.add-button( href="" ) - include ../../../svg/add.svg + svg.icon.icon-add + use(xlink:href="#icon-add") diff --git a/app/partials/common/components/assigned-to.jade b/app/partials/common/components/assigned-to.jade index 25b4b52b..2588a8b5 100644 --- a/app/partials/common/components/assigned-to.jade +++ b/app/partials/common/components/assigned-to.jade @@ -2,7 +2,8 @@ img(src!="<%- photo %>", alt!="<%- fullName %>") <% if (isIocaine) { %> .iocaine-symbol(title="{{ 'TASK.TITLE_ACTION_IOCAINE' | translate }}") - include ../../../svg/iocaine.svg + svg.icon.icon-iocaine + use(xlink:href="#icon-iocaine") <% }; %> .assigned-to @@ -23,7 +24,8 @@ <%- fullName %> <% }; %> <% if (isEditable && !isUnassigned) { %> - span.icon.icon-arrow-bottom + svg.icon.icon-arrow-down + use(xlink:href="#icon-arrow-down") <% }; %> <% if (isEditable && isUnassigned) { %> @@ -37,8 +39,9 @@ <% }; %> <% if (isEditable && !isUnassigned) { %> - a.icon.icon-delete( + svg.icon.icon-close.remove-user( href="" title="{{'COMMON.ASSIGNED_TO.DELETE_ASSIGNMENT' | translate}}" ) + use(xlink:href="#icon-close") <% } %> diff --git a/app/partials/common/components/block-button.jade b/app/partials/common/components/block-button.jade index 2f474602..0a499ff2 100644 --- a/app/partials/common/components/block-button.jade +++ b/app/partials/common/components/block-button.jade @@ -2,9 +2,11 @@ a.button-gray.item-block( href="" title="{{ 'COMMON.BLOCK_TITLE' | translate }}" ) - include ../../../svg/lock.svg + svg.icon.icon-lock + use(xlink:href="#icon-lock") a.button-red.item-unblock( href="" title="{{ 'COMMON.UNBLOCK_TITLE' | translate }}" ) - include ../../../svg/unlock.svg + svg.icon.icon-lock + use(xlink:href="#icon-unlock") diff --git a/app/partials/common/components/delete-button.jade b/app/partials/common/components/delete-button.jade index 22f6ee5b..3f1d987c 100644 --- a/app/partials/common/components/delete-button.jade +++ b/app/partials/common/components/delete-button.jade @@ -2,4 +2,5 @@ a.button-red.button-delete( href="" title="{{ 'COMMON.DELETE' | translate }}" ) - include ../../../svg/trash.svg + svg.icon.icon-trash + use(xlink:href="#icon-trash") diff --git a/app/partials/common/components/editable-description.jade b/app/partials/common/components/editable-description.jade index 6cfdeda1..348ef613 100644 --- a/app/partials/common/components/editable-description.jade +++ b/app/partials/common/components/editable-description.jade @@ -2,10 +2,12 @@ include wysiwyg.jade .view-description section.us-content.wysiwyg(tg-bind-html="item.description_html || noDescriptionMsg") - span.edit.icon.icon-edit + svg.icon.icon-edit.edit + use(xlink:href="#icon-edit") .edit-description textarea(ng-attr-placeholder="{{'COMMON.DESCRIPTION.EMPTY' | translate}}", ng-model="item.description", tg-markitup="tg-markitup") +wysihelp span.save-container - a.save.icon.icon-floppy(href="", title="{{'COMMON.SAVE' | translate}}") + svg.save.icon.icon-save(title="{{'COMMON.SAVE' | translate}}") + use(xlink:href="#icon-save") diff --git a/app/partials/common/components/editable-subject.jade b/app/partials/common/components/editable-subject.jade index f5d728bb..e4cc7bb2 100644 --- a/app/partials/common/components/editable-subject.jade +++ b/app/partials/common/components/editable-subject.jade @@ -1,7 +1,9 @@ .view-subject | {{ item.subject }} - a.edit.icon.icon-edit(href="" title="{{'COMMON.EDIT' | translate}}") + svg.edit.icon.icon-edit(href="" title="{{'COMMON.EDIT' | translate}}") + use(xlink:href="#icon-edit") .edit-subject input(type="text", ng-model="item.subject", data-required="true", data-maxlength="500", ng-model-options="{ debounce: 200 }") span.save-container - a.save.icon.icon-floppy(href="", title="{{'COMMON.SAVE' | translate}}") + svg.save.icon.icon-save(href="", title="{{'COMMON.SAVE' | translate}}") + use(xlink:href="#icon-save") diff --git a/app/partials/common/components/watchers.jade b/app/partials/common/components/watchers.jade index fcbe398d..fb5d9771 100644 --- a/app/partials/common/components/watchers.jade +++ b/app/partials/common/components/watchers.jade @@ -10,11 +10,11 @@ span <%- watcher.full_name_display %> <% if(isEditable){ %> - a.icon.icon-delete.js-delete-watcher( - href="" + svg.icon.icon-trash.js-delete-watcher.delete-watcher( data-watcher-id!="<%- watcher.id %>" title="{{'COMMON.WATCHERS.DELETE' | translate}}" ) + use(xlink:href="#icon-trash") <% }; %> <% } %> <% }); %> diff --git a/app/partials/common/components/wysiwyg.jade b/app/partials/common/components/wysiwyg.jade index 3d90e44a..4c10f363 100644 --- a/app/partials/common/components/wysiwyg.jade +++ b/app/partials/common/components/wysiwyg.jade @@ -2,5 +2,6 @@ mixin wysihelp div.wysiwyg-help span.drag-drop-help Attach files by dragging & dropping on the textarea above. a.help-markdown(href="https://taiga.io/support/taiga-markdown-syntax/", target="_blank", title="{{'COMMON.WYSIWYG.MARKDOWN_HELP' | translate}}") - span.icon.icon-help + svg.icon.icon-question + use(xlink:href="#icon-question") span(translate="COMMON.WYSIWYG.MARKDOWN_HELP") diff --git a/app/partials/common/estimation/us-estimation-points-per-role.jade b/app/partials/common/estimation/us-estimation-points-per-role.jade index 86bf489c..298960c0 100644 --- a/app/partials/common/estimation/us-estimation-points-per-role.jade +++ b/app/partials/common/estimation/us-estimation-points-per-role.jade @@ -3,7 +3,8 @@ ul.points-per-role li.ticket-role-points.total(class!="<% if(editable){ %>clickable<% } %>", data-role-id!="<%- role.id %>", title!="<%- role.name %>") span.points <%- role.points %> - span.icon-arrow-bottom + svg.icon.icon-arrow-down + use(xlink:href="#icon-arrow-down") span.role <%- role.name %> <% }); %> diff --git a/app/partials/common/estimation/us-estimation-total.jade b/app/partials/common/estimation/us-estimation-total.jade index 235494bb..013bd495 100644 --- a/app/partials/common/estimation/us-estimation-total.jade +++ b/app/partials/common/estimation/us-estimation-total.jade @@ -1,5 +1,6 @@ a.us-points(href="", title!="<%= title %>", class!="<% if (!editable) { %>not-clickable<% } %>") span.points-value <%= text %> <% if (editable) { %> - span.icon.icon-arrow-bottom(tg-check-permission="modify_us") + svg.icon.icon-arrow-down(tg-check-permission="modify_us") + use(xlink:href="#icon-arrow-down") <% } %> diff --git a/app/partials/common/history/history-activity.jade b/app/partials/common/history/history-activity.jade index a49c3fb6..7a7ce6ff 100644 --- a/app/partials/common/history/history-activity.jade +++ b/app/partials/common/history/history-activity.jade @@ -1,4 +1,4 @@ -div(class!="activity-single <%- mode %>") +.activity-single(class!="<%- mode %>") .activity-user a.avatar(href!="<%- userProfileUrl %>", title!="<%- userFullName %>") img(src!="<%- avatar %>", alt!="<%- userFullName %>") @@ -18,11 +18,11 @@ div(class!="activity-single <%- mode %>") .comment.wysiwyg(ng-non-bindable) | <%= comment %> <% if (!deleteCommentDate && mode !== "activity" && canDeleteComment) { %> - a.icon.icon-delete.comment-delete( - href="" + svg.icon.icon-trash.comment-delete( data-activity-id!="<%- activityId %>" title!="<%- deleteCommentActionTitle %>" ) + use(xlink:href="#icon-trash") <% } %> <% } %> @@ -31,7 +31,8 @@ div(class!="activity-single <%- mode %>") <% if (mode != "activity") { %> a.changes-title(href="", title="{{'ACTIVITY.SHOW_ACTIVITY' | translate}}") span <%- changesText %> - span.icon.icon-arrow-up + svg.icon.icon-arrow-right + use(xlink:href="#icon-arrow-right") <% } %> <% _.each(changes, function(change) { %> | <%= change %> diff --git a/app/partials/common/history/history-base.jade b/app/partials/common/history/history-base.jade index ceef5a7c..3d8f1874 100644 --- a/app/partials/common/history/history-base.jade +++ b/app/partials/common/history/history-base.jade @@ -6,13 +6,15 @@ section.history <% if (commentsVisible) { %> li a(href="#", class="active", data-section-class="history-comments") - span.icon.icon-comment + svg.icon.icon-writer + use(xlink:href="#icon-writer") span.tab-title(translate="COMMENTS.TITLE") <% } %> <% if (historyVisible) { %> li a(href="#", data-section-class="history-activity") - span.icon.icon-issues + svg.icon.icon-timeline + use(xlink:href="#icon-timeline") span.tab-title(translate="ACTIVITY.TITLE") <% } %> <% } %> diff --git a/app/partials/common/history/history-deleted-comment.jade b/app/partials/common/history/history-deleted-comment.jade index fbbcd29d..51510e55 100644 --- a/app/partials/common/history/history-deleted-comment.jade +++ b/app/partials/common/history/history-deleted-comment.jade @@ -13,6 +13,7 @@ data-activity-id!="<%- activityId %>" title="{{ 'COMMENTS.RESTORE' | translate }}" ) - span.icon.icon-reload + svg.icon.icon-reload + use(xlink:href="#icon-reload") span(translate="COMMENTS.RESTORE") <% } %> diff --git a/app/partials/common/lightbox-feedback.jade b/app/partials/common/lightbox-feedback.jade index d985a8a6..f46019c6 100644 --- a/app/partials/common/lightbox-feedback.jade +++ b/app/partials/common/lightbox-feedback.jade @@ -1,5 +1,5 @@ -a.close(href="", title="{{'COMMON.CLOSE' | translate}}") - span.icon.icon-delete +svg.close.icon.icon-close(href="", title="{{'COMMON.CLOSE' | translate}}") + use(xlink:href="#icon-close") form h2.title(translate="LIGHTBOX.FEEDBACK.TITLE") fieldset diff --git a/app/partials/common/lightbox/lightbox-assigned-to-users.jade b/app/partials/common/lightbox/lightbox-assigned-to-users.jade index 49c44b9a..78916665 100644 --- a/app/partials/common/lightbox/lightbox-assigned-to-users.jade +++ b/app/partials/common/lightbox/lightbox-assigned-to-users.jade @@ -11,10 +11,11 @@ title!="<%- selected.full_name_display %>" ) | <%-selected.full_name_display %> - a.icon-delete.remove-assigned-to( + svg.icon.icon-close.remove-assigned-to( href="" title="{{'COMMON.ASSIGNED_TO.REMOVE_ASSIGNED' | translate}}" ) + use(xlink:href="#icon-close") <% } %> <% _.each(users, function(user) { %> diff --git a/app/partials/common/lightbox/lightbox-assigned-to.jade b/app/partials/common/lightbox/lightbox-assigned-to.jade index 7f00751d..d97ab443 100644 --- a/app/partials/common/lightbox/lightbox-assigned-to.jade +++ b/app/partials/common/lightbox/lightbox-assigned-to.jade @@ -1,5 +1,6 @@ -a.close(href="", title="close") - span.icon.icon-delete +svg.close.icon.icon-close(href="", title="{{'COMMON.CLOSE' | translate}}") + use(xlink:href="#icon-close") + div.form h2.title(translate="LIGHTBOX.ASSIGNED_TO.SELECT") fieldset diff --git a/app/partials/common/lightbox/lightbox-attachment-preview.jade b/app/partials/common/lightbox/lightbox-attachment-preview.jade index b1b1ebb5..bf401bbf 100644 --- a/app/partials/common/lightbox/lightbox-attachment-preview.jade +++ b/app/partials/common/lightbox/lightbox-attachment-preview.jade @@ -1,6 +1,6 @@ .attachment-preview - a.close(href="", title="{{'COMMON.CLOSE' | translate}}") - span.icon.icon-delete + svg.close.icon.icon-close(href="", title="{{'COMMON.CLOSE' | translate}}") + use(xlink:href="#icon-close") a(href="{{::file.get('url')}}", title="{{::file.get('description')}}", target="_blank", download="{{::file.get('name')}}") - img(src="{{::file.get('url')}}") \ No newline at end of file + img(src="{{::file.get('url')}}") diff --git a/app/partials/common/lightbox/lightbox-block.jade b/app/partials/common/lightbox/lightbox-block.jade index b74ee6d4..d7bd60da 100644 --- a/app/partials/common/lightbox/lightbox-block.jade +++ b/app/partials/common/lightbox/lightbox-block.jade @@ -1,5 +1,5 @@ -a.close(href="", title="{{'COMMON.CLOSE' | translate}}") - span.icon.icon-delete +svg.close.icon.icon-close(href="", title="{{'COMMON.CLOSE' | translate}}") + use(xlink:href="#icon-close") div.form h2.title fieldset diff --git a/app/partials/common/lightbox/lightbox-change-owner.jade b/app/partials/common/lightbox/lightbox-change-owner.jade new file mode 100644 index 00000000..8fe0a128 --- /dev/null +++ b/app/partials/common/lightbox/lightbox-change-owner.jade @@ -0,0 +1,72 @@ +svg.close.icon.icon-close(href="", title="{{'COMMON.CLOSE' | translate}}") + use(xlink:href="#icon-close") + +.form + h2.title(translate="LIGHTBOX.CHANGE_OWNER.TITLE") + fieldset + input( + type="text", + data-maxlength="500", + placeholder="{{'LIGHTBOX.ASSIGNED_TO.SEARCH' | translate}}", + ng-model="vm.q", + ng-change="vm.userSearch()" + ) + + .assigned-to-list + .user-list-single.is-active(ng-if="vm.selected") + .user-list-avatar + a( + href="#" + title="{{'COMMON.ASSIGNED_TO.TITLE' | translate}}" + ) + img(ng-src="{{vm.selected.photo}}") + a.user-list-name( + href="" + title="{{vm.selected.full_name_display}}" + ) {{vm.selected.full_name_display}} + + .user-list-single.ng-animate-disabled( + ng-repeat="user in vm.getUsers()", + ng-click="vm.selectUser(user)" + ) + .user-list-avatar + a( + href="#" + title="{{'COMMON.ASSIGNED_TO.TITLE' | translate}}" + ) + img(ng-src="{{user.photo}}") + a.user-list-name( + href="" + title="{{user.full_name_display}}" + ) {{user.full_name_display}} + + .more-watchers(ng-if="!vm.q.length") + span(translate="COMMON.ASSIGNED_TO.TOO_MANY") + + .add-comment + a( + href="", + class="ng-animate-disabled" + ng-if="!vm.commentOpen", + ng-click="vm.commentOpen = true" + translate="LIGHTBOX.CHANGE_OWNER.ADD_COMMENT" + ) + + fieldset(ng-if="vm.commentOpen") + svg.icon.icon-close( + ng-click="vm.commentOpen = false" + href="", + title="{{'COMMON.CLOSE' | translate}}" + ) + use(xlink:href="#icon-close") + label(translate="LIGHTBOX.CHANGE_OWNER.ADD_COMMENT") + textarea(ng-model="vm.comment") + + button.button-green.submit-button( + tg-loading="vm.loading", + ng-click="vm.submit()", + ng-disabled="!vm.selected", + type="submit", + title="{{'LIGHTBOX.CHANGE_OWNER.BUTTON' | translate}}", + translate="LIGHTBOX.CHANGE_OWNER.BUTTON" + ) diff --git a/app/partials/common/lightbox/lightbox-import-error.jade b/app/partials/common/lightbox/lightbox-import-error.jade new file mode 100644 index 00000000..36273ea6 --- /dev/null +++ b/app/partials/common/lightbox/lightbox-import-error.jade @@ -0,0 +1,97 @@ +a.close( + href="" + title="{{'COMMON.CLOSE' | translate}}" +) + svg.icon.icon-close + use(xlink:href="#icon-close") + +.content(ng-switch="key") + .private-space(ng-switch-when="private-space") + img( + src="/#{v}/svg/icons/project-limit.svg" + ) + + h2.title( + translate="PROJECT.IMPORT.PROJECT_RESTRICTIONS.PRIVATE_PROJECTS_SPACE.TITLE" + translate-values="{{values}}" + ) + p.description( + translate="PROJECT.IMPORT.PROJECT_RESTRICTIONS.PRIVATE_PROJECTS_SPACE.DESC" + translate-values="{{values}}" + ) + + div(ng-switch-when="private-members") + img( + src="/#{v}/svg/icons/block-user.svg" + ) + + h2.title( + translate="PROJECT.IMPORT.PROJECT_RESTRICTIONS.PRIVATE_PROJECTS_MEMBERS.TITLE" + translate-values="{{values}}" + ) + p.description( + translate="PROJECT.IMPORT.PROJECT_RESTRICTIONS.PROJECT_MEMBERS_DESC" + translate-values="{{values}}" + ) + + div(ng-switch-when="private-space-members") + img( + src="/#{v}/svg/icons/multi-block-project.svg" + ) + + h2.title( + translate="PROJECT.IMPORT.PROJECT_RESTRICTIONS.PRIVATE_PROJECTS_SPACE_MEMBERS.TITLE" + translate-values="{{values}}" + ) + p.description( + translate="PROJECT.IMPORT.PROJECT_RESTRICTIONS.PRIVATE_PROJECTS_SPACE_MEMBERS.DESC" + translate-values="{{values}}" + ) + + div(ng-switch-when="public-space") + img( + src="/#{v}/svg/icons/project-limit.svg" + ) + + h2.title( + translate="PROJECT.IMPORT.PROJECT_RESTRICTIONS.PUBLIC_PROJECTS_SPACE.TITLE" + translate-values="{{values}}" + ) + p.description( + translate="PROJECT.IMPORT.PROJECT_RESTRICTIONS.PUBLIC_PROJECTS_SPACE.DESC" + translate-values="{{values}}" + ) + + div(ng-switch-when="public-members") + img( + src="/#{v}/svg/icons/block-user.svg" + ) + + h2.title( + translate="PROJECT.IMPORT.PROJECT_RESTRICTIONS.PUBLIC_PROJECTS_MEMBERS.TITLE" + translate-values="{{values}}" + ) + p.description( + translate="PROJECT.IMPORT.PROJECT_RESTRICTIONS.PROJECT_MEMBERS_DESC" + translate-values="{{values}}" + ) + + div(ng-switch-when="public-space-members") + img( + src="/#{v}/svg/icons/multi-block-project.svg" + ) + + h2.title( + translate="PROJECT.IMPORT.PROJECT_RESTRICTIONS.PUBLIC_PROJECTS_SPACE_MEMBERS.TITLE" + translate-values="{{values}}" + ) + p.description( + translate="PROJECT.IMPORT.PROJECT_RESTRICTIONS.PUBLIC_PROJECTS_SPACE_MEMBERS.DESC" + translate-values="{{values}}" + ) + + div.options + a.button-green( + translate="COMMON.ACCEPT" + ng-click="close()" + ) diff --git a/app/partials/common/lightbox/lightbox-leave-project-warning.jade b/app/partials/common/lightbox/lightbox-leave-project-warning.jade new file mode 100644 index 00000000..51fd7caa --- /dev/null +++ b/app/partials/common/lightbox/lightbox-leave-project-warning.jade @@ -0,0 +1,20 @@ +a.close(href="", title="{{'COMMON.CLOSE' | translate}}") + svg.icon.icon-close(title="{{'COMMON.CLOSE' | translate}}") + use(xlink:href="#icon-close") +div.content + svg.icon.icon-exclamation + use(xlink:href="#icon-exclamation") + + h2.title {{'LIGHTBOX.LEAVE_PROJECT_WARNING.TITLE' | translate}} + + div(ng-if="isCurrentUser") + p {{'LIGHTBOX.LEAVE_PROJECT_WARNING.CURRENT_USER_OWNER.DESC' | translate}} + + a.button-green(tg-nav="project-admin-home:project=project.slug", href="") + span(translate="LIGHTBOX.LEAVE_PROJECT_WARNING.CURRENT_USER_OWNER.BUTTON") + + div(ng-if="!isCurrentUser") + p {{'LIGHTBOX.LEAVE_PROJECT_WARNING.OTHER_USER_OWNER.DESC' | translate}} + + a.button-green(tg-nav="project-admin-home:project=project.slug", href="") + span(translate="LIGHTBOX.LEAVE_PROJECT_WARNING.OTHER_USER_OWNER.BUTTON") diff --git a/app/partials/common/lightbox/lightbox-request-ownership.jade b/app/partials/common/lightbox/lightbox-request-ownership.jade new file mode 100644 index 00000000..54247951 --- /dev/null +++ b/app/partials/common/lightbox/lightbox-request-ownership.jade @@ -0,0 +1,14 @@ +a.close(href="", title="{{'COMMON.CLOSE' | translate}}") + svg.icon.icon-close + use(xlink:href="#icon-close") + +.content + h2.title(translate="ADMIN.PROJECT_PROFILE.REQUEST_OWNERSHIP_CONFIRMATION_TITLE") + p(translate="ADMIN.PROJECT_PROFILE.REQUEST_OWNERSHIP_DESC") + + a.button-green( + href="", + ng-click="request()", + tg-loading="loading" + ) + span(translate="ADMIN.PROJECT_PROFILE.REQUEST_OWNERSHIP_BUTTON") diff --git a/app/partials/common/lightbox/lightbox-users.jade b/app/partials/common/lightbox/lightbox-users.jade index 2c43e246..d6693258 100644 --- a/app/partials/common/lightbox/lightbox-users.jade +++ b/app/partials/common/lightbox/lightbox-users.jade @@ -1,5 +1,5 @@ -a.close(href="", title="{{'COMMON.CLOSE' | translate}}") - span.icon.icon-delete +svg.close.icon.icon-close(href="", title="{{'COMMON.CLOSE' | translate}}") + use(xlink:href="#icon-close") div.form h2.title(translate="COMMON.WATCHERS.ADD") fieldset diff --git a/app/partials/common/tag/lb-tag-line-tags.jade b/app/partials/common/tag/lb-tag-line-tags.jade index fb6be1eb..7f95583e 100644 --- a/app/partials/common/tag/lb-tag-line-tags.jade +++ b/app/partials/common/tag/lb-tag-line-tags.jade @@ -1,5 +1,6 @@ <% _.each(tags, function(tag) { %> span(class="tag", style!="<%- tag.style %>") span.tag-name <%- tag.name %> - a(href="", title="{{ 'COMMON.TAGS.DELETE' | translate }}", class="icon icon-delete") + svg.icon.icon-close.remove-tag(title="{{ 'COMMON.TAGS.DELETE' | translate }}") + use(xlink:href="#icon-close") <% }); %> diff --git a/app/partials/common/tag/lb-tag-line.jade b/app/partials/common/tag/lb-tag-line.jade index 1c06a23e..5fe8414b 100644 --- a/app/partials/common/tag/lb-tag-line.jade +++ b/app/partials/common/tag/lb-tag-line.jade @@ -1,3 +1,8 @@ .tags-container -input(type="text", placeholder="{{'COMMON.TAGS.PLACEHOLDER' | translate}}", class="tag-input") -a(href="", title="{{'COMMON.SAVE' | translate}}", class="save icon icon-floppy hidden") +input.tag-input( + type="text" + placeholder="{{'COMMON.TAGS.PLACEHOLDER' | translate}}" +) +span.save.hidden(title="{{'COMMON.SAVE' | translate}}") + svg.icon.icon-save + use(xlink:href="#icon-save") diff --git a/app/partials/common/tag/tag-line.jade b/app/partials/common/tag/tag-line.jade index 06040a9e..2d205441 100644 --- a/app/partials/common/tag/tag-line.jade +++ b/app/partials/common/tag/tag-line.jade @@ -1,8 +1,11 @@ .tags-container a(href="#", class="add-tag hidden", title="{{'COMMON.TAGS.ADD' | translate}}") - span.icon.icon-plus + svg.icon.icon-add + use(xlink:href="#icon-add") span.add-tag-text(translate="COMMON.TAGS.ADD") span.add-tag-input input(type="text", placeholder="{{'COMMON.TAGS.PLACEHOLDER' | translate}}", class="tag-input hidden") - a(href="", title="{{'COMMON.SAVE' | translate}}", class="save icon icon-floppy hidden") + span.save.hidden(title="{{'COMMON.SAVE' | translate}}") + svg.icon.icon-save + use(xlink:href="#icon-save") diff --git a/app/partials/common/tag/tags-line-tags.jade b/app/partials/common/tag/tags-line-tags.jade index c9b0dbd9..9ea57c69 100644 --- a/app/partials/common/tag/tags-line-tags.jade +++ b/app/partials/common/tag/tags-line-tags.jade @@ -2,6 +2,7 @@ span(class="tag", style!="border-left: 5px solid <%- tag.color %>;") span.tag-name <%- tag.name %> <% if (isEditable) { %> - a(href="", title="{{ 'COMMON.TAGS.DELETE' | translate }}", class="icon icon-delete") + svg.icon.icon-close.remove-tag(title="{{ 'COMMON.TAGS.DELETE' | translate }}") + use(xlink:href="#icon-close") <% } %> <% }); %> diff --git a/app/partials/common/wysiwyg/wysiwyg-markitup-preview.jade b/app/partials/common/wysiwyg/wysiwyg-markitup-preview.jade index a674385d..791c2d2b 100644 --- a/app/partials/common/wysiwyg/wysiwyg-markitup-preview.jade +++ b/app/partials/common/wysiwyg/wysiwyg-markitup-preview.jade @@ -1,5 +1,6 @@ .preview .actions - a(href="#" title="{{'COMMON.WYSIWYG.EDIT_BUTTON' | translate}}" class="icon icon-edit edit") + svg.edit.icon.icon-edit(title="{{'COMMON.WYSIWYG.EDIT_BUTTON' | translate}}") + use(xlink:href="#icon-edit") .content.wysiwyg | <%= data %> diff --git a/app/partials/contrib/user-settings.jade b/app/partials/contrib/user-settings.jade new file mode 100644 index 00000000..2af06472 --- /dev/null +++ b/app/partials/contrib/user-settings.jade @@ -0,0 +1,10 @@ +doctype html + +div.wrapper( + ng-controller="ContribUserSettingsController as ctrl" + ng-init="section='user-settings'" +) + sidebar.menu-secondary.sidebar.settings-nav(tg-user-settings-navigation) + include ../includes/modules/user-settings-menu + + section.main(ng-include="currentPlugin.template") \ No newline at end of file diff --git a/app/partials/custom-attributes/custom-attribute-value-edit.jade b/app/partials/custom-attributes/custom-attribute-value-edit.jade index f6869cba..a62c4f53 100644 --- a/app/partials/custom-attributes/custom-attribute-value-edit.jade +++ b/app/partials/custom-attributes/custom-attribute-value-edit.jade @@ -14,10 +14,13 @@ form.custom-field-single.editable <% } else if (type=="multiline") { %> textarea#custom-field-value(name="value") <%- value %> <% } else if (type=="date") { %> - input#custom-field-value(name="value", type="text", value!="<%- value %>") + input#custom-field-value(name="value", type="text", data-pikaday, value!="<%- value %>") + <% } else if (type=="url") { %> + input#custom-field-value(name="value", type="url", data-type="url", value!="<%- value %>") <% } else { %> input#custom-field-value(name="value", type="text", value!="<%- value %>") <% } %> div.custom-field-options - a.icon.icon-floppy(href="", title="{{'COMMON.CUSTOM_ATTRIBUTES.SAVE' | translate}}") + svg.icon.icon-save.js-save-description(title="{{'COMMON.CUSTOM_ATTRIBUTES.SAVE' | translate}}") + use(xlink:href="#icon-save") diff --git a/app/partials/custom-attributes/custom-attribute-value.jade b/app/partials/custom-attributes/custom-attribute-value.jade index f7ac5620..51e7bfeb 100644 --- a/app/partials/custom-attributes/custom-attribute-value.jade +++ b/app/partials/custom-attributes/custom-attribute-value.jade @@ -1,5 +1,5 @@ -div.custom-field-single - div.custom-field-data +.custom-field-single + .custom-field-data span.custom-field-name <%- name %> <% if (description){ %> @@ -7,11 +7,17 @@ div.custom-field-single <%- description %> <% } %> - div.custom-field-value.js-value-view-mode + .custom-field-value.js-value-view-mode span + <% if (type=="url") { %> + a(href!="<%- value %>") + <%- value %> + <% } else { %> <%- value %> + <% } %> <% if (isEditable) { %> - div.custom-field-options - a.icon.icon-edit(href="", title="{{'COMMON.CUSTOM_ATTRIBUTES.EDIT' | translate}}") + .custom-field-options + svg.icon.icon-edit.js-edit-description(title="{{'COMMON.CUSTOM_ATTRIBUTES.EDIT' | translate}}") + use(xlink:href="#icon-edit") <% } %> diff --git a/app/partials/custom-attributes/custom-attributes-values.jade b/app/partials/custom-attributes/custom-attributes-values.jade index 3c34c6e1..09d7ecf9 100644 --- a/app/partials/custom-attributes/custom-attributes-values.jade +++ b/app/partials/custom-attributes/custom-attributes-values.jade @@ -2,6 +2,7 @@ section.duty-custom-fields(ng-show="ctrl.customAttributes.length") div.custom-fields-header span(translate="COMMON.CUSTOM_ATTRIBUTES.CUSTOM_FIELDS") // Remove .open class on click on this button in both .icon and .custom-fields-body to close - a.icon.icon-arrow-bottom(class!="<% if (!collapsed) { %>open<% } %>") + svg.icon.icon-arrow-down(class!="<% if (!collapsed) { %>open<% } %>") + use(xlink:href="#icon-arrow-down") div.custom-fields-body(class!="<% if (!collapsed) { %>open<% } %>") div(ng-repeat="att in ctrl.customAttributes", tg-custom-attribute-value="ctrl.getAttributeValue(att)", required-edition-perm!="<%- requiredEditionPerm %>") diff --git a/app/partials/error/permission-denied.jade b/app/partials/error/permission-denied.jade index fa1333fc..f90e3561 100644 --- a/app/partials/error/permission-denied.jade +++ b/app/partials/error/permission-denied.jade @@ -2,8 +2,14 @@ doctype html div.error-main div.error-container - object.logo-svg(type="image/svg+xml", data="/svg/logo.svg") - img(src="/#{v}/images/logo.png", alt="TAIGA") + img.logo-svg( + ng-src="/#{v}/svg/logo.svg" + alt="TAIGA" + ) h1.logo(translate="ERROR.PERMISSION_DENIED") p.error-text(translate="ERROR.PERMISSION_DENIED_TEXT") - a(href="/", title="", translate="COMMON.GO_HOME") + a( + href="/" + title="" + translate="COMMON.GO_HOME" + ) diff --git a/app/partials/includes/components/addnewtask.jade b/app/partials/includes/components/addnewtask.jade index fd25ed2d..6de3e427 100644 --- a/app/partials/includes/components/addnewtask.jade +++ b/app/partials/includes/components/addnewtask.jade @@ -1,6 +1,14 @@ -a.icon.icon-plus(tg-check-permission="add_task", - href="", title="{{'TASKBOARD.TITLE_ACTION_ADD' | translate}}", - ng-click="ctrl.addNewTask('standard', us)") -a.icon.icon-bulk(tg-check-permission="add_task", - href="", title="{{'TASKBOARD.TITLE_ACTION_ADD_BULK' | translate}}", - ng-click="ctrl.addNewTask('bulk', us)") +svg.icon.icon-add( + tg-check-permission="add_task" + href="" + title="{{'TASKBOARD.TITLE_ACTION_ADD' | translate}}" + ng-click="ctrl.addNewTask('standard', us)" +) + use(xlink:href="#icon-add") +svg.icon.icon-bulk( + tg-check-permission="add_task" + href="" + title="{{'TASKBOARD.TITLE_ACTION_ADD_BULK' | translate}}" + ng-click="ctrl.addNewTask('bulk', us)" +) + use(xlink:href="#icon-bulk") diff --git a/app/partials/includes/components/addnewus.jade b/app/partials/includes/components/addnewus.jade index 52f59b9a..27a9d870 100644 --- a/app/partials/includes/components/addnewus.jade +++ b/app/partials/includes/components/addnewus.jade @@ -6,4 +6,5 @@ div.new-us a.button-bulk(href="", title="{{'US.ADD_BULK' | translate}}", ng-click="ctrl.addNewUs('bulk')", tg-check-permission="add_us") - span.icon.icon-bulk + svg.icon.icon-bulk + use(xlink:href="#icon-bulk") diff --git a/app/partials/includes/components/backlog-row.jade b/app/partials/includes/components/backlog-row.jade index 99684c1b..e564a31b 100644 --- a/app/partials/includes/components/backlog-row.jade +++ b/app/partials/includes/components/backlog-row.jade @@ -13,7 +13,8 @@ div.row.us-item-row( ng-class="{'inactive': !us.total_voters, 'is-voted': us.is_voter}" title="{{ 'COMMON.VOTE_BUTTON.COUNTER_TITLE'|translate:{total:us.total_voters||0}:'messageformat' }}" ) - span.icon.icon-caret-up + svg.icon.icon-upvote + use(xlink:href="#icon-upvote") span {{ ::us.total_voters }} div.user-stories div.tags-block(tg-colorize-tags="us.tags", tg-colorize-tags-type="backlog") @@ -27,25 +28,33 @@ div.row.us-item-row( span(tg-bo-ref="us.ref") span(ng-bind="us.subject") div.us-settings - a.icon.icon-edit( + a.edit-story( href="" tg-check-permission="modify_us" ng-click="ctrl.editUserStory(us.project, us.ref, $event)" title="{{'COMMON.EDIT' | translate}}" ) - a.icon.icon-delete( + svg.icon.icon-edit + use(xlink:href="#icon-edit") + + a.icon-delete( href="" tg-check-permission="delete_us" ng-click="ctrl.deleteUserStory(us)" title="{{'COMMON.DELETE' | translate}}" ) + svg.icon.icon-trash + use(xlink:href="#icon-trash") div.status(tg-us-status="us" on-update="ctrl.updateUserStoryStatus()") a.us-status(href="", title="{{'BACKLOG.STATUS_NAME' | translate}}") span.us-status-bind - span.icon.icon-arrow-bottom(tg-check-permission="modify_us") + svg.icon.icon-arrow-down(tg-check-permission="modify_us") + use(xlink:href="#icon-arrow-down") div.points(tg-backlog-us-points="us") a.us-points(href="", title="{{'COMMON.FIELDS.POINTS' | translate}}") - a.icon.icon-drag-v(tg-check-permission="modify_us", href="", title="{{'COMMON.DRAG' | translate}}") + a(tg-check-permission="modify_us", href="", title="{{'COMMON.DRAG' | translate}}") + svg.icon.icon-drag + use(xlink:href="#icon-drag") diff --git a/app/partials/includes/components/beta.jade b/app/partials/includes/components/beta.jade deleted file mode 100644 index 647d2108..00000000 --- a/app/partials/includes/components/beta.jade +++ /dev/null @@ -1 +0,0 @@ -img.beta(src="/#{v}/images/beta.png", title="{{'COMMON.BETA' | translate}}") diff --git a/app/partials/includes/components/notification-message.jade b/app/partials/includes/components/notification-message.jade index 82b3ab05..aae6172b 100644 --- a/app/partials/includes/components/notification-message.jade +++ b/app/partials/includes/components/notification-message.jade @@ -11,19 +11,22 @@ div.notification-message.notification-message-success div.text - h4.warning(translate="NOTIFICATION.OK") - p(translate="NOTIFICATION.SAVED") + h4.warning + p div.notification-message.notification-message-error - div.icon.icon-notification-error + svg.icon.icon-error + use(xlink:href="#icon-error") div.text - h4.warning(translate="NOTIFICATION.WARNING") - p(translate="NOTIFICATION.WARNING_TEXT") - a.icon.icon-delete(href="", title="{{'NOTIFICATION.CLOSE' | translate}}") + h4.warning + p + svg.icon.icon-close(href="", title="{{'NOTIFICATION.CLOSE' | translate}}") + use(xlink:href="#icon-close") div.notification-light.notification-message-light-error div.text - h4.warning(translate="NOTIFICATION.WARNING") - p(translate="NOTIFICATION.WARNING_TEXT") + h4.warning + p a.close(href="", title="{{'NOTIFICATION.CLOSE' | translate}}") - include ../../../svg/remove.svg + svg.icon.icon-close + use(xlink:href="#icon-close") diff --git a/app/partials/includes/components/sprint-summary.jade b/app/partials/includes/components/sprint-summary.jade index 5fbe8e4e..87244b25 100644 --- a/app/partials/includes/components/sprint-summary.jade +++ b/app/partials/includes/components/sprint-summary.jade @@ -13,7 +13,8 @@ div.summary.large-summary span.description(translate="BACKLOG.SPRINT_SUMMARY.COMPLETED_POINTS") div.summary-stats - span.icon.icon-bulk + svg.icon.icon-bulk + use(xlink:href="#icon-bulk") span.number(ng-bind="stats.openTasks|default:'--'") span.description(translate="BACKLOG.SPRINT_SUMMARY.OPEN_TASKS") div.summary-stats @@ -21,9 +22,11 @@ div.summary.large-summary span.description(translate="BACKLOG.SPRINT_SUMMARY.CLOSED_TASKS") div.summary-stats(title="{{'COMMON.IOCAINE_TEXT' | translate}}") - span.icon.icon-iocaine + svg.icon.icon-iocaine + use(xlink:href="#icon-iocaine") span.number(ng-bind="stats.iocaine_doses|default:'--'") span.description(translate="BACKLOG.SPRINT_SUMMARY.IOCAINE_DOSES") div.stats.toggle-analytics-visibility(title="{{'BACKLOG.SPRINT_SUMMARY.SHOW_STATISTICS_TITLE' | translate}}") - include ../../../svg/graph.svg + svg.icon.icon-graph + use(xlink:href="#icon-graph") diff --git a/app/partials/includes/components/summary.jade b/app/partials/includes/components/summary.jade index c1f9620c..282f43e5 100644 --- a/app/partials/includes/components/summary.jade +++ b/app/partials/includes/components/summary.jade @@ -22,4 +22,5 @@ div.summary title="{{'BACKLOG.SPRINT_SUMMARY.TOGGLE_BAKLOG_GRAPH' | translate}}", ng-if="!showGraphPlaceholder" ) - include ../../../svg/graph.svg + svg.icon.icon-graph + use(xlink:href="#icon-graph") diff --git a/app/partials/includes/components/taskboard-task.jade b/app/partials/includes/components/taskboard-task.jade index dd34369e..4716a763 100644 --- a/app/partials/includes/components/taskboard-task.jade +++ b/app/partials/includes/components/taskboard-task.jade @@ -1,11 +1,18 @@ div.taskboard-tagline(tg-colorize-tags="task.tags", tg-colorize-tags-type="taskboard") div.taskboard-task-inner div.taskboard-user-avatar(tg-taskboard-user-avatar, users="usersById", task="task", project="project", ng-class="{iocaine: task.is_iocaine}") - span.icon.icon-iocaine(ng-if="task.is_iocaine", title="{{'COMMON.IOCAINE_TEXT' | translate}}") + svg.icon.icon-iocaine( + ng-if="task.is_iocaine" + title="{{'COMMON.IOCAINE_TEXT' | translate}}" + ) + use(xlink:href="#icon-iocaine") p.taskboard-text a.task-assigned(href="", title="{{'TASKBOARD.TITLE_ACTION_ASSIGN' | translate}}") span.task-num(tg-bo-ref="task.ref") a.task-name(href="", title="#{{ ::task.ref }} {{ ::task.subject }}", ng-bind="task.subject", tg-nav="project-tasks-detail:project=project.slug,ref=task.ref") - a.icon.icon-edit(tg-check-permission="modify_task", - href="", title="{{'TASKBOARD.TITLE_ACTION_EDIT' | translate}}") + svg.icon.icon-edit( + tg-check-permission="modify_task" + title="{{'TASKBOARD.TITLE_ACTION_EDIT' | translate}}" + ) + use(xlink:href="#icon-edit") diff --git a/app/partials/includes/modules/admin/admin-custom-attributes.jade b/app/partials/includes/modules/admin/admin-custom-attributes.jade index 353ea45e..073dcbe5 100644 --- a/app/partials/includes/modules/admin/admin-custom-attributes.jade +++ b/app/partials/includes/modules/admin/admin-custom-attributes.jade @@ -22,7 +22,8 @@ section.custom-fields-table.basic-table div(ng-repeat="attr in customAttributes track by attr.id", tg-bind-scope) form.js-form(tg-bind-scope) div.row.single-custom-field.js-view-custom-field - span.icon.icon-drag-v + svg.icon.icon-drag + use(xlink:href="#icon-drag") div.custom-name span {{ attr.name }} div.custom-description @@ -32,16 +33,19 @@ section.custom-fields-table.basic-table span(ng-switch-default, translate="ADMIN.CUSTOM_FIELDS.FIELD_TYPE_TEXT") span(ng-switch-when="multiline", translate="ADMIN.CUSTOM_FIELDS.FIELD_TYPE_MULTI") span(ng-switch-when="date", translate="ADMIN.CUSTOM_FIELDS.FIELD_TYPE_DATE") + span(ng-switch-when="url", translate="ADMIN.CUSTOM_FIELDS.FIELD_TYPE_URL") div.custom-options div.custom-options-wrapper - a.js-edit-custom-field-button.icon.icon-edit( + svg.js-edit-custom-field-button.icon.icon-edit( href="" title="{{'ADMIN.CUSTOM_ATTRIBUTES.EDIT' | translate}}" ) - a.js-delete-custom-field-button.icon.icon-delete( + use(xlink:href="#icon-edit") + svg.js-delete-custom-field-button.icon.icon-trash( href="" title="{{'ADMIN.CUSTOM_ATTRIBUTES.DELETE' | translate}}" ) + use(xlink:href="#icon-trash") div.row.single-custom-field.js-edit-custom-field.hidden fieldset.custom-name @@ -67,14 +71,16 @@ section.custom-fields-table.basic-table ) fieldset.custom-options div.custom-options-wrapper - a.js-update-custom-field-button.icon.icon-floppy( + svg.js-update-custom-field-button.icon.icon-save( href="" title="{{'ADMIN.CUSTOM_ATTRIBUTES.ACTION_UPDATE' | translate}}" ) - a.js-cancel-edit-custom-field-button.icon.icon-delete( + use(xlink:href="#icon-save") + svg.js-cancel-edit-custom-field-button.icon.icon-close( href="" title="{{'ADMIN.CUSTOM_ATTRIBUTES.ACTION_CANCEL_EDITION' | translate}}" ) + use(xlink:href="#icon-close") form.row.single-custom-field.js-new-custom-field.hidden fieldset.custom-name @@ -102,11 +108,13 @@ section.custom-fields-table.basic-table fieldset.custom-options div.custom-options-wrapper - a.js-create-custom-field-button.icon.icon-floppy( + svg.js-create-custom-field-button.icon.icon-save( href="" title="{{'ADMIN.CUSTOM_ATTRIBUTES.SAVE_TITLE' | translate}}" ) - a.js-cancel-new-custom-field-button.icon.icon-delete( + use(xlink:href="#icon-save") + svg.js-cancel-new-custom-field-button.icon.icon-trash( href="" title="{{'ADMIN.CUSTOM_ATTRIBUTES.CANCEL_TITLE' | translate}}" ) + use(xlink:href="#icon-trash") diff --git a/app/partials/includes/modules/admin/project-points.jade b/app/partials/includes/modules/admin/project-points.jade index bb991265..6189a3d7 100644 --- a/app/partials/includes/modules/admin/project-points.jade +++ b/app/partials/includes/modules/admin/project-points.jade @@ -18,7 +18,8 @@ section.project-values-table div(ng-repeat="value in values track by value.id", tg-bind-scope) form(tg-bind-scope) div.project-values-row.row.table-main.visualization - span.icon.icon-drag-v + svg.icon.icon-drag + use(xlink:href="#icon-drag") div.project-values-name span {{ value.name }} @@ -27,8 +28,10 @@ section.project-values-table span {{ value.value }} div.project-values-settings - a.edit-value.icon.icon-edit(href="", title="{{'ADMIN.POINTS.TITLE_ACTION_EDIT_VALUE' | translate}}") - a.delete-value.icon.icon-delete(href="", title="{{'ADMIN.POINTS.TITLE_ACTION_DELETE_VALUE' | translate}}") + svg.edit-value.icon.icon-edit(title="{{'ADMIN.POINTS.TITLE_ACTION_EDIT_VALUE' | translate}}") + use(xlink:href="#icon-edit") + svg.delete-value.icon.icon-trash(title="{{'ADMIN.POINTS.TITLE_ACTION_DELETE_VALUE' | translate}}") + use(xlink:href="#icon-trash") div.project-values-row.row.table-main.edition.hidden div.project-values-name @@ -38,19 +41,33 @@ section.project-values-table input(name="value", type="text", placeholder="{{'COMMON.FIELDS.VALUE' | translate}}", ng-model="value.value", data-type="number") div.project-values-settings - a.save.icon.icon-floppy(href="", title="{{'COMMON.SAVE' | translate}}") - a.cancel.icon.icon-delete(href="", title="{{'COMON.CANCEL' | translate}}") + svg.save.icon.icon-save(title="{{'COMMON.SAVE' | translate}}") + use(xlink:href="#icon-save") + svg.cancel.icon.icon-close(href="", title="{{'COMON.CANCEL' | translate}}") + use(xlink:href="#icon-close") form div.project-values-row.new-value.hidden div.project-values-name - input(name="name", type="text", placeholder="{{'COMMON.FIELDS.NAME' | translate}}", ng-model="newValue.name", - data-required="true") + input( + name="name" + type="text" + placeholder="{{'COMMON.FIELDS.NAME' | translate}}" + ng-model="newValue.name" + data-required="true" + ) div.project-values-value - input("name=value", type="text", placeholder="{{'COMMON.FIELDS.VALUE' | translate}}", ng-model="newValue.value", - data-type="number") + input( + name="value" + type="text" + placeholder="{{'COMMON.FIELDS.VALUE' | translate}}" + ng-model="newValue.value" + data-type="number" + ) div.project-values-settings - a.add-new.icon.icon-floppy(href="", title="{{'COMMON.ADD' | translate}}") - a.delete-new.icon.icon-delete(href="", title="{{'COMMON.CANCEL' | translate}}") + svg.add-new.icon.icon-save(title="{{'COMMON.ADD' | translate}}") + use(xlink:href="#icon-save") + svg.delete-new.icon.icon-trash(title="{{'COMMON.CANCEL' | translate}}") + use(xlink:href="#icon-trash") diff --git a/app/partials/includes/modules/admin/project-status.jade b/app/partials/includes/modules/admin/project-status.jade index 40c5c799..1540413d 100644 --- a/app/partials/includes/modules/admin/project-status.jade +++ b/app/partials/includes/modules/admin/project-status.jade @@ -17,7 +17,8 @@ section.colors-table.admin-status-table div(ng-repeat="value in values", tg-bind-scope) form(tg-bind-scope) div.row.table-main.visualization - span.icon.icon-drag-v + svg.icon.icon-drag + use(xlink:href="#icon-drag") div.color-column div.current-color(ng-style="{background: value.color}") @@ -28,43 +29,75 @@ section.colors-table.admin-status-table span {{ value.slug }} div.is-closed-column - div.icon.icon-check-square(ng-show="value.is_closed") + svg.icon.icon-check(ng-show="value.is_closed") + use(xlink:href="#icon-check") div.options-column - a.edit-value.icon.icon-edit(href="", title="{{'ADMIN.COMMON.TITLE_ACTION_EDIT_VALUE' | translate}}") - a.delete-value.icon.icon-delete(href="", title="{{'ADMIN.COMMON.TITLE_ACTION_DELETE_VALUE' | translate}}") + svg.edit-value.icon.icon-edit(title="{{'ADMIN.COMMON.TITLE_ACTION_EDIT_VALUE' | translate}}") + use(xlink:href="#icon-edit") + svg.delete-value.icon.icon-trash(title="{{'ADMIN.COMMON.TITLE_ACTION_DELETE_VALUE' | translate}}") + use(xlink:href="#icon-trash") div.row.table-main.edition.hidden - div.color-column(tg-color-selection, ng-model="value") + div.color-column( + tg-color-selection + ng-model="value" + ) div.current-color(ng-style="{background: value.color}") include ../../components/select-color div.status-name - input(name="name", type="text", placeholder="{{'ADMIN.STATUS.PLACEHOLDER_WRITE_STATUS_NAME' | translate}}", - ng-model="value.name", data-required="true", data-maxlength="255") + input( + name="name" + type="text" + placeholder="{{'ADMIN.STATUS.PLACEHOLDER_WRITE_STATUS_NAME' | translate}}" + ng-model="value.name" + data-required="true" + data-maxlength="255" + ) div.is-closed-column - select(name="is_closed", ng-model="value.is_closed", data-required="true", - ng-options="e.id as e.name | translate for e in [{'id':true, 'name':'COMMON.YES'},{'id':false, 'name': 'COMMON.NO'}]") + select( + name="is_closed" + ng-model="value.is_closed" + data-required="true" + ng-options="e.id as e.name | translate for e in [{'id':true, 'name':'COMMON.YES'},{'id':false, 'name': 'COMMON.NO'}]") div.options-column - a.save.icon.icon-floppy(href="", title="{{'COMMON.SAVE' | translate}}") - a.cancel.icon.icon-delete(href="", title="{{'COMMON.CANCEL' | translate}}") + svg.save.icon.icon-save(title="{{'COMMON.SAVE' | translate}}") + use(xlink:href="#icon-save") + svg.cancel.icon.icon-close(title="{{'COMMON.CANCEL' | translate}}") + use(xlink:href="#icon-close") form div.row.table-main.new-value.hidden - div.color-column(tg-color-selection, ng-model="newValue") + div.color-column( + tg-color-selection + ng-model="newValue" + ) div.current-color(ng-style="{background: newValue.color}") include ../../components/select-color div.status-name - input(name="name", type="text", placeholder="{{'ADMIN.STATUS.PLACEHOLDER_WRITE_STATUS_NAME' | translate}}", - ng-model="newValue.name", data-required="true", data-maxlength="255") + input( + name="name" + type="text" + placeholder="{{'ADMIN.STATUS.PLACEHOLDER_WRITE_STATUS_NAME' | translate}}" + ng-model="newValue.name" + data-required="true" + data-maxlength="255" + ) div.is-closed-column - select(name="is_closed", ng-model="newValue.is_closed", data-required="true", - ng-options="e.id as e.name | translate for e in [{'id':true, 'name': 'COMMON.YES'},{'id':false, 'name': 'COMMON.NO'}]") + select( + name="is_closed" + ng-model="newValue.is_closed" + data-required="true" + ng-options="e.id as e.name | translate for e in [{'id':true, 'name': 'COMMON.YES'},{'id':false, 'name': 'COMMON.NO'}]" + ) div.options-column - a.add-new.icon.icon-floppy(href="", title="{{'COMMON.ADD' | translate}}") - a.delete-new.icon.icon-delete(href="", title="{{'COMMON.CANCEL' | translate}}") + svg.add-new.icon.icon-save(title="{{'COMMON.ADD' | translate}}") + use(xlink:href="#icon-save") + svg.delete-new.icon.icon-close(title="{{'COMMON.CANCEL' | translate}}") + use(xlink:href="#icon-close") diff --git a/app/partials/includes/modules/admin/project-types.jade b/app/partials/includes/modules/admin/project-types.jade index cd69b129..12a53bce 100644 --- a/app/partials/includes/modules/admin/project-types.jade +++ b/app/partials/includes/modules/admin/project-types.jade @@ -16,7 +16,8 @@ section.colors-table div(ng-repeat="value in values", tg-bind-scope) form(tg-bind-scope) div.row.table-main.visualization - span.icon.icon-drag-v + svg.icon.icon-drag + use(xlink:href="#icon-drag") div.color-column div.current-color(ng-style="{background: value.color}") @@ -25,32 +26,56 @@ section.colors-table span {{ value.name }} div.options-column - a.edit-value.icon.icon-edit(href="", title="{{'ADMIN.COMMON.TITLE_ACTION_EDIT_VALUE' | translate}}") - a.delete-value.icon.icon-delete(href="", title="{{'ADMIN.COMMON.TITLE_ACTION_DELETE_VALUE' | translate}}") + svg.edit-value.icon.icon-edit(title="{{'ADMIN.COMMON.TITLE_ACTION_EDIT_VALUE' | translate}}") + use(xlink:href="#icon-edit") + svg.delete-value.icon.icon-trash(title="{{'ADMIN.COMMON.TITLE_ACTION_DELETE_VALUE' | translate}}") + use(xlink:href="#icon-trash") div.row.table-main.edition.hidden - div.color-column(tg-color-selection, ng-model="value") + div.color-column( + tg-color-selection + ng-model="value" + ) div.current-color(ng-style="{background: value.color}") include ../../components/select-color div.status-name - input(name="name", type="text", placeholder="{{'ADMIN.TYPES.PLACEHOLDER_WRITE_NAME' | translate}}", - ng-model="value.name", data-required="true", data-maxlength="255") + input( + name="name" + type="text" + placeholder="{{'ADMIN.TYPES.PLACEHOLDER_WRITE_NAME' | translate}}", + ng-model="value.name" + data-required="true" + data-maxlength="255" + ) div.options-column - a.save.icon.icon-floppy(href="", title="{{'COMMON.SAVE' | translate}}") - a.cancel.icon.icon-delete(href="", title="{{'COMMON.CANCEL' | translate}}") + svg.save.icon.icon-save(title="{{'COMMON.SAVE' | translate}}") + use(xlink:href="#icon-save") + svg.cancel.icon.icon-trash(title="{{'COMMON.CANCEL' | translate}}") + use(xlink:href="#icon-trash") form div.row.table-main.new-value.hidden - div.color-column(tg-color-selection, ng-model="newValue") + div.color-column( + tg-color-selection + ng-model="newValue" + ) div.current-color(ng-style="{background: newValue.color}") include ../../components/select-color div.status-name - input(name="name", type="text", placeholder="{{'ADMIN.TYPES.PLACEHOLDER_WRITE_NAME' | translate}}", - ng-model="newValue.name", data-required="true", data-maxlength="255") + input( + name="name" + type="text" + placeholder="{{'ADMIN.TYPES.PLACEHOLDER_WRITE_NAME' | translate}}", + ng-model="newValue.name" + data-required="true" + data-maxlength="255" + ) div.options-column - a.add-new.icon.icon-floppy(href="", title="{{'COMMON.ADD' | translate}}") - a.delete-new.icon.icon-delete(href="", title="{{'COMMON.CANCEL' | translate}}") + svg.add-new.icon.icon-save(title="{{'COMMON.ADD' | translate}}") + use(xlink:href="#icon-save") + svg.delete-new.icon.icon-trash(title="{{'COMMON.CANCEL' | translate}}") + use(xlink:href="#icon-trash") diff --git a/app/partials/includes/modules/admin/project-us-status.jade b/app/partials/includes/modules/admin/project-us-status.jade index cf583523..892990d8 100644 --- a/app/partials/includes/modules/admin/project-us-status.jade +++ b/app/partials/includes/modules/admin/project-us-status.jade @@ -21,7 +21,8 @@ section.project-us-status div(ng-repeat="value in values", tg-bind-scope) form(tg-bind-scope) div.row.table-main.visualization - span.icon.icon-drag-v + svg.icon.icon-drag + use(xlink:href="#icon-drag") div.color-column div.current-color(ng-style="{background: value.color}") @@ -33,44 +34,69 @@ section.project-us-status span {{ value.slug }} div.is-closed-column - div.icon.icon-check-square(ng-show="value.is_closed") + svg.icon.icon-check(ng-show="value.is_closed") + use(xlink:href="#icon-check") div.is-archived-column - div.icon.icon-check-square(ng-show="value.is_archived") + svg.icon.icon-check(ng-show="value.is_archived") + use(xlink:href="#icon-check") div.status-wip-limit span(ng-hide="value.is_archived") {{ value.wip_limit }} div.options-column - a.edit-value.icon.icon-edit(href="", title="{{'ADMIN.COMMON.TITLE_ACTION_EDIT_VALUE' | translate}}") - a.delete-value.icon.icon-delete(href="", title="{{'ADMIN.COMMON.TITLE_ACTION_DELETE_VALUE' | translate}}") + svg.edit-value.icon.icon-edit(title="{{'ADMIN.COMMON.TITLE_ACTION_EDIT_VALUE' | translate}}") + use(xlink:href="#icon-edit") + svg.delete-value.icon.icon-trash(title="{{'ADMIN.COMMON.TITLE_ACTION_DELETE_VALUE' | translate}}") + use(xlink:href="#icon-trash") div.row.table-main.edition.hidden - div.color-column(tg-color-selection, ng-model="value") - div.current-color(ng-style="{background: value.color}") + .color-column(tg-color-selection, ng-model="value") + .current-color(ng-style="{background: value.color}") include ../../components/select-color - div.status-name - input(name="name", type="text", placeholder="{{'ADMIN.US_STATUS.PLACEHOLDER_WRITE_NAME' | translate}}", - ng-model="value.name", data-required="true", data-maxlength="255") + .status-name + input( + name="name" + type="text" + placeholder="{{'ADMIN.US_STATUS.PLACEHOLDER_WRITE_NAME' | translate}}", + ng-model="value.name" + data-required="true" + data-maxlength="255" + ) - div.is-closed-column - select(name="is_closed", ng-model="value.is_closed", data-required="true", - ng-options="e.id as e.name | translate for e in [{'id':true, 'name':'COMMON.YES'},{'id':false, 'name': 'COMMON.NO'}]") + .is-closed-column + select( + name="is_closed" + ng-model="value.is_closed" + data-required="true" + ng-options="e.id as e.name | translate for e in [{'id':true, 'name':'COMMON.YES'},{'id':false, 'name': 'COMMON.NO'}]" + ) - div.is-archived-column - select(name="is_archived", ng-model="value.is_archived", data-required="true", - ng-options="e.id as e.name | translate for e in [{'id':true, 'name':'COMMON.YES'},{'id':false, 'name': 'COMMON.NO'}]") + .is-archived-column + select( + name="is_archived" + ng-model="value.is_archived" + data-required="true" + ng-options="e.id as e.name | translate for e in [{'id':true, 'name':'COMMON.YES'},{'id':false, 'name': 'COMMON.NO'}]" + ) - div.status-wip-limit - input(name="wip_limit", type="number", ng-hide="value.is_archived", - ng-model="value.wip_limit", data-type="digits", - placeholder="{{'ADMIN.US_STATUS.WIP_LIMIT_COLUMN' | translate}}") + .status-wip-limit + input( + name="wip_limit" + type="number" + ng-hide="value.is_archived" + ng-model="value.wip_limit" + data-type="digits" + placeholder="{{'ADMIN.US_STATUS.WIP_LIMIT_COLUMN' | translate}}" + ) - div.options-column - a.save.icon.icon-floppy(href="", title="{{'COMMON.SAVE' | translate}}") - a.cancel.icon.icon-delete(href="", title="{{'COMMON.CANCEL' | translate}}") + .options-column + svg.save.icon.icon-save(title="{{'COMMON.SAVE' | translate}}") + use(xlink:href="#icon-save") + svg.cancel.icon.icon-close(title="{{'COMMON.CANCEL' | translate}}") + use(xlink:href="#icon-close") form div.row.table-main.new-value.hidden @@ -79,23 +105,43 @@ section.project-us-status include ../../components/select-color div.status-name - input(name="name", type="text", - ng-model="newValue.name", data-required="true", data-maxlength="255", - placeholder="{{'ADMIN.US_STATUS.PLACEHOLDER_WRITE_NAME' | translate}}") + input( + name="name" + type="text" + ng-model="newValue.name" + data-required="true" + data-maxlength="255" + placeholder="{{'ADMIN.US_STATUS.PLACEHOLDER_WRITE_NAME' | translate}}" + ) div.is-closed-column - select(name="is_closed", ng-model="newValue.is_closed", data-required="true", - ng-options="e.id as e.name | translate for e in [{'id':true, 'name':'COMMON.YES'},{'id':false, 'name': 'COMMON.NO'}]") + select( + name="is_closed" + ng-model="newValue.is_closed" + data-required="true" + ng-options="e.id as e.name | translate for e in [{'id':true, 'name':'COMMON.YES'},{'id':false, 'name': 'COMMON.NO'}]" + ) div.is-archived-column - select(name="is_archived", ng-model="newValue.is_archived", data-required="true", - ng-options="e.id as e.name | translate for e in [{'id':true, 'name':'COMMON.YES'},{'id':false, 'name': 'COMMON.NO'}]") + select( + name="is_archived" + ng-model="newValue.is_archived" + data-required="true" + ng-options="e.id as e.name | translate for e in [{'id':true, 'name':'COMMON.YES'},{'id':false, 'name': 'COMMON.NO'}]" + ) div.status-wip-limit - input(name="wip_limit", type="number", ng-hide="newValue.is_archived", - ng-model="newValue.wip_limit", data-type="digits", - placeholder="{{'ADMIN.US_STATUS.WIP_LIMIT_COLUMN' | translate}}") + input( + name="wip_limit" + type="number" + ng-hide="newValue.is_archived" + ng-model="newValue.wip_limit" + data-type="digits" + placeholder="{{'ADMIN.US_STATUS.WIP_LIMIT_COLUMN' | translate}}" + ) div.options-column - a.add-new.icon.icon-floppy(href="", title="{{'COMMON.ADD' | translate}}") - a.delete-new.icon.icon-delete(href="", title="{{'COMMON.CANCEL' | translate}}") + svg.add-new.icon.icon-save(title="{{'COMMON.ADD' | translate}}") + use(xlink:href="#icon-save") + svg.delete-new.icon.icon-trash(title="{{'COMMON.CANCEL' | translate}}") + use(xlink:href="#icon-trash") diff --git a/app/partials/includes/modules/backlog-filters.jade b/app/partials/includes/modules/backlog-filters.jade index 056f65a0..01b04ad7 100644 --- a/app/partials/includes/modules/backlog-filters.jade +++ b/app/partials/includes/modules/backlog-filters.jade @@ -6,13 +6,19 @@ section.filters form fieldset input(type="text", placeholder="{{'COMMON.FILTERS.INPUT_PLACEHOLDER' | translate}}", ng-model="filtersQ") - a.icon.icon-search(href="", title="{{'COMMON.FILTERS.TITLE_ACTION_FILTER_BUTTON' | translate}}") + svg.icon.icon-search(href="", title="{{'COMMON.FILTERS.TITLE_ACTION_FILTER_BUTTON' | translate}}") + use(xlink:href="#icon-search") div.filters-step-cat div.filters-applied h2.hidden.breadcrumb - a.back(href="", title="{{'COMMON.FILTERS.BREADCRUMB_TITLE' | translate}}", translate="BACKLOG.FILTERS.TITLE") - span.icon-arrow-right + a.back( + href="" + title="{{'COMMON.FILTERS.BREADCRUMB_TITLE' | translate}}" + translate="BACKLOG.FILTERS.TITLE" + ) + svg.icon.icon-arrow-right + use(xlink:href="#icon-arrow-right") a.subfilter(href="") span.title(translate="COMMON.FILTERS.BREADCRUMB_STATUS") div.filters-cats @@ -20,10 +26,12 @@ section.filters li a(href="", title="{{'BACKLOG.FILTERS.FILTER_CATEGORY_STATUS' | translate}}", data-type="status") span.title(translate="BACKLOG.FILTERS.FILTER_CATEGORY_STATUS") - span.icon.icon-arrow-right + svg.icon.icon-arrow-right + use(xlink:href="#icon-arrow-right") li a(href="", title="{{'BACKLOG.FILTERS.FILTER_CATEGORY_TAGS' | translate}}", data-type="tags") span.title(translate="BACKLOG.FILTERS.FILTER_CATEGORY_TAGS") - span.icon.icon-arrow-right + svg.icon.icon-arrow-right + use(xlink:href="#icon-arrow-right") div.filter-list.hidden diff --git a/app/partials/includes/modules/backlog-table.jade b/app/partials/includes/modules/backlog-table.jade index 9c3eab4c..b666dbe2 100644 --- a/app/partials/includes/modules/backlog-table.jade +++ b/app/partials/includes/modules/backlog-table.jade @@ -6,7 +6,8 @@ div.backlog-table-header div.status(translate="COMMON.FIELDS.STATUS") div.points(tg-us-role-points-selector, title="{{'BACKLOG.TABLE.TITLE_COLUMN_POINTS' | translate}}") span.header-points(translate="COMMON.FIELDS.POINTS") - span.icon.icon-arrow-bottom + svg.icon.icon-arrow-down + use(xlink:href="#icon-arrow-down") div.backlog-table-body(tg-backlog-sortable, ng-class="{'show-tags': ctrl.showTags, 'active-filters': ctrl.activeFilters}" ) include ../components/backlog-row diff --git a/app/partials/includes/modules/colors-table.jade b/app/partials/includes/modules/colors-table.jade deleted file mode 100644 index b989422c..00000000 --- a/app/partials/includes/modules/colors-table.jade +++ /dev/null @@ -1,21 +0,0 @@ -section.colors-table - div.table-header - div.row - div.color-column(translate="COMMON.FIELDS.COLOR") - div.status-name(translate="COMMON.FIELDS.NAME") - div.is-closed-column(translate="COMMON.IS_CLOSED") - div.options-column - - div.table-main - div.row.row-edit - div.color-column - div.current-color - include ../components/select-color - - div.status-name - input(type="text") - div.is-closed-column - input(type="checkbox") - div.options-column - a.icon.icon-floppy(href="#") - a.icon.icon-delete(href="#") diff --git a/app/partials/includes/modules/comment-activity.jade b/app/partials/includes/modules/comment-activity.jade deleted file mode 100644 index 86eb047d..00000000 --- a/app/partials/includes/modules/comment-activity.jade +++ /dev/null @@ -1,17 +0,0 @@ -div.us-activity - a.activity-title(ng-show="ctrl.countChanges(comment)", href="", title="{{'ACTIVITY.SHOW_ACTIVITY' | translate}}") - span(tg-bo-bind="ctrl.buildChangesText(comment)") - span.icon.icon-arrow-up - - div.activity-inner(ng-repeat="(key, change) in comment.values_diff") - div.activity-changed - span(tg-bo-bind="key") - div.activity-fromto - p - strong(translate="COMMON.FROM") - br - span(tg-bo-bind="ctrl.getChangeText(change[0])") - p - strong(translate="COMMON.TO") - br - span(tg-bo-bind="ctrl.getChangeText(change[1])") diff --git a/app/partials/includes/modules/issues-filters.jade b/app/partials/includes/modules/issues-filters.jade index ab735773..b879fd56 100644 --- a/app/partials/includes/modules/issues-filters.jade +++ b/app/partials/includes/modules/issues-filters.jade @@ -6,13 +6,15 @@ section.filters fieldset input(type="text", placeholder="{{'ISSUES.FILTERS.INPUT_SEARCH_PLACEHOLDER' | translate}}", ng-model="filtersQ") - a.icon.icon-search(href="", title="{{'ISSUES.FILTERS.TITLE_ACTION_SEARCH' | translate}}") + svg.icon.icon-search(title="{{'ISSUES.FILTERS.TITLE_ACTION_SEARCH' | translate}}") + use(xlink:href="#icon-search") div.filters-step-cat div.filters-applied a.hide.button.button-gray.save-filters(href="", title="{{'COMMON.SAVE' | translate}}", ng-class="{hide: filters.length}", translate="ISSUES.FILTERS.ACTION_SAVE_CUSTOM_FILTER") h2.hidden.breadcrumb a.back(href="", title="{{'ISSUES.FILTERS.TITLE_BREADCRUMB' | translate}}", translate="ISSUES.FILTERS.BREADCRUMB") - span.icon-arrow-right + svg.icon.icon-arrow-right + use(xlink:href="#icon-arrow-right") a.subfilter(href="", title="cat-name") span.title(translate="COMMON.FILTERS.BREADCRUMB_STATUS") div.filters-cats @@ -20,35 +22,43 @@ section.filters li a(href="", title="{{ 'ISSUES.FILTERS.CATEGORIES.TYPE' | translate}}", data-type="types") span.title(translate="ISSUES.FILTERS.CATEGORIES.TYPE") - span.icon.icon-arrow-right + svg.icon.icon-arrow-right + use(xlink:href="#icon-arrow-right") li a(href="", title="{{ 'ISSUES.FILTERS.CATEGORIES.STATUS' | translate}}", data-type="status") span.title(translate="ISSUES.FILTERS.CATEGORIES.STATUS") - span.icon.icon-arrow-right + svg.icon.icon-arrow-right + use(xlink:href="#icon-arrow-right") li a(href="", title="{{ 'ISSUES.FILTERS.CATEGORIES.SEVERITY' | translate}}", data-type="severities") span.title(translate="ISSUES.FILTERS.CATEGORIES.SEVERITY") - span.icon.icon-arrow-right + svg.icon.icon-arrow-right + use(xlink:href="#icon-arrow-right") li a(href="", title="{{ 'ISSUES.FILTERS.CATEGORIES.PRIORITIES' | translate}}", data-type="priorities") span.title(translate="ISSUES.FILTERS.CATEGORIES.PRIORITIES") - span.icon.icon-arrow-right + svg.icon.icon-arrow-right + use(xlink:href="#icon-arrow-right") li a(href="", title="{{ 'ISSUES.FILTERS.CATEGORIES.TAGS' | translate}}", data-type="tags") span.title(translate="ISSUES.FILTERS.CATEGORIES.TAGS") - span.icon.icon-arrow-right + svg.icon.icon-arrow-right + use(xlink:href="#icon-arrow-right") li a(href="", title="{{ 'ISSUES.FILTERS.CATEGORIES.ASSIGNED_TO' | translate}}", data-type="assignedTo") span.title(translate="ISSUES.FILTERS.CATEGORIES.ASSIGNED_TO") - span.icon.icon-arrow-right + svg.icon.icon-arrow-right + use(xlink:href="#icon-arrow-right") li a(href="", title="{{ 'ISSUES.FILTERS.CATEGORIES.CREATED_BY' | translate}}", data-type="createdBy") span.title(translate="ISSUES.FILTERS.CATEGORIES.CREATED_BY") - span.icon.icon-arrow-right + svg.icon.icon-arrow-right + use(xlink:href="#icon-arrow-right") li.custom-filters(ng-if="filters.myFilters.length") a(href="", title="{{ 'ISSUES.FILTERS.CATEGORIES.CUSTOM_FILTERS' | translate}}", data-type="myFilters") span.title(translate="ISSUES.FILTERS.CATEGORIES.CUSTOM_FILTERS") - span.icon.icon-arrow-right + svg.icon.icon-arrow-right + use(xlink:href="#icon-arrow-right") div.filter-list.hidden diff --git a/app/partials/includes/modules/issues-options.jade b/app/partials/includes/modules/issues-options.jade index 4cbce556..2a9692eb 100644 --- a/app/partials/includes/modules/issues-options.jade +++ b/app/partials/includes/modules/issues-options.jade @@ -3,4 +3,5 @@ section.issues-options(tg-check-permission="add_issue") a.button-green(href="", ng-click="ctrl.addNewIssue()") span.text(translate="ISSUES.ACTION_NEW_ISSUE") a.button-bulk(href="", ng-click="ctrl.addIssuesInBulk()") - span.icon.icon-bulk + svg.icon.icon-bulk + use(xlink:href="#icon-bulk") diff --git a/app/partials/includes/modules/issues-table.jade b/app/partials/includes/modules/issues-table.jade index ddf6ada0..e23a3025 100644 --- a/app/partials/includes/modules/issues-table.jade +++ b/app/partials/includes/modules/issues-table.jade @@ -20,7 +20,8 @@ section.issues-table.basic-table(ng-class="{empty: !issues.length}") ng-class="{'inactive': !issue.total_voters, 'is-voted': issue.is_voter}" title="{{ 'COMMON.VOTE_BUTTON.COUNTER_TITLE'|translate:{total:issue.total_voters||0}:'messageformat' }}" ) - span.icon.icon-caret-up + svg.icon.icon-upvote + use(xlink:href="#icon-upvote") span {{ ::issue.total_voters }} div.subject a( @@ -42,14 +43,16 @@ section.issues-table.basic-table(ng-class="{empty: !issues.length}") title="{{'ISSUES.TABLE.TITLE_ACTION_CHANGE_STATUS' | translate}}" ) span.issue-status-bind - span.icon.icon-arrow-bottom(tg-check-permission="modify_issue") + svg.icon.icon-arrow-down(tg-check-permission="modify_issue") + use(xlink:href="#icon-arrow-down") div.created-field(tg-bo-bind="issue.created_date|momentFormat:'DD MMM YYYY HH:mm'") div.assigned-field(tg-issue-assigned-to-inline-edition="issue") div.issue-assignedto(title="{{'ISSUES.TABLE.TITLE_ACTION_ASSIGNED_TO' | translate}}") figure.avatar - span.icon.icon-arrow-bottom(tg-check-permission="modify_issue") + svg.icon.icon-arrow-down(tg-check-permission="modify_issue") + use(xlink:href="#icon-arrow-down") section.empty-issues(ng-if="issues != undefined && issues.length == 0") img( diff --git a/app/partials/includes/modules/kanban-table.jade b/app/partials/includes/modules/kanban-table.jade index 5770b403..502fef51 100644 --- a/app/partials/includes/modules/kanban-table.jade +++ b/app/partials/includes/modules/kanban-table.jade @@ -7,37 +7,67 @@ div.kanban-table(tg-kanban-squish-column) tg-class-permission="{'readonly': '!modify_task'}") span(tg-bo-bind="s.name") div.options - a.icon.icon-vfold.hfold(href="", ng-click='foldStatus(s)', - title="{{'KANBAN.TITLE_ACTION_FOLD' | translate}}", - ng-class='{hidden:folds[s.id]}') - a.icon.icon-vunfold.hunfold(href="", ng-click='foldStatus(s)', - title="{{'KANBAN.TITLE_ACTION_UNFOLD' | translate}}", - ng-class='{hidden:!folds[s.id]}') + a.option( + href="" + ng-click='foldStatus(s)' + title="{{'KANBAN.TITLE_ACTION_FOLD' | translate}}" + ng-class='{hidden:folds[s.id]}' + ) + svg.icon.icon-fold-column + use(xlink:href="#icon-fold-column") + a.option.hunfold( + href="" + ng-click='foldStatus(s)' + title="{{'KANBAN.TITLE_ACTION_UNFOLD' | translate}}" + ng-class='{hidden:!folds[s.id]}' + ) + svg.icon.icon-unfold-column + use(xlink:href="#icon-unfold-column") + a.option( + href="" + title="{{'KANBAN.TITLE_ACTION_FOLD_CARDS' | translate}}" + ng-class="{hidden:statusViewModes[s.id] == 'minimized'}" + ng-click="ctrl.updateStatusViewMode(s.id, 'minimized')" + ) + svg.icon.icon-fold-row + use(xlink:href="#icon-fold-row") + a.option( + href="" + title="{{'KANBAN.TITLE_ACTION_UNFOLD_CARDS' | translate}}" + ng-class="{hidden:statusViewModes[s.id] == 'maximized'}" + ng-click="ctrl.updateStatusViewMode(s.id, 'maximized')" + ) + svg.icon.icon-unfold-row + use(xlink:href="#icon-unfold-row") - a.icon.icon-vfold(href="", title="{{'KANBAN.TITLE_ACTION_FOLD_CARDS' | translate}}", - ng-class="{hidden:statusViewModes[s.id] == 'minimized'}", - ng-click="ctrl.updateStatusViewMode(s.id, 'minimized')") - a.icon.icon-vunfold(href="", title="{{'KANBAN.TITLE_ACTION_UNFOLD_CARDS' | translate}}", - ng-class="{hidden:statusViewModes[s.id] == 'maximized'}", - ng-click="ctrl.updateStatusViewMode(s.id, 'maximized')") + a.option( + href="" + title="{{'KANBAN.TITLE_ACTION_ADD_US' | translate}}" + ng-click="ctrl.addNewUs('standard', s.id)" + tg-check-permission="add_us" + ng-hide="s.is_archived" + ) + svg.icon.icon-add + use(xlink:href="#icon-add") - a.icon.icon-plus(href="", title="{{'KANBAN.TITLE_ACTION_ADD_US' | translate}}", - ng-click="ctrl.addNewUs('standard', s.id)", - tg-check-permission="add_us", - ng-hide="s.is_archived") + a.option( + href="" + title="{{'KANBAN.TITLE_ACTION_ADD_BULK' | translate}}" + ng-click="ctrl.addNewUs('bulk', s.id)" + tg-check-permission="add_us" + ng-hide="s.is_archived" + ) + svg.icon.icon-bulk + use(xlink:href="#icon-bulk") - a.icon.icon-bulk(href="", title="{{'KANBAN.TITLE_ACTION_ADD_BULK' | translate}}", - ng-click="ctrl.addNewUs('bulk', s.id)", - tg-check-permission="add_us", - ng-hide="s.is_archived") - - a( + a.option( href="" ng-attr-title="{{title}}" ng-class="class" ng-if="s.is_archived" tg-kanban-archived-status-header="s") - include ../../../svg/eye.svg + svg.icon.icon-watch + use(xlink:href="#icon-watch") div.kanban-table-body div.kanban-table-inner diff --git a/app/partials/includes/modules/lightbox-add-member.jade b/app/partials/includes/modules/lightbox-add-member.jade deleted file mode 100644 index 624af87f..00000000 --- a/app/partials/includes/modules/lightbox-add-member.jade +++ /dev/null @@ -1,11 +0,0 @@ -a.close(href="", title="close") - span.icon.icon-delete -form - h2.title(translate="LIGHTBOX.ADD_MEMBER.TITLE") - - //- Form is set in a directive - .add-member-forms - - button.button-green.submit-button(type="submit", title="{{'COMMON.CREATE' | translate}}", translate="COMMON.CREATE") - - p.help-text(translate="LIGHTBOX.ADD_MEMBER.HELP_TEXT") diff --git a/app/partials/includes/modules/lightbox-ask-choice.jade b/app/partials/includes/modules/lightbox-ask-choice.jade index cc7336a0..c1f5a0fb 100644 --- a/app/partials/includes/modules/lightbox-ask-choice.jade +++ b/app/partials/includes/modules/lightbox-ask-choice.jade @@ -1,5 +1,6 @@ a.close(href="", title="{{'COMMON.CLOSE' | translate}}") - span.icon.icon-delete + svg.icon.icon-close + use(xlink:href="#icon-close") form h2.title p.question @@ -8,7 +9,7 @@ form select.choices p.warning - div.options + .options a.button-green(href="", title="{{'COMMON.ACCEPT' | translate}}") span(translate="COMMON.ACCEPT") a.button-red(href="", title="{{'COMMON.CANCEL' | translate}}") diff --git a/app/partials/includes/modules/lightbox-create-issue.jade b/app/partials/includes/modules/lightbox-create-issue.jade index bfcd53dd..829d660f 100644 --- a/app/partials/includes/modules/lightbox-create-issue.jade +++ b/app/partials/includes/modules/lightbox-create-issue.jade @@ -1,19 +1,42 @@ -a.close(href="", title="{{'COMMON.CLOSE' | translate}}") - span.icon.icon-delete +a.close( + href="" + title="{{'COMMON.CLOSE' | translate}}" +) + svg.icon.icon-close + use(xlink:href="#icon-close") form h2.title(translate="LIGHTBOX.CREATE_ISSUE.TITLE") fieldset - input(type="text", ng-model="issue.subject", ng-attr-placeholder="{{'COMMON.FIELDS.SUBJECT' | translate}}", ng-model-options="{ debounce: 200 }", data-required="true", data-maxlength="500") - div.fieldset-row + input( + type="text" + ng-model="issue.subject" + ng-attr-placeholder="{{'COMMON.FIELDS.SUBJECT' | translate}}" + ng-model-options="{ debounce: 200 }" + data-required="true" + data-maxlength="500" + ) + .fieldset-row fieldset - select.type(ng-model="issue.type", ng-options="t.id as t.name for t in issueTypes") + select.type( + ng-model="issue.type" + ng-options="t.id as t.name for t in issueTypes" + ) fieldset - select.priority(ng-model="issue.priority", ng-options="p.id as p.name for p in priorityList") + select.priority( + ng-model="issue.priority" + ng-options="p.id as p.name for p in priorityList" + ) fieldset - select.severity(ng-model="issue.severity", ng-options="s.id as s.name for s in severityList") + select.severity( + ng-model="issue.severity" + ng-options="s.id as s.name for s in severityList" + ) fieldset - div.tags-block(tg-lb-tag-line, ng-model="issue.tags") + .tags-block( + tg-lb-tag-line + ng-model="issue.tags" + ) fieldset section @@ -24,7 +47,14 @@ form ) fieldset - textarea.description(ng-attr-placeholder="{{'COMMON.FIELDS.DESCRIPTION' | translate}}", ng-model="issue.description") + textarea.description( + ng-attr-placeholder="{{'COMMON.FIELDS.DESCRIPTION' | translate}}" + ng-model="issue.description" + ) // include lightbox-attachments - button.button-green.submit-button(type="submit", title="{{'COMMON.CREATE' | translate}}", translate="COMMON.CREATE") + button.button-green.submit-button( + type="submit" + title="{{'COMMON.CREATE' | translate}}" + translate="COMMON.CREATE" + ) diff --git a/app/partials/includes/modules/lightbox-delete-project.jade b/app/partials/includes/modules/lightbox-delete-project.jade index 0ae8f2ad..c360d23d 100644 --- a/app/partials/includes/modules/lightbox-delete-project.jade +++ b/app/partials/includes/modules/lightbox-delete-project.jade @@ -1,11 +1,12 @@ a.close(href="", title="{{'close' | translate}}") - span.icon.icon-delete + svg.icon.icon-close + use(xlink:href="#icon-close") form h2.title(translate="LIGHTBOX.DELETE_PROJECT.TITLE") p span.question(translate="LIGHTBOX.DELETE_PROJECT.QUESTION") span.subtitle(translate="LIGHTBOX.DELETE_PROJECT.SUBTITLE") - div.options + .options a.button-green(href="", title="{{'LIGHTBOX.DELETE_PROJECT.CONFIRM' | translate}}") span(translate="LIGHTBOX.DELETE_PROJECT.CONFIRM") a.button-red(href="", title="{{'COMMON.CANCEL' | translate}}") diff --git a/app/partials/includes/modules/lightbox-generic-ask.jade b/app/partials/includes/modules/lightbox-generic-ask.jade index c51ba250..6ddcaf0a 100644 --- a/app/partials/includes/modules/lightbox-generic-ask.jade +++ b/app/partials/includes/modules/lightbox-generic-ask.jade @@ -1,12 +1,16 @@ a.close(href="", title="{{'COMMON.CLOSE' | translate}}") - span.icon.icon-delete + svg.icon.icon-close + use(xlink:href="#icon-close") form h2.title p span.subtitle span.message div.options - a.button-green(href="", title="{{'COMMON.ACCEPT' | translate}}") + a.button-green( + href="" + title="{{'COMMON.ACCEPT' | translate}}" + ) span(translate="COMMON.ACCEPT") a.button-red(href="", title="{{'COMMON.CANCEL' | translate}}") span(translate="COMMON.CANCEL") diff --git a/app/partials/includes/modules/lightbox-generic-error.jade b/app/partials/includes/modules/lightbox-generic-error.jade index ca06f309..343dbaa6 100644 --- a/app/partials/includes/modules/lightbox-generic-error.jade +++ b/app/partials/includes/modules/lightbox-generic-error.jade @@ -1,7 +1,14 @@ -a.close(href="", title="{{'COMMON.CLOSE' | translate}}") - span.icon.icon-delete +a.close( + href="" + title="{{'COMMON.CLOSE' | translate}}" +) + svg.icon.icon-close + use(xlink:href="#icon-close") section h2.title - div.options - a.button-green(href="", title="{{'COMMON.ACCEPT' | translate}}") + .options + a.button-green( + href="" + title="{{'COMMON.ACCEPT' | translate}}" + ) span(translate="COMMON.ACCEPT") diff --git a/app/partials/includes/modules/lightbox-generic-success.jade b/app/partials/includes/modules/lightbox-generic-success.jade index 35828685..02bf8c0a 100644 --- a/app/partials/includes/modules/lightbox-generic-success.jade +++ b/app/partials/includes/modules/lightbox-generic-success.jade @@ -1,8 +1,15 @@ -a.close(href="", title="{{'COMMON.CLOSE' | translate}}") - span.icon.icon-delete +a.close( + href="" + title="{{'COMMON.CLOSE' | translate}}" +) + svg.icon.icon-close + use(xlink:href="#icon-close") section h2.title p.message - div.options - a.button-green(href="", title="{{'COMMON.ACCEPT' | translate}}") + .options + a.button-green( + href="" + title="{{'COMMON.ACCEPT' | translate}}" + ) span(translate="COMMON.ACCEPT") diff --git a/app/partials/includes/modules/lightbox-issue-bulk.jade b/app/partials/includes/modules/lightbox-issue-bulk.jade index bef68aac..b418e7d5 100644 --- a/app/partials/includes/modules/lightbox-issue-bulk.jade +++ b/app/partials/includes/modules/lightbox-issue-bulk.jade @@ -1,8 +1,24 @@ -a.close(href="", title="{{'COMMON.CLOSE' | translate}}") - span.icon.icon-delete +a.close( + href="" + title="{{'COMMON.CLOSE' | translate}}" +) + svg.icon.icon-close + use(xlink:href="#icon-close") form h2.title(translate="COMMON.NEW_BULK") fieldset - textarea(cols="200", wrap="off", tg-limit-line-length, ng-attr-placeholder="{{'COMMON.ONE_ITEM_LINE' | translate}}", ng-model="new.bulk", data-required="true", data-linewidth="200") + textarea( + cols="200" + wrap="off" + ng-model="new.bulk" + data-required="true" + data-linewidth="200" + ng-attr-placeholder="{{'COMMON.ONE_ITEM_LINE' | translate}}" - button.button-green.submit-button(type="submit", title="{{'COMMON.SAVE' | translate}}", translate="COMMON.SAVE") + ) + + button.button-green.submit-button( + type="submit" + title="{{'COMMON.SAVE' | translate}}" + translate="COMMON.SAVE" + ) diff --git a/app/partials/includes/modules/lightbox-sprint-add-edit.jade b/app/partials/includes/modules/lightbox-sprint-add-edit.jade index d44ad710..148084eb 100644 --- a/app/partials/includes/modules/lightbox-sprint-add-edit.jade +++ b/app/partials/includes/modules/lightbox-sprint-add-edit.jade @@ -1,30 +1,57 @@ -a.close(href="", title="{{'COMMON.CLOSE' | translate}}") - span.icon.icon-delete +a.close( + href="" + title="{{'COMMON.CLOSE' | translate}}" +) + svg.icon.icon-close + use(xlink:href="#icon-close") form h2.title(translate="LIGHTBOX.ADD_EDIT_SPRINT.TITLE") fieldset - input.sprint-name(type="text", name="name", ng-model="sprint.name", - ng-model-options="{ debounce: 200 }", - data-required="true", data-maxlength="500", - placeholder="{{'LIGHTBOX.ADD_EDIT_SPRINT.PLACEHOLDER_SPRINT_NAME' | translate}}") + input.sprint-name( + type="text" + name="name" + ng-model="sprint.name" + ng-model-options="{ debounce: 200 }" + data-required="true" + data-maxlength="500" + placeholder="{{'LIGHTBOX.ADD_EDIT_SPRINT.PLACEHOLDER_SPRINT_NAME' | translate}}" + ) label.last-sprint-name fieldset.dates div - input.date-start(type="text", name="estimated_start", - ng-model="sprint.estimated_start", data-required="true", tg-date-selector, - placeholder="{{'LIGHTBOX.ADD_EDIT_SPRINT.PLACEHOLDER_SPRINT_START' | translate}}") + input.date-start( + type="text" + name="estimated_start" + ng-model="sprint.estimated_start" + data-required="true" + tg-date-selector + placeholder="{{'LIGHTBOX.ADD_EDIT_SPRINT.PLACEHOLDER_SPRINT_START' | translate}}" + ) div - input.date-end(type="text", name="estimated_finish", - ng-model="sprint.estimated_finish", data-required="true", tg-date-selector, - placeholder="{{'LIGHTBOX.ADD_EDIT_SPRINT.PLACEHOLDER_SPRINT_END' | translate}}") + input.date-end( + type="text" + name="estimated_finish" + ng-model="sprint.estimated_finish" + data-required="true" + tg-date-selector + placeholder="{{'LIGHTBOX.ADD_EDIT_SPRINT.PLACEHOLDER_SPRINT_END' | translate}}" + ) - button.button-green.submit-button(type="submit", title="{{'COMMON.CREATE' | translate}}", - translate="COMMON.CREATE") + button.button-green.submit-button( + type="submit" + title="{{'COMMON.CREATE' | translate}}" + translate="COMMON.CREATE" + ) - div(tg-check-permission="delete_milestone") - span.delete-sprint.hidden(translate) - span(translate="LIGHTBOX.ADD_EDIT_SPRINT.ACTION_DELETE_SPRINT") - a.icon.icon-delete(href="", - title="{{'LIGHTBOX.ADD_EDIT_SPRINT.TITLE_ACTION_DELETE_SPRINT' | translate}}") + a.delete-sprint( + tg-check-permission="delete_milestone" + href="" + title="{{'LIGHTBOX.ADD_EDIT_SPRINT.TITLE_ACTION_DELETE_SPRINT' | translate}}" + ) + span {{'LIGHTBOX.ADD_EDIT_SPRINT.ACTION_DELETE_SPRINT' | translate }} + svg.icon.icon-trash( + href="" + ) + use(xlink:href="#icon-trash") diff --git a/app/partials/includes/modules/lightbox-task-bulk.jade b/app/partials/includes/modules/lightbox-task-bulk.jade index f07ef517..7fac9d2e 100644 --- a/app/partials/includes/modules/lightbox-task-bulk.jade +++ b/app/partials/includes/modules/lightbox-task-bulk.jade @@ -1,8 +1,24 @@ -a.close(href="", title="{{'COMMON.CLOSE' | translate}}") - span.icon.icon-delete +a.close( + href="" + title="{{'COMMON.CLOSE' | translate}}" +) + svg.icon.icon-close + use(xlink:href="#icon-close") form h2.title(translate="COMMON.NEW_BULK") fieldset - textarea(cols="200", wrap="off", tg-limit-line-length, ng-attr-placeholder="{{'COMMON.ONE_ITEM_LINE' | translate}}", ng-model="form.data", data-required="true") + textarea( + cols="200" + wrap="off" + ng-model="form.data" + data-required="true" + data-linewidth="200" + ng-attr-placeholder="{{'COMMON.ONE_ITEM_LINE' | translate}}" - button.button-green.submit-button(type="submit", title="{{'COMMON.SAVE' | translate}}", translate="COMMON.SAVE") + ) + + button.button-green.submit-button( + type="submit" + title="{{'COMMON.SAVE' | translate}}" + translate="COMMON.SAVE" + ) diff --git a/app/partials/includes/modules/lightbox-task-create-edit.jade b/app/partials/includes/modules/lightbox-task-create-edit.jade index a878e7ad..68fef13c 100644 --- a/app/partials/includes/modules/lightbox-task-create-edit.jade +++ b/app/partials/includes/modules/lightbox-task-create-edit.jade @@ -1,22 +1,44 @@ -a.close(href="", title="{{'COMMON.CLOSE' | translate}}") - span.icon.icon-delete +a.close( + href="" + title="{{'COMMON.CLOSE' | translate}}" +) + svg.icon.icon-close + use(xlink:href="#icon-close") form h2.title(translate="LIGHTBOX.CREATE_EDIT_TASK.TITLE") fieldset - input(type="text", ng-model="task.subject", ng-attr-placeholder="{{'LIGHTBOX.CREATE_EDIT_TASK.PLACEHOLDER_SUBJECT' | translate}}", ng-model-options="{ debounce: 200 }", - data-required="true", data-maxlength="500") + input( + type="text" + ng-model="task.subject" + ng-attr-placeholder="{{'LIGHTBOX.CREATE_EDIT_TASK.PLACEHOLDER_SUBJECT' | translate}}" + ng-model-options="{ debounce: 200 }" + data-required="true" + data-maxlength="500" + ) fieldset - select(ng-model="task.status", ng-options="s.id as s.name for s in taskStatusList", - placeholder="{{'LIGHTBOX.CREATE_EDIT_TASK.PLACEHOLDER_STATUS' | translate}}") + select( + ng-model="task.status" + ng-options="s.id as s.name for s in taskStatusList" + placeholder="{{'LIGHTBOX.CREATE_EDIT_TASK.PLACEHOLDER_STATUS' | translate}}" + ) fieldset - select(ng-model="task.assigned_to", ng-options="s.id as s.full_name_display for s in users", - placeholder="{{'Assigned to'}}") - option(value="", translate="LIGHTBOX.CREATE_EDIT_TASK.OPTION_UNASSIGNED") + select( + ng-model="task.assigned_to" + ng-options="s.id as s.full_name_display for s in users" + placeholder="{{'Assigned to'}}" + ) + option( + value="" + translate="LIGHTBOX.CREATE_EDIT_TASK.OPTION_UNASSIGNED" + ) fieldset - div.tags-block(tg-lb-tag-line, ng-model="task.tags") + div.tags-block( + tg-lb-tag-line + ng-model="task.tags" + ) fieldset section @@ -27,19 +49,46 @@ form ) fieldset - textarea.description(ng-attr-placeholder="{{'LIGHTBOX.CREATE_EDIT_TASK.PLACEHOLDER_SHORT_DESCRIPTION' | translate}}", ng-model="task.description", ng-model-options="{ debounce: 200 }") + textarea.description( + ng-attr-placeholder="{{'LIGHTBOX.CREATE_EDIT_TASK.PLACEHOLDER_SHORT_DESCRIPTION' | translate}}" + ng-model="task.description" + ng-model-options="{ debounce: 200 }" + ) div.settings fieldset.iocaine-flag(title="{{'COMMON.IOCAINE_TEXT' | translate}}") - input(type="checkbox", ng-model="task.is_iocaine", name="iocaine-task", id="iocaine-task", ng-value="true") + input( + type="checkbox" + ng-model="task.is_iocaine" + name="iocaine-task" + id="iocaine-task" + ng-value="true" + ) label.iocaine.trans-button(for="iocaine-task") - span.icon.icon-iocaine(for="iocaine-task icon-iocaine") + svg.icon.icon-iocaine(for="iocaine-task icon-iocaine") + use(xlink:href="#icon-iocaine") span Iocaine fieldset.blocking-flag - input(type="checkbox", ng-model="task.is_blocked", name="blocked-task", id="blocked-task", ng-value="true") - label.blocked.trans-button(for="blocked-task", translate="COMMON.BLOCKED") + input( + type="checkbox" + ng-model="task.is_blocked" + name="blocked-task" + id="blocked-task" + ng-value="true" + ) + label.blocked.trans-button( + for="blocked-task" + translate="COMMON.BLOCKED" + ) - tg-blocking-message-input(watch="task.is_blocked", ng-model="task.blocked_note") + tg-blocking-message-input( + watch="task.is_blocked" + ng-model="task.blocked_note" + ) - button.button-green.submit-button(type="submit", title="{{'COMMON.CREATE' | translate}}", translate="COMMON.CREATE") + button.button-green.submit-button( + type="submit" + title="{{'COMMON.CREATE' | translate}}" + translate="COMMON.CREATE" + ) diff --git a/app/partials/includes/modules/lightbox-us-bulk.jade b/app/partials/includes/modules/lightbox-us-bulk.jade index e12442fd..b522a0ed 100644 --- a/app/partials/includes/modules/lightbox-us-bulk.jade +++ b/app/partials/includes/modules/lightbox-us-bulk.jade @@ -1,8 +1,23 @@ -a.close(href="", title="{{'COMMON.CLOSE' | translate}}") - span.icon.icon-delete +a.close( + href="" + title="{{'COMMON.CLOSE' | translate}}" +) + svg.icon.icon-close + use(xlink:href="#icon-close") form h2.title(translate="COMMON.NEW_BULK") fieldset - textarea(cols="200", wrap="off", tg-limit-line-length, ng-attr-placeholder="{{'COMMON.ONE_ITEM_LINE' | translate}}", ng-model="new.bulk", data-required="true", data-linewidth="200") + textarea( + cols="200" + wrap="off" + ng-model="new.bulk" + data-required="true" + data-linewidth="200" + ng-attr-placeholder="{{'COMMON.ONE_ITEM_LINE' | translate}}" + ) - button.button-green.submit-button(type="submit", title="{{'COMMON.SAVE' | translate}}", translate="COMMON.SAVE") \ No newline at end of file + button.button-green.submit-button( + type="submit", + title="{{'COMMON.SAVE' | translate}}", + translate="COMMON.SAVE" + ) diff --git a/app/partials/includes/modules/lightbox-us-create-edit.jade b/app/partials/includes/modules/lightbox-us-create-edit.jade index bb3d5045..c03c8010 100644 --- a/app/partials/includes/modules/lightbox-us-create-edit.jade +++ b/app/partials/includes/modules/lightbox-us-create-edit.jade @@ -1,23 +1,45 @@ -a.close(href="", title="{{'COMMON.CLOSE' | translate}}") - span.icon.icon-delete +a.close( + href="" + title="{{'COMMON.CLOSE' | translate}}" +) + svg.icon.icon-close + use(xlink:href="#icon-close") form h2.title(translate="LIGHTBOX.CREATE_EDIT_US.TITLE") fieldset - input(type="text", name="subject", ng-model-options="{ debounce: 200 }", ng-model="us.subject", placeholder="{{'COMMON.FIELDS.SUBJECT' | translate}}", - data-required="true", data-maxlength="500") + input( + type="text" + name="subject" + ng-model-options="{ debounce: 200 }" + ng-model="us.subject" + placeholder="{{'COMMON.FIELDS.SUBJECT' | translate}}" + data-required="true" + data-maxlength="500" + ) fieldset.ticket-estimation tg-lb-us-estimation(ng-model="us") fieldset - select(name="status", ng-model="us.status", ng-options="s.id as s.name for s in usStatusList") + select( + name="status" + ng-model="us.status" + ng-options="s.id as s.name for s in usStatusList" + ) fieldset - div.tags-block(tg-lb-tag-line, ng-model="us.tags") + div.tags-block( + tg-lb-tag-line + ng-model="us.tags" + ) fieldset - textarea.description(name="description", ng-model="us.description", ng-model-options="{ debounce: 200 }", - ng-attr-placeholder="{{'LIGHTBOX.CREATE_EDIT_US.PLACEHOLDER_DESCRIPTION' | translate}}") + textarea.description( + name="description" + ng-model="us.description" + ng-model-options="{ debounce: 200 }" + ng-attr-placeholder="{{'LIGHTBOX.CREATE_EDIT_US.PLACEHOLDER_DESCRIPTION' | translate}}" + ) fieldset section tg-attachments-simple( @@ -28,19 +50,51 @@ form div.settings fieldset.team-requirement - input(type="checkbox", name="team_requirement", ng-model="us.team_requirement", - id="team-requirement", ng-value="true") - label.requirement.trans-button(for="team-requirement", translate="US.FIELDS.TEAM_REQUIREMENT") + input( + type="checkbox" + name="team_requirement" + ng-model="us.team_requirement" + id="team-requirement" + ng-value="true" + ) + label.requirement.trans-button( + for="team-requirement" + translate="US.FIELDS.TEAM_REQUIREMENT" + ) fieldset.client-requirement - input(type="checkbox", name="client_requirement", ng-model="us.client_requirement", - id="client-requirement", ng-value="true") - label.requirement.trans-button(for="client-requirement", translate="US.FIELDS.CLIENT_REQUIREMENT") + input( + type="checkbox" + name="client_requirement" + ng-model="us.client_requirement", + id="client-requirement" + ng-value="true" + ) + label.requirement.trans-button( + for="client-requirement" + translate="US.FIELDS.CLIENT_REQUIREMENT" + ) fieldset.blocking-flag - input(type="checkbox", name="is_blocked", ng-model="us.is_blocked", id="blocked-us" ng-value="true") - label.blocked.trans-button(for="blocked-us", translate="COMMON.BLOCKED") + input( + type="checkbox" + name="is_blocked" + ng-model="us.is_blocked" + id="blocked-us" + ng-value="true" + ) + label.blocked.trans-button( + for="blocked-us" + translate="COMMON.BLOCKED" + ) - tg-blocking-message-input(watch="us.is_blocked", ng-model="us.blocked_note") + tg-blocking-message-input( + watch="us.is_blocked" + ng-model="us.blocked_note" + ) - button.button-green.submit-button(type="submit", title="{{'COMMON.CREATE' | translate}}", translate="COMMON.CREATE") + button.button-green.submit-button( + type="submit" + title="{{'COMMON.CREATE' | translate}}" + translate="COMMON.CREATE" + ) diff --git a/app/partials/includes/modules/login-form.jade b/app/partials/includes/modules/login-form.jade index 87615f94..bb62082d 100644 --- a/app/partials/includes/modules/login-form.jade +++ b/app/partials/includes/modules/login-form.jade @@ -5,6 +5,8 @@ div.login-form-container(tg-login) type="text" autocorrect="off" autocapitalize="none" + autofocus + required name="username" data-required="true" placeholder="{{'LOGIN_COMMON.PLACEHOLDER_AUTH_NAME' | translate}}" diff --git a/app/partials/includes/modules/related-tasks.jade b/app/partials/includes/modules/related-tasks.jade index da0c24ba..c7a5054e 100644 --- a/app/partials/includes/modules/related-tasks.jade +++ b/app/partials/includes/modules/related-tasks.jade @@ -6,7 +6,7 @@ section.related-tasks( span.related-tasks-title(translate="COMMON.RELATED_TASKS") div(tg-related-task-create-button) .related-tasks-body - .row.single-related-task( + .row.single-related-task.js-related-task( ng-repeat="task in tasks" ng-class="{closed: task.is_closed, blocked: task.is_blocked, iocaine: task.is_iocaine}" tg-related-task-row diff --git a/app/partials/includes/modules/search-filter.jade b/app/partials/includes/modules/search-filter.jade index 5c8c93ae..3304a5cc 100644 --- a/app/partials/includes/modules/search-filter.jade +++ b/app/partials/includes/modules/search-filter.jade @@ -4,7 +4,8 @@ ul.search-filter href="#" title="{{ 'SEARCH.FILTER_USER_STORIES' | translate }}" ) - span.icon.icon-bulk + svg.icon.icon-bulk + use(xlink:href="#icon-bulk") span.num span.name(translate="SEARCH.FILTER_USER_STORIES") @@ -13,7 +14,8 @@ ul.search-filter href="#" title="{{ 'SEARCH.FILTER_ISSUES' | translate }}" ) - span.icon.icon-issues + svg.icon.icon-issues + use(xlink:href="#icon-issues") span.num span.name(translate="SEARCH.FILTER_ISSUES") @@ -22,7 +24,8 @@ ul.search-filter href="#" title="{{ 'SEARCH.FILTER_TASKS' | translate }}" ) - span.icon.icon-bulk + svg.icon.icon-bulk + use(xlink:href="#icon-bulk") span.num span.name(translate="SEARCH.FILTER_TASKS") @@ -31,6 +34,7 @@ ul.search-filter href="#" title="{{ 'SEARCH.FILTER_WIKI' | translate }}" ) - span.icon.icon-wiki + svg.icon.icon-wiki + use(xlink:href="#icon-wiki") span.num span.name(translate="SEARCH.FILTER_WIKI") diff --git a/app/partials/includes/modules/search-in.jade b/app/partials/includes/modules/search-in.jade index e13718a3..e16d70ee 100644 --- a/app/partials/includes/modules/search-in.jade +++ b/app/partials/includes/modules/search-in.jade @@ -1,6 +1,11 @@ section.search-in header fieldset - input(type="text", placeholder="{{'SEARCH.PLACEHOLDER_SEARCH' | translate}}", ng-model="searchTerm") + input( + type="text" + placeholder="{{'SEARCH.PLACEHOLDER_SEARCH' | translate}}" + ng-model="searchTerm" + ) .icon-search-wrapper(tg-loading="loading") - a.icon.icon-search(href="", title="{{'SEARCH.TITLE_ACTION_SEARCH' | translate}}") + svg.icon.icon-search(title="{{'SEARCH.TITLE_ACTION_SEARCH' | translate}}") + use(xlink:href="#icon-search") diff --git a/app/partials/includes/modules/sprints.jade b/app/partials/includes/modules/sprints.jade index 2e1b163f..82066a18 100644 --- a/app/partials/includes/modules/sprints.jade +++ b/app/partials/includes/modules/sprints.jade @@ -13,7 +13,8 @@ section.sprints ng-if="totalMilestones" tg-check-permission="add_milestone" ) - include ../../../svg/add.svg + svg.icon.icon-add + use(xlink:href="#icon-add") div.sprints-empty(ng-if="totalMilestones === 0") img( @@ -36,7 +37,8 @@ section.sprints a.filter-closed-sprints(href="", tg-backlog-toggle-closed-sprints-visualization, ng-if="totalClosedMilestones") - span.icon.icon-archive + svg.icon.icon-archive + use(xlink:href="#icon-archive") span.text(translate="BACKLOG.SPRINTS.ACTION_SHOW_CLOSED_SPRINTS") div.sprint.sprint-closed(ng-repeat="sprint in closedSprints track by sprint.id", diff --git a/app/partials/includes/modules/taskboard-table.jade b/app/partials/includes/modules/taskboard-table.jade index 5559f648..a87acc12 100644 --- a/app/partials/includes/modules/taskboard-table.jade +++ b/app/partials/includes/modules/taskboard-table.jade @@ -4,15 +4,39 @@ div.taskboard-table(tg-taskboard-squish-column) h2.task-colum-name(translate="TASKBOARD.TABLE.COLUMN") h2.task-colum-name(ng-repeat="s in taskStatusList track by s.id", ng-style="{'border-top-color':s.color}", ng-class="{'column-fold':statusesFolded[s.id]}", class="squish-status-{{s.id}}", tg-bo-title="s.name") span(tg-bo-bind="s.name") - a.icon.icon-vfold.hfold(href="", ng-click='foldStatus(s)', title="{{'TASKBOARD.TABLE.TITLE_ACTION_FOLD' | translate}}", ng-class='{hidden:statusesFolded[s.id]}') - a.icon.icon-vunfold.hunfold(href="", title="{{'TASKBOARD.TABLE.TITLE_ACTION_UNFOLD' | translate}}", ng-click='foldStatus(s)', ng-class='{hidden:!statusesFolded[s.id]}') + svg.icon.icon-fold-row.hfold( + ng-click='foldStatus(s)' + title="{{'TASKBOARD.TABLE.TITLE_ACTION_FOLD' | translate}}" + ng-class='{hidden:statusesFolded[s.id]}' + ) + use(xlink:href="#icon-fold-row") + + svg.icon.icon-fold-row.hunfold( + title="{{'TASKBOARD.TABLE.TITLE_ACTION_UNFOLD' | translate}}" + ng-click='foldStatus(s)' + ng-class='{hidden:!statusesFolded[s.id]}' + ) + use(xlink:href="#icon-unfold-row") div.taskboard-table-body(tg-taskboard-table-height-fixer) div.taskboard-table-inner div.task-row(ng-repeat="us in userstories track by us.id", ng-class="{blocked: us.is_blocked, 'row-fold':usFolded[us.id]}") div.taskboard-userstory-box.task-column(tg-bo-title="us.blocked_note") - a.icon.icon-vfold.vfold(href="", title="{{'TASKBOARD.TABLE.TITLE_ACTION_FOLD_ROW' | translate}}", ng-click='foldUs(us)', ng-class='{hidden:usFolded[us.id]}') - a.icon.icon-vunfold.vunfold(href="", title="{{'TASKBOARD.TABLE.TITLE_ACTION_UNFOLD_ROW' | translate}}", ng-click='foldUs(us)', ng-class='{hidden:!usFolded[us.id]}') + + svg.icon.icon-fold-row.vfold( + title="{{'TASKBOARD.TABLE.TITLE_ACTION_FOLD_ROW' | translate}}" + ng-click='foldUs(us)' + ng-class='{hidden:usFolded[us.id]}' + ) + use(xlink:href="#icon-fold-row") + + svg.icon.icon-unfold-row.vunfold( + title="{{'TASKBOARD.TABLE.TITLE_ACTION_UNFOLD_ROW' | translate}}" + ng-click='foldUs(us)' + ng-class='{hidden:!usFolded[us.id]}' + ) + use(xlink:href="#icon-fold-row") + h3.us-title a(href="", tg-nav="project-userstories-detail:project=project.slug,ref=us.ref", @@ -41,8 +65,22 @@ div.taskboard-table(tg-taskboard-squish-column) div.task-row(ng-init="us = null", ng-class="{'row-fold':usFolded[null]}") div.taskboard-userstory-box.task-column - a.icon.icon-vfold.vfold(href="", title="{{'TASKBOARD.TABLE.TITLE_ACTION_FOLD_ROW' | translate}}", ng-click='foldUs()', ng-class="{hidden:usFolded[null]}") - a.icon.icon-vunfold.vunfold(href="", title="{{'TASKBOARD.TABLE.TITLE_ACTION_UNFOLD_ROW' | translate}}", ng-click='foldUs()', ng-class="{hidden:!usFolded[null]}") + a.vfold( + href="" + title="{{'TASKBOARD.TABLE.TITLE_ACTION_FOLD_ROW' | translate}}" + ng-click='foldUs()' + ng-class="{hidden:usFolded[null]}" + ) + svg.icon.icon-fold-row + use(xlink:href="#icon-fold-row") + a.vunfold( + href="" + title="{{'TASKBOARD.TABLE.TITLE_ACTION_UNFOLD_ROW' | translate}}" + ng-click='foldUs()' + ng-class="{hidden:!usFolded[null]}" + ) + svg.icon.icon-unfold-row + use(xlink:href="#icon-unfold-row") h3.us-title span(translate="TASKBOARD.TABLE.ROW_UNASSIGED_TASKS_TITLE") include ../components/addnewtask.jade diff --git a/app/partials/includes/modules/team/team-filters.jade b/app/partials/includes/modules/team/team-filters.jade index d2d68cb9..72b104a0 100644 --- a/app/partials/includes/modules/team/team-filters.jade +++ b/app/partials/includes/modules/team/team-filters.jade @@ -7,6 +7,7 @@ section.team-filters fieldset input(type="text", placeholder="{{'TEAM.PLACEHOLDER_INPUT_SEARCH' | translate}}", ng-model="filtersQ") .icon-search-wrapper - a.icon.icon-search(href="", title="{{'COMMON.FILTERS.TITLE_ACTION_FILTER_BUTTON' | translate}}") + svg.icon.icon-search(title="{{'COMMON.FILTERS.TITLE_ACTION_FILTER_BUTTON' | translate}}") + use(xlink:href="#icon-search") - nav(tg-team-filters) \ No newline at end of file + nav(tg-team-filters) diff --git a/app/partials/includes/modules/team/team-table.jade b/app/partials/includes/modules/team/team-table.jade index f2a2e3a2..b8500578 100644 --- a/app/partials/includes/modules/team/team-table.jade +++ b/app/partials/includes/modules/team/team-table.jade @@ -27,10 +27,30 @@ section.table-team.basic-table div.popover.attribute-explanation span(translate="TEAM.EXPLANATION_COLUMN_TOTAL_POWER") - div.hero(tg-team-current-user, stats="stats", currentuser="currentUser", projectid="projectId", issuesEnabled="issuesEnabled", tasksenabled="tasksEnabled", wikienabled="wikiEnabled", ng-if="::currentUser") + div.hero( + tg-team-current-user + stats="stats" + currentuser="currentUser" + project="project" + issuesEnabled="issuesEnabled" + tasksenabled="tasksEnabled" + wikienabled="wikiEnabled" + owner="owner" + ng-if="::currentUser" + ) h2(ng-show="memberships.length") span(translate="TEAM.SECTION_TITLE_TEAM") span {{filtersRole.name || ("TEAM.SECTION_FILTER_ALL" | translate)}} -section.table-team.basic-table(tg-team-members, memberships="memberships", stats="stats", filtersq="filtersQ", filtersrole="filtersRole", issuesEnabled="issuesEnabled", tasksenabled="tasksEnabled", wikienabled="wikiEnabled") +section.table-team.basic-table( + tg-team-members + memberships="memberships" + stats="stats" + filtersq="filtersQ" + filtersrole="filtersRole" + issuesEnabled="issuesEnabled" + tasksenabled="tasksEnabled" + wikienabled="wikiEnabled" + owner="owner" +) diff --git a/app/partials/includes/modules/user-settings-menu.jade b/app/partials/includes/modules/user-settings-menu.jade index 68afaab3..05a7cb7c 100644 --- a/app/partials/includes/modules/user-settings-menu.jade +++ b/app/partials/includes/modules/user-settings-menu.jade @@ -10,3 +10,10 @@ section.admin-menu li#usersettingsmenu-mail-notifications a(href="", tg-nav="user-settings-mail-notifications", title="{{ 'USER_SETTINGS.MENU.EMAIL_NOTIFICATIONS' | translate }}") span.title(translate="USER_SETTINGS.MENU.EMAIL_NOTIFICATIONS") + li#usersettings-contrib(ng-repeat="plugin in userSettingsPlugins") + a( + href="" + tg-nav="user-settings-contrib:plugin=plugin.slug" + ng-class="{active: plugin.slug == currentPlugin.slug}" + ) + span.title {{ plugin.name }} diff --git a/app/partials/issue/iocaine-button.jade b/app/partials/issue/iocaine-button.jade index fecc54d9..25406e92 100644 --- a/app/partials/issue/iocaine-button.jade +++ b/app/partials/issue/iocaine-button.jade @@ -3,7 +3,8 @@ fieldset(title="{{ 'TASK.TITLE_ACTION_IOCAINE' | translate }}") for="is-iocaine" class!="<% if(isEditable){ %>is-editable<% }; %> <% if(isIocaine){ %>active<% }; %>" ) - include ../../svg/iocaine.svg + svg.icon.icon-iocaine + use(xlink:href="#icon-iocaine") input( type="checkbox" id="is-iocaine" diff --git a/app/partials/issue/issue-priority-button.jade b/app/partials/issue/issue-priority-button.jade index 62055e0b..0e82506b 100644 --- a/app/partials/issue/issue-priority-button.jade +++ b/app/partials/issue/issue-priority-button.jade @@ -2,7 +2,8 @@ div(class!="priority-data <% if(editable){ %>clickable<% }%>") span(class="level", style!="background-color:<%- priority.color %>") span(class="priority-priority") <%- priority.name %> <% if(editable){ %> - span(class="icon icon-arrow-bottom") + svg.icon.icon-arrow-down + use(xlink:href="#icon-arrow-down") <% }%> span(class="level-name", translate="COMMON.FIELDS.PRIORITY") diff --git a/app/partials/issue/issue-severity-button.jade b/app/partials/issue/issue-severity-button.jade index 6ffe35dd..377e7346 100644 --- a/app/partials/issue/issue-severity-button.jade +++ b/app/partials/issue/issue-severity-button.jade @@ -2,7 +2,8 @@ div(class!="severity-data <% if(editable){ %>clickable<% }%>") span(class="level", style!="background-color:<%- severity.color %>") span(class="severity-severity") <%- severity.name %> <% if(editable){ %> - span(class="icon icon-arrow-bottom") + svg.icon.icon-arrow-down + use(xlink:href="#icon-arrow-down") <% }%> span(class="level-name", translate="COMMON.FIELDS.SEVERITY") diff --git a/app/partials/issue/issue-type-button.jade b/app/partials/issue/issue-type-button.jade index 675e7d92..9a050bb2 100644 --- a/app/partials/issue/issue-type-button.jade +++ b/app/partials/issue/issue-type-button.jade @@ -2,7 +2,8 @@ div(class!="type-data <% if(editable){ %>clickable<% }%>") span(class="level", style!="background-color:<%- type.color %>") span(class="type-type") <%- type.name %> <% if(editable){ %> - span(class="icon icon-arrow-bottom") + svg.icon.icon-arrow-down + use(xlink:href="#icon-arrow-down") <% }%> span(class="level-name", translate="COMMON.FIELDS.TYPE") diff --git a/app/partials/issue/issues-detail.jade b/app/partials/issue/issues-detail.jade index 81283610..5a2b5a44 100644 --- a/app/partials/issue/issues-detail.jade +++ b/app/partials/issue/issues-detail.jade @@ -46,17 +46,19 @@ div.wrapper( span.block-description-title(translate="COMMON.BLOCKED") span.block-description(ng-bind="issue.blocked_note || ('ISSUES.BLOCKED' | translate)") - div.issue-nav - a.icon.icon-arrow-left( + .issue-nav + svg.icon.icon-arrow-left( ng-show="previousUrl" tg-bo-href="previousUrl" title="{{'ISSUES.TITLE_PREVIOUS_ISSUE' | translate}}" ) - a.icon.icon-arrow-right( + use(xlink:href="#icon-arrow-left") + svg.icon.icon-arrow-right( ng-show="nextUrl" tg-bo-href="nextUrl" title="{{'ISSUES.TITLE_NEXT_ISSUE' | translate}}" ) + use(xlink:href="#icon-arrow-right") .subheader div.tags-block(tg-tag-line, ng-model="issue", required-perm="modify_issue") tg-created-by-display.ticket-created-by(ng-model="issue") diff --git a/app/partials/issue/issues-filters-selected.jade b/app/partials/issue/issues-filters-selected.jade index 90daaacc..187ba9f6 100644 --- a/app/partials/issue/issues-filters-selected.jade +++ b/app/partials/issue/issues-filters-selected.jade @@ -1,8 +1,9 @@ <% _.each(filters, function(f) { %> -a(class="single-filter selected", - data-type!="<%- f.type %>", - data-id!="<%- f.id %>") - span(class="name", style!="<%- f.style %>") - | <%- f.name %> - span(class="icon icon-delete") -<% }) %> \ No newline at end of file +a.single-filter.selected( + data-type!="<%- f.type %>" + data-id!="<%- f.id %>" +) + span.name(style!="<%- f.style %>") <%- f.name %> + svg.icon.icon-close.remove-filter + use(xlink:href="#icon-close") +<% }) %> diff --git a/app/partials/issue/issues-filters.jade b/app/partials/issue/issues-filters.jade index 8738bc6a..3dfa76ef 100644 --- a/app/partials/issue/issues-filters.jade +++ b/app/partials/issue/issues-filters.jade @@ -7,7 +7,8 @@ a(class="single-filter", data-type!="<%- f.type %>", data-id!="<%- f.id %>") span(class="number") <%- f.count %> <% } %> <% if (f.type == "myFilters"){ %> - span(class="icon icon-delete") + svg.icon.icon-close.remove-filter + use(xlink:href="#icon-close") <% } %> <% } %> <% }) %> diff --git a/app/partials/issue/issues-status-button.jade b/app/partials/issue/issues-status-button.jade index 957831a8..39f67881 100644 --- a/app/partials/issue/issues-status-button.jade +++ b/app/partials/issue/issues-status-button.jade @@ -5,7 +5,8 @@ span.detail-status-inner.js-edit-status( ) span <%- status.name %> <% if(editable){ %> - span.icon.icon-arrow-bottom + svg.icon.icon-arrow-down + use(xlink:href="#icon-arrow-down") <% }%> ul.popover.pop-status diff --git a/app/partials/issue/promote-issue-to-us-button.jade b/app/partials/issue/promote-issue-to-us-button.jade index d9a4ad31..2a241ca1 100644 --- a/app/partials/issue/promote-issue-to-us-button.jade +++ b/app/partials/issue/promote-issue-to-us-button.jade @@ -1,5 +1,6 @@ -a.promote-button.editable( +a.promote-button.is-editable( tg-check-permission="add_us" title="{{ 'ISSUES.ACTION_PROMOTE_TO_US' | translate }}" ) - include ../../svg/promote.svg + svg.icon.icon-promote + use(xlink:href="#icon-promote") diff --git a/app/partials/kanban/kanban-task.jade b/app/partials/kanban/kanban-task.jade index a63842bc..a863a07b 100644 --- a/app/partials/kanban/kanban-task.jade +++ b/app/partials/kanban/kanban-task.jade @@ -24,4 +24,9 @@ div.kanban-task-inner(ng-class="{'task-archived': us.isArchived}") span.task-name(ng-bind="us.subject") p(translate="KANBAN.UNDO_ARCHIVED") - a.icon.icon-edit(tg-check-permission="modify_us", href="", title="{{'COMMON.EDIT' | translate}}", ng-hide="us.isArchived") + svg.icon.icon-edit( + tg-check-permission="modify_us" + title="{{'COMMON.EDIT' | translate}}" + ng-hide="us.isArchived" + ) + use(xlink:href="#icon-edit") diff --git a/app/partials/project/wizard-create-project.jade b/app/partials/project/wizard-create-project.jade index 1d52dc48..ca9808be 100644 --- a/app/partials/project/wizard-create-project.jade +++ b/app/partials/project/wizard-create-project.jade @@ -1,46 +1,94 @@ +svg.close.icon.icon-close(title="{{'COMMON.CLOSE' | translate}}") + use(xlink:href="#icon-close") form - section.wizard-step.create-step1(data-step="step1") - div.title - h1(translate="WIZARD.SECTION_TITLE_CHOOSE_TEMPLATE") - p(translate="WIZARD.CHOOSE_TEMPLATE_TEXT") - div.template-wrapper - div.template-inner - 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.backlog(for="template-{{ template.id }}") - span.icon( ng-class="'icon-'+template.slug") - h2 {{ template.name }} - p {{ template.description }} - - fieldset - a.button-next.button-green(href="#", title="{{'PAGINATION.NEXT' | translate}}", translate="PAGINATION.NEXT") - - section.wizard-step.create-step2.active(data-step="step2") - div.title - h1(translate="WIZARD.SECTION_TITLE_CREATE_PROJECT") - p(translate="WIZARD.CREATE_PROJECT_TEXT") - div.template-wrapper - div.template-inner - fieldset - input(type="text", name="name", ng-model="data.name", data-required="true", placeholder="{{'COMMON.FIELDS.NAME' | translate}}", maxlength="45") - fieldset - textarea(name="description", ng-model="data.description", data-required="true", ng-attr-placeholder="{{'COMMON.FIELDS.DESCRIPTION' | translate}}") - fieldset.wizard-action - div - a.button-prev.button.button-gray(href="#", title="{{'PAGINATION.PREVIOUS' | translate}}", translate="PAGINATION.PREVIOUS") - button.button-green.submit-button(type="submit", title="{{'COMMON.CREATE' | translate}}", translate="COMMON.CREATE") - - button(type="submit", class="hidden") - -div.progress-bar - div.progress-state - span(translate="WIZARD.PROGRESS_TEMPLATE_SELECTION") - span(translate="WIZARD.PROGRESS_NAME_DESCRIPTION") - // span Final touches - div.progress-bar-wrapper - div.bar - -a.close(href="#" title="{{'COMMON.CLOSE' | translate}}") - span.icon.icon-delete + 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") + // UX issue + //- a.more-info( + //- href="" + //- title="{{ 'WIZARD.CHOOSE_TEMPLATE_TITLE' | translate }}" + //- translate="WIZARD.CHOOSE_TEMPLATE_INFO" + //- ) + .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 }}") + svg.icon(ng-class="'icon-'+template.slug") + use(xlink:href="{{'#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") + svg.icon.icon-discover + use(xlink:href="#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") + svg.icon.icon-lock + use(xlink:href="#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 new file mode 100644 index 00000000..798bf1fd --- /dev/null +++ b/app/partials/project/wizard-restrictions.jade @@ -0,0 +1,9 @@ +div.create-warning(ng-if="!canCreatePrivateProjects.valid && canCreatePrivateProjects.reason == 'max_private_projects'") + svg.icon.icon-exclamation + use(xlink:href="#icon-exclamation") + span {{ 'WIZARD.MAX_PRIVATE_PROJECTS' | translate }} + +div.create-warning(ng-if="!canCreatePublicProjects.valid && canCreatePublicProjects.reason == 'max_public_projects'") + svg.icon.icon-exclamation + use(xlink:href="#icon-exclamation") + span {{ 'WIZARD.MAX_PUBLIC_PROJECTS' | translate }} diff --git a/app/partials/search/lightbox-search.jade b/app/partials/search/lightbox-search.jade index 189c4890..328deb21 100644 --- a/app/partials/search/lightbox-search.jade +++ b/app/partials/search/lightbox-search.jade @@ -1,8 +1,9 @@ a.close(href="", title="{{'COMMON.CLOSE' | translate}}") - span.icon.icon-delete + svg.icon.icon-close + use(xlink:href="#icon-close") form h2.title(translate="LIGHTBOX.SEARCH.TITLE") fieldset input(type="text", name="text", id="search-text", placeholder="{{'LIGHTBOX.SEARCH.PLACEHOLDER_SEARCH' | translate}}", data-required="true") fieldset - button.button-green.submit-button(type="submit", title="{{' LIGHTBOX.SEARCH.TITLE' | translate}}", translate="LIGHTBOX.SEARCH.TITLE") \ No newline at end of file + button.button-green.submit-button(type="submit", title="{{' LIGHTBOX.SEARCH.TITLE' | translate}}", translate="LIGHTBOX.SEARCH.TITLE") diff --git a/app/partials/task/related-task-create-form.jade b/app/partials/task/related-task-create-form.jade index 35f0f4f9..997b8a60 100644 --- a/app/partials/task/related-task-create-form.jade +++ b/app/partials/task/related-task-create-form.jade @@ -2,15 +2,19 @@ .task-name input(type='text', placeholder="{{'TASK.PLACEHOLDER_SUBJECT' | translate}}") .task-settings - a.icon.icon-floppy(href='', title="{{'COMMON.SAVE' | translate}}") - a.icon.icon-delete.cancel-edit(href='', title="{{'COMMON.CANCEL' | translate}}") + svg.icon.icon-save(title="{{'COMMON.SAVE' | translate}}") + use(xlink:href="#icon-save") + svg.icon.icon-close.cancel-edit(href='', title="{{'COMMON.CANCEL' | translate}}") + use(xlink:href="#icon-close") .status(tg-related-task-status='newTask', ng-model='newTask', not-auto-save='true') a.task-status(href='', title="{{'TASK.TITLE_SELECT_STATUS' | translate}}") span.task-status-bind - span.icon.icon-arrow-bottom + svg.icon.icon-arrow-down + use(xlink:href="#icon-arrow-down") .assigned-to(tg-related-task-assigned-to-inline-edition='newTask', not-auto-save='true') .task-assignedto(title="{{'COMMON.FIELDS.ASSIGNED_TO' | translate}}") figure.avatar - span.icon.icon-arrow-bottom + svg.icon.icon-arrow-down + use(xlink:href="#icon-arrow-down") diff --git a/app/partials/task/related-task-row-edit.jade b/app/partials/task/related-task-row-edit.jade index 6023b2ae..93f32d63 100644 --- a/app/partials/task/related-task-row-edit.jade +++ b/app/partials/task/related-task-row-edit.jade @@ -2,15 +2,19 @@ .task-name input(type='text', value!='<%- task.subject %>', placeholder="{{'TASK.PLACEHOLDER_SUBJECT' | translate}}") .task-settings - a.icon.icon-floppy(href='', title="{{'COMMON.SAVE' | translate}}") - a.icon.icon-delete.cancel-edit(href='', title="{{'COMMON.CANCEL' | translate}}") + svg.icon.icon-save.save-task(title="{{'COMMON.SAVE' | translate}}") + use(xlink:href="#icon-save") + svg.icon.icon-close.cancel-edit(title="{{'COMMON.CANCEL' | translate}}") + use(xlink:href="#icon-close") .status(tg-related-task-status='task', ng-model='task') a.task-status(href='', title="{{'TASK.TITLE_SELECT_STATUS' | translate}}") span.task-status-bind - span.icon.icon-arrow-bottom + svg.icon.icon-arrow-down + use(xlink:href="#icon-arrow-down") .assigned-to(tg-related-task-assigned-to-inline-edition='task') .task-assignedto(title="{{'COMMON.FIELDS.ASSIGNED_TO' | translate}}") figure.avatar - span.icon.icon-arrow-bottom + svg.icon.icon-arrow-down + use(xlink:href="#icon-arrow-down") diff --git a/app/partials/task/related-task-row.jade b/app/partials/task/related-task-row.jade index 0a51af0d..446b2017 100644 --- a/app/partials/task/related-task-row.jade +++ b/app/partials/task/related-task-row.jade @@ -1,23 +1,25 @@ .tasks .task-name - .icon.icon-iocaine a.clickable( tg-nav="project-tasks-detail:project=project.slug,ref=task.ref" title!="#<%- task.ref %> <%- task.subject %>") + svg.icon.icon-iocaine + use(xlink:href="#icon-iocaine") span #<%- task.ref %> span <%- task.subject %> .task-settings <% if(perms.modify_task) { %> - a.icon.icon-edit( + svg.icon.icon-edit.edit-task( href="" title="{{'COMMON.EDIT' | translate}}" ) + use(xlink:href="#icon-edit") <% } %> <% if(perms.delete_task) { %> - a.icon.icon-delete.delete-task( - href="" + svg.icon.icon-trash.delete-task( title="{{'COMMON.DELETE' | translate}}" ) + use(xlink:href="#icon-trash") <% } %> .status( @@ -27,10 +29,12 @@ a.task-status( href="" title="{{'TASK.TITLE_SELECT_STATUS' | translate}}" + ng-style="{'color': task.status_extra_info.color}" ) span.task-status-bind <% if(perms.modify_task) { %> - span.icon.icon-arrow-bottom + svg.icon.icon-arrow-down(ng-style="{'fill': task.status_extra_info.color}") + use(xlink:href="#icon-arrow-down") <% } %> .assigned-to( @@ -42,5 +46,6 @@ ) figure.avatar <% if(perms.modify_task) { %> - span.icon.icon-arrow-bottom + svg.icon.icon-arrow-down + use(xlink:href="#icon-arrow-down") <% } %> diff --git a/app/partials/task/task-detail.jade b/app/partials/task/task-detail.jade index cd416edc..e4060314 100644 --- a/app/partials/task/task-detail.jade +++ b/app/partials/task/task-detail.jade @@ -62,16 +62,20 @@ div.wrapper( ) div.issue-nav - a.icon.icon-arrow-left( + a( ng-show="previousUrl" tg-bo-href="previousUrl" title="{{'TASK.PREVIOUS' | translate}}" ) - a.icon.icon-arrow-right( + svg.icon.icon-arrow-left + use(xlink:href='#icon-arrow-left') + a( ng-show="nextUrl" tg-bo-href="nextUrl" title="{{'TASK.NEXT' | translate}}" ) + svg.icon.icon-arrow-right + use(xlink:href='#icon-arrow-right') .subheader div.tags-block(tg-tag-line, ng-model="task", required-perm="modify_task") tg-created-by-display.ticket-created-by(ng-model="task") diff --git a/app/partials/team/leave-project.jade b/app/partials/team/leave-project.jade index b9d52ae0..04fa75c4 100644 --- a/app/partials/team/leave-project.jade +++ b/app/partials/team/leave-project.jade @@ -1,3 +1,7 @@ -a.leave-project(ng-click="leave()", href="") - span.icon.icon-delete - | {{ 'TEAM.ACTION_LEAVE_PROJECT' | translate }} +a.leave-project( + ng-click="leave()" + href="" +) + svg.icon.icon-close + use(xlink:href="#icon-close") + span {{ 'TEAM.ACTION_LEAVE_PROJECT' | translate }} diff --git a/app/partials/team/team-filter.jade b/app/partials/team/team-filter.jade index d23c8644..67ccfcd0 100644 --- a/app/partials/team/team-filter.jade +++ b/app/partials/team/team-filter.jade @@ -1,10 +1,20 @@ ul li - a(ng-class="{active: !filtersRole.id}", ng-click="ctrl.setRole()", href="") + a( + ng-class="{active: !filtersRole.id}" + ng-click="ctrl.setRole()" + href="" + ) span.title(translate="TEAM.SECTION_FILTER_ALL") - span.icon.icon-arrow-right + svg.icon.icon-arrow-right + use(xlink:href="#icon-arrow-right") li(ng-repeat="role in roles") - a(ng-class="{active: role.id == filtersRole.id}", ng-click="ctrl.setRole(role)", href="") + a( + ng-class="{active: role.id == filtersRole.id}" + ng-click="ctrl.setRole(role)" + href="" + ) span.title(tg-bo-bind="role.name") - span.icon.icon-arrow-right + svg.icon.icon-arrow-right + use(xlink:href="#icon-arrow-right") diff --git a/app/partials/team/team-member-current-user.jade b/app/partials/team/team-member-current-user.jade index b5d81ce1..1c425a44 100644 --- a/app/partials/team/team-member-current-user.jade +++ b/app/partials/team/team-member-current-user.jade @@ -1,17 +1,24 @@ .row .username - figure.avatar + .avatar img(tg-bo-src="currentUser.photo", tg-bo-alt="currentUser.full_name_display") - figcaption - span.name(tg-bo-bind="currentUser.full_name_display") + .avatar-data + .name + span(tg-bo-bind="currentUser.full_name_display") + svg.icon.icon-badge(ng-if="currentUser.id == owner") + use(xlink:href="#icon-badge") + title(translate="COMMON.OWNER") - span.position(tg-bo-bind="currentUser.role_name") + .position(tg-bo-bind="currentUser.role_name") - div(tg-leave-project="", projectid="{{projectId}}") + div(tg-leave-project="", project="project", user="currentUser") - .member-stats(tg-team-member-stats, stats="stats", - user="currentUser.user", - issuesEnabled="issuesEnabled", - tasksenabled="tasksEnabled", - wikienabled="wikiEnabled") + .member-stats( + tg-team-member-stats + stats="stats" + ser="currentUser.user" + issuesEnabled="issuesEnabled" + tasksenabled="tasksEnabled" + wikienabled="wikiEnabled" + ) diff --git a/app/partials/team/team-member-stats.jade b/app/partials/team/team-member-stats.jade index c271ffe0..161683b0 100644 --- a/app/partials/team/team-member-stats.jade +++ b/app/partials/team/team-member-stats.jade @@ -1,22 +1,37 @@ .attribute(ng-if="issuesEnabled") - span.icon.icon-briefcase(ng-style="{'opacity': stats.closed_bugs[userId]}", - ng-class="{'top': stats.closed_bugs[userId] == 1}") + svg.icon.icon-briefcase( + ng-style="{'opacity': stats.closed_bugs[userId]}" + ng-class="{'top': stats.closed_bugs[userId] == 1}" + ) + use(xlink:href="#icon-briefcase") .attribute(ng-if="tasksEnabled") - span.icon.icon-iocaine(ng-style="{'opacity': stats.iocaine_tasks[userId]}", - ng-class="{'top': stats.iocaine_tasks[userId] == 1}") + svg.icon.icon-iocaine( + ng-style="{'opacity': stats.iocaine_tasks[userId]}" + ng-class="{'top': stats.iocaine_tasks[userId] == 1}" + ) + use(xlink:href="#icon-iocaine") .attribute(ng-if="wikiEnabled") - span.icon.icon-writer(ng-style="{'opacity': stats.wiki_changes[userId]}", - ng-class="{'top': stats.wiki_changes[userId] == 1}") + svg.icon.icon-edit( + ng-style="{'opacity': stats.wiki_changes[userId]}" + ng-class="{'top': stats.wiki_changes[userId] == 1}" + ) + use(xlink:href="#icon-edit") .attribute(ng-if="issuesEnabled") - span.icon.icon-bug(ng-style="{'opacity': stats.created_bugs[userId]}", - ng-class="{'top': stats.created_bugs[userId] == 1}") + svg.icon.icon-bug( + ng-style="{'opacity': stats.created_bugs[userId]}" + ng-class="{'top': stats.created_bugs[userId] == 1}" + ) + use(xlink:href="#icon-bug") .attribute(ng-if="tasksEnabled") - span.icon.icon-tasks(ng-style="{'opacity': stats.closed_tasks[userId]}", - ng-class="{'top': stats.closed_tasks[userId] == 1}") + svg.icon.icon-task( + ng-style="{'opacity': stats.closed_tasks[userId]}" + ng-class="{'top': stats.closed_tasks[userId] == 1}" + ) + use(xlink:href="#icon-task") .attribute span.points(ng-bind="stats.totals[userId]") diff --git a/app/partials/team/team-members.jade b/app/partials/team/team-members.jade index 55df4055..1c88dfde 100644 --- a/app/partials/team/team-members.jade +++ b/app/partials/team/team-members.jade @@ -1,15 +1,24 @@ .row.member(ng-repeat="user in memberships | membersFilter:filtersQ:filtersRole") .username - figure.avatar + .avatar img(tg-bo-src="user.photo", tg-bo-alt="user.full_name_display") - figcaption - a.name(tg-nav="user-profile:username=user.username", - title="{{::user.full_name_display}}") {{::user.full_name_display}} + .avatar-data + a.name( + tg-nav="user-profile:username=user.username", + title="{{::user.full_name_display}}" + ) {{::user.full_name_display}} + svg.icon.icon-badge(ng-if="user.id == owner") + use(xlink:href="#icon-badge") + title(translate="COMMON.OWNER") + span.position {{::user.role_name}} - .member-stats(tg-team-member-stats, stats="stats", - user="user.user", - issuesEnabled="issuesEnabled", - tasksenabled="tasksEnabled", - wikienabled="wikiEnabled") + .member-stats( + tg-team-member-stats + stats="stats" + user="user.user" + issuesEnabled="issuesEnabled" + tasksenabled="tasksEnabled" + wikienabled="wikiEnabled" + ) diff --git a/app/partials/us/us-client-requirement-button.jade b/app/partials/us/us-client-requirement-button.jade index b8d7a506..d9cb54a1 100644 --- a/app/partials/us/us-client-requirement-button.jade +++ b/app/partials/us/us-client-requirement-button.jade @@ -3,7 +3,8 @@ label.button-gray.client-requirement( class!="<% if(canEdit){ %>is-editable<% }; %> <% if(isRequired){ %>active<% }; %>" title="{{ 'COMMON.CLIENT_REQUIREMENT' | translate }}" ) - include ../../svg/client-requirement.svg + svg.icon.icon-client-requirement + use(xlink:href="#icon-client-requirement") input( type="checkbox" id="client-requirement" diff --git a/app/partials/us/us-detail.jade b/app/partials/us/us-detail.jade index ec0074b6..b6dcbcd0 100644 --- a/app/partials/us/us-detail.jade +++ b/app/partials/us/us-detail.jade @@ -55,16 +55,20 @@ div.wrapper( span.block-description-title(translate="COMMON.BLOCKED") span.block-description(ng-bind="us.blocked_note || ('US.BLOCKED' | translate)") div.issue-nav - a.icon.icon-arrow-left( + a( ng-show="previousUrl" tg-bo-href="previousUrl" title="{{'US.PREVIOUS' | translate}}" ) - a.icon.icon-arrow-right( + svg.icon.icon-arrow-left + use(xlink:href="#icon-arrow-left") + a( ng-show="nextUrl" tg-bo-href="nextUrl" title="{{'US.NEXT' | translate}}" ) + svg.icon.icon-arrow-right + use(xlink:href="#icon-arrow-right") .subheader .tags-block(tg-tag-line, ng-model="us", required-perm="modify_us") tg-created-by-display.ticket-created-by(ng-model="us") diff --git a/app/partials/us/us-status-button.jade b/app/partials/us/us-status-button.jade index 64f9caaf..5066a9ab 100644 --- a/app/partials/us/us-status-button.jade +++ b/app/partials/us/us-status-button.jade @@ -4,7 +4,8 @@ span.detail-status-inner.js-edit-status( ) span <%- status.name %> <% if(editable){ %> - span.icon.icon-arrow-bottom + svg.icon.icon-arrow-down + use(xlink:href="#icon-arrow-down") <% }%> ul.pop-status.popover diff --git a/app/partials/us/us-team-requirement-button.jade b/app/partials/us/us-team-requirement-button.jade index e34338b1..9a4d186d 100644 --- a/app/partials/us/us-team-requirement-button.jade +++ b/app/partials/us/us-team-requirement-button.jade @@ -3,7 +3,8 @@ label.button-gray.team-requirement( class!=" <% if(canEdit){ %>is-editable<% }; %> <% if(isRequired){ %>active<% }; %>" title="{{ 'COMMON.TEAM_REQUIREMENT' | translate }}" ) - include ../../svg/team-requirement.svg + svg.icon.icon-team-requirement + use(xlink:href="#icon-team-requirement") input( type="checkbox" diff --git a/app/partials/user/lightbox/lightbox-delete-account.jade b/app/partials/user/lightbox/lightbox-delete-account.jade index 5befed76..087e25b3 100644 --- a/app/partials/user/lightbox/lightbox-delete-account.jade +++ b/app/partials/user/lightbox/lightbox-delete-account.jade @@ -1,12 +1,12 @@ a.close(href="", title="{{'close' | translate}}") - span.icon.icon-delete + svg.icon.icon-close + use(xlink:href="#icon-close") form - h2.title(translate="LIGHTBOX.DELETE_ACCOUNT.SECTION_NAME") - p - span.question(translate="LIGHTBOX.DELETE_ACCOUNT.CONFIRM") - span.subtitle(translate="LIGHTBOX.DELETE_ACCOUNT.SUBTITLE") + h2.title(translate="LIGHTBOX.DELETE_ACCOUNT.CONFIRM") + + p(ng-bind-html="'LIGHTBOX.DELETE_ACCOUNT.BLOCK_PROJECT' | translate") div.options - a.button-green(href="", title="{{'COMMON.ACCEPT' | translate}}") - span(translate="COMMON.ACCEPT") - a.button-red(href="", title="{{'Cancel' | translate}}", ) - span(translate="COMMON.CANCEL") + a.button-green(href="", title="{{'LIGHTBOX.DELETE_ACCOUNT.CANCEL' | translate}}") + span(translate="LIGHTBOX.DELETE_ACCOUNT.CANCEL") + a.button-red(href="", title="{{'LIGHTBOX.DELETE_ACCOUNT.ACCEPT' | translate}}") + span(translate="LIGHTBOX.DELETE_ACCOUNT.ACCEPT") diff --git a/app/partials/user/user-change-password.jade b/app/partials/user/user-change-password.jade index 5b5e0b5d..60d7eaf1 100644 --- a/app/partials/user/user-change-password.jade +++ b/app/partials/user/user-change-password.jade @@ -17,6 +17,7 @@ div.wrapper( fieldset label(for="current-password", translate="CHANGE_PASSWORD.FIELD_CURRENT_PASSWORD") input( + data-required="true" type="password" name="password" id="current-password" @@ -28,6 +29,7 @@ div.wrapper( fieldset label(for="new-password", translate="CHANGE_PASSWORD.FIELD_NEW_PASSWORD") input( + data-required="true" type="password" name="new-password" id="new-password" @@ -39,6 +41,7 @@ div.wrapper( fieldset label(for="retype-password", translate="CHANGE_PASSWORD.FIELD_RETYPE_PASSWORD") input( + data-required="true" type="password" name="retype-password" id="retype-password" diff --git a/app/partials/wiki/editable-wiki-content.jade b/app/partials/wiki/editable-wiki-content.jade index 2faf3b51..e5729ed0 100644 --- a/app/partials/wiki/editable-wiki-content.jade +++ b/app/partials/wiki/editable-wiki-content.jade @@ -2,7 +2,11 @@ include ../common/components/wysiwyg.jade .view-wiki-content section.wysiwyg(tg-bind-html='wiki.html') - span.edit.icon.icon-edit(title="{{'COMMON.EDIT' | translate}}", ng-if="wiki") + svg.edit.icon.icon-edit( + title="{{'COMMON.EDIT' | translate}}" + ng-if="wiki" + ) + use(xlink:href="#icon-edit") .edit-wiki-content(style='display: none;') textarea(ng-attr-placeholder="{{'WIKI.PLACEHOLDER_PAGE' | translate}}", @@ -10,5 +14,7 @@ include ../common/components/wysiwyg.jade +wysihelp span.action-container - a.save.icon.icon-floppy(href='', title="{{'COMMON.SAVE' | translate}}") - a.cancel.icon.icon-delete(href='', title="{{'COMMON.CANCEL' | translate}}") + svg.save.icon.icon-save(title="{{'COMMON.SAVE' | translate}}") + use(xlink:href="#icon-save") + svg.cancel.icon.icon-close(title="{{'COMMON.CANCEL' | translate}}") + use(xlink:href="#icon-close") diff --git a/app/partials/wiki/wiki-nav.jade b/app/partials/wiki/wiki-nav.jade index 8e2c97bc..4d3fa0da 100644 --- a/app/partials/wiki/wiki-nav.jade +++ b/app/partials/wiki/wiki-nav.jade @@ -8,7 +8,8 @@ nav a(title!="<%- link.title %>") span.link-title <%- link.title %> <% if (deleteWikiLinkPermission) { %> - span.icon.icon-delete + svg.icon.icon-trash + use(xlink:href="#icon-trash") <% } %> input(type="text" placeholder="{{'COMMON.FIELDS.NAME' | translate}}" class="hidden" value!="<%- link.title %>") <% }) %> diff --git a/app/partials/wiki/wiki.jade b/app/partials/wiki/wiki.jade index 2f55f74d..1b30f29f 100644 --- a/app/partials/wiki/wiki.jade +++ b/app/partials/wiki/wiki.jade @@ -29,5 +29,6 @@ div.wrapper(ng-controller="WikiDetailController as ctrl", ) a.remove(href="", ng-click="ctrl.delete()", ng-if="wiki.id", title="{{'WIKI.REMOVE' | translate}}", tg-check-permission="delete_wiki_page") - span.icon.icon-delete + svg.icon.icon-trash + use(xlink:href="#icon-trash") span(translate="WIKI.REMOVE") diff --git a/app/styles/components/beta.scss b/app/styles/components/beta.scss deleted file mode 100644 index 6856d586..00000000 --- a/app/styles/components/beta.scss +++ /dev/null @@ -1,6 +0,0 @@ -.beta { - left: 0; - position: absolute; - top: 0; - z-index: 9999; -} diff --git a/app/styles/components/buttons.scss b/app/styles/components/buttons.scss index e4f13781..66d0b13a 100755 --- a/app/styles/components/buttons.scss +++ b/app/styles/components/buttons.scss @@ -30,10 +30,20 @@ } .icon { color: $white; - margin-right: .3rem; + } + &.disabled, + &[disabled] { + background: $whitish; + box-shadow: none; + color: $gray-light; + cursor: not-allowed; + opacity: .65; + &:hover { + background: $whitish; + color: $gray-light; + } } } - .trans-button { @extend %medium; @extend %title; @@ -43,23 +53,16 @@ color: $blackish; transition: color .2s linear; } - &:hover, - &.active { - span, - .icon { - color: $primary; - } + .icon { + margin-right: .5rem; } &:visited { color: $blackish; } } - - .submit-button { width: 100%; } - .button-green, a.button-green { @extend %button; @@ -70,7 +73,6 @@ a.button-green { color: $white; } } - .button-gray, a.button-gray { @extend %button; @@ -81,7 +83,6 @@ a.button-gray { color: $white; } } - .button-blackish { @extend %button; background: $blackish; @@ -91,7 +92,6 @@ a.button-gray { color: $white; } } - .button-red { @extend %button; background: $red-light; @@ -103,7 +103,6 @@ a.button-gray { color: $white; } } - .button-block { background: $white; color: $red; @@ -112,19 +111,20 @@ a.button-gray { color: $white; } } - .button-bulk { @extend %button; background: $primary; padding: .35rem .5rem; .icon { + fill: currentColor; margin-right: 0; + position: relative; + top: 1px; } &:hover { background: $primary-light; } } - .button-auth { @extend %button; background: $grayer; diff --git a/app/styles/components/check.scss b/app/styles/components/check.scss index 1cada375..176b1b2e 100644 --- a/app/styles/components/check.scss +++ b/app/styles/components/check.scss @@ -8,12 +8,12 @@ width: 65px; input { cursor: pointer; - height: 500px; + height: 50px; left: -10px; opacity: 0; position: absolute; top: -10px; - width: 500px; + width: 100px; z-index: 999; + div { background-color: $gray; diff --git a/app/styles/components/editor-help.scss b/app/styles/components/editor-help.scss index 64880b9a..5e77956a 100644 --- a/app/styles/components/editor-help.scss +++ b/app/styles/components/editor-help.scss @@ -13,17 +13,20 @@ .help-markdown, .help-button { - @extend %xsmall; &:hover { span { transition: color .2s linear; } .icon { - color: $primary-light; - transition: color .2s linear; + fill: $primary-light; + transition: fill .2s linear; } } + span { + vertical-align: text-top; + } .icon { + fill: $gray-light; margin-right: .2rem; } } diff --git a/app/styles/components/estimation.scss b/app/styles/components/estimation.scss index 39a0f6e3..f9d47a2b 100644 --- a/app/styles/components/estimation.scss +++ b/app/styles/components/estimation.scss @@ -13,7 +13,6 @@ min-height: 2rem; padding: .5rem 1rem; position: relative; - transition: color .3s linear; &.clickable { &:hover, &.active { @@ -22,7 +21,8 @@ .points, .role, .icon-arrow-bottom { - color: $whitish; + color: currentColor; + fill: currentColor; } } } @@ -34,13 +34,15 @@ .role, .icon-arrow-bottom { @extend %text; - color: $whitish; + color: currentColor; + fill: currentColor; } } - .icon-arrow-bottom { - color: $gray-light; + .icon-arrow-down { + fill: currentColor; + height: .6rem; margin-left: .25rem; - vertical-align: middle; + width: .6rem; } .points { @extend %light; diff --git a/app/styles/components/filter.scss b/app/styles/components/filter.scss index 5aa0a398..86994832 100644 --- a/app/styles/components/filter.scss +++ b/app/styles/components/filter.scss @@ -23,8 +23,10 @@ padding: 8px 10px; } .name { + @include ellipsis(100%); background: darken($whitish, 10%); // Fallback display: block; + padding-right: 2rem; width: 100%; } .number { @@ -33,15 +35,14 @@ right: 0; top: 0; } - .icon-delete { - color: $grayer; + .remove-filter { + fill: $gray; position: absolute; right: .5rem; - top: .5rem; - transition: color .3s linear; + top: .75rem; + transition: fill .2s linear; &:hover { - color: $red; - transition: color .3s linear; + fill: $red; } } } diff --git a/app/styles/components/kanban-task.scss b/app/styles/components/kanban-task.scss index 70a6480e..37406516 100644 --- a/app/styles/components/kanban-task.scss +++ b/app/styles/components/kanban-task.scss @@ -9,10 +9,9 @@ margin-bottom: 0; } &:hover { - .icon-edit, - .icon-drag-h { - color: $card-dark; + .icon-edit { display: block; + fill: $card-dark; opacity: 1; transition: color .3s linear, opacity .3s linear; } @@ -96,15 +95,14 @@ bottom: .5rem; position: absolute; } - .icon-edit, - .icon-drag-h { - @extend %large; - color: $card-hover; + .icon-edit { + @include svg-size(1.1rem); + fill: $card-hover; opacity: 0; position: absolute; - transition: opacity .2s linear; &:hover { - color: darken($card-hover, 15%); + cursor: pointer; + fill: darken($card-hover, 15%); transition: color .3s linear; } } diff --git a/app/styles/components/list-items.scss b/app/styles/components/list-items.scss index 0b715bac..12ebdb93 100644 --- a/app/styles/components/list-items.scss +++ b/app/styles/components/list-items.scss @@ -32,9 +32,21 @@ .list-itemtype-project { @include list-itemtype-common; justify-content: space-between; + &.blocked-project { + .list-itemtype-track, + .list-itemtype-project-image, + .list-itemtype-project-name, + .list-itemtype-project-description, + .list-itemtype-project-private { + opacity: .4; + } + } h2 { @extend %large; } + .icon-blocked-project { + @include svg-size(.75rem); + } .list-itemtype-project-data-wrapper { display: flex; } @@ -75,6 +87,20 @@ .list-itemtype-ticket { @include list-itemtype-common; + position: relative; + &.blocked-project { + .ticket-project, + .ticket-type, + .ticket-status, + .list-itemtype-avatar, + .list-itemtype-track, + .ticket-title { + opacity: .4; + } + .icon-blocked-project { + @include svg-size(); + } + } h2 { @extend %medium; } @@ -97,7 +123,6 @@ color: $red; margin-left: .3rem; } - } diff --git a/app/styles/components/markitup.scss b/app/styles/components/markitup.scss index ebb6e881..dd121e40 100644 --- a/app/styles/components/markitup.scss +++ b/app/styles/components/markitup.scss @@ -35,4 +35,8 @@ min-height: 2rem; padding: .3rem; } + .content { + background: $white; + margin-bottom: 0; + } } diff --git a/app/styles/components/notification-message.scss b/app/styles/components/notification-message.scss index a0c93c13..33585da6 100644 --- a/app/styles/components/notification-message.scss +++ b/app/styles/components/notification-message.scss @@ -1,15 +1,22 @@ .notification-message-success { background: rgba($primary-light, .95); box-shadow: 0 25px 10px -15px rgba($black, .05); - opacity: 1; right: -370px; top: 2%; transition: opacity .2s ease-in; width: 370px; &.active { - animation: animSlide 2000ms linear both; + animation: animSlide 2000ms; + animation-fill-mode: forwards; + animation-iteration-count: 1; opacity: 1; } + &.inactive { + animation: animSlideOut .5s; + opacity: 0; + transform: none; + } + p { margin: 0; } @@ -40,8 +47,11 @@ 20% { transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -413.214, 0, 0, 1); } 27.23% { transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -403.135, 0, 0, 1); } 38.34% { transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -399.585, 0, 0, 1); } - 60.56% { transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -400.01, 0, 0, 1); } - 82.78% { opacity: 1; transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -400, 0, 0, 1); } + 100% { transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -400, 0, 0, 1); } +} + +@keyframes animSlideOut { + 0% { opacity: 1; transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -400, 0, 0, 1); } 100% { opacity: 0; transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -400, 0, 0, 1); } } @@ -49,6 +59,7 @@ .notification-message-error { background: rgba($red, .9); + opacity: 1; top: 0; transform: translateY(-100%); width: 100%; @@ -60,10 +71,10 @@ &.inactive { transition: all .6s ease-in-out; } - .icon-notification-error { - @extend %xxlarge; - display: inline; - vertical-align: sub; + .icon-error { + @include svg-size(3rem); + fill: $white; + margin-right: .5rem; } .warning { @extend %xlarge; @@ -79,8 +90,9 @@ margin: 0; } } - .icon-delete { - color: $white; + .icon-close { + cursor: pointer; + fill: $white; position: absolute; right: 1rem; top: 1rem; @@ -131,7 +143,7 @@ .close { margin-right: 1rem; width: 2rem; - path { + svg { fill: $white; } } diff --git a/app/styles/components/private.scss b/app/styles/components/private.scss index 943986c3..8a40e013 100644 --- a/app/styles/components/private.scss +++ b/app/styles/components/private.scss @@ -1,12 +1,4 @@ .private { - display: inline-block; + fill: $gray-light; margin-left: .5rem; - width: .5rem; - svg { - @include svg-size(); - } - path { - fill: $gray-light; - transition: fill .3s linear; - } } diff --git a/app/styles/components/summary.scss b/app/styles/components/summary.scss index 3c25c075..28d6aaa5 100644 --- a/app/styles/components/summary.scss +++ b/app/styles/components/summary.scss @@ -139,8 +139,11 @@ $summary-background: $grayer; margin-right: 2rem; } .icon { - font-size: 1.4rem; + fill: currentColor; + height: 1.5rem; margin-right: .4rem; + vertical-align: middle; + width: 1.5rem; &.icon-stats { color: $primary; float: right; @@ -171,10 +174,11 @@ $summary-background: $grayer; margin-bottom: 1rem; padding: 2rem 6rem; svg { - flex-basis: 5rem; + @include svg-size(4rem); + fill: $primary-dark; + flex-basis: 4rem; flex-shrink: 0; - margin-right: 1rem; - width: 5rem; + margin-right: 2rem; } p { margin: 0; @@ -189,9 +193,6 @@ $summary-background: $grayer; margin: 0; text-transform: uppercase; } - path { - fill: $primary-dark; - } a { @extend %bold; animation: blink 2s infinite; diff --git a/app/styles/components/tag.scss b/app/styles/components/tag.scss index 235c061f..2e0254ac 100644 --- a/app/styles/components/tag.scss +++ b/app/styles/components/tag.scss @@ -41,8 +41,15 @@ margin-right: .25rem; padding: .4rem; width: 14rem; - +.icon-floppy { - margin-left: .5rem; + } + .icon-save { + @include svg-size(); + cursor: pointer; + fill: $grayer; + margin-left: .5rem; + &:hover { + fill: $primary; + transition: .2s linear; } } .tag { @@ -50,14 +57,23 @@ margin: 0 .5rem .5rem 0; padding: .5rem; } + .icon-close { + @include svg-size(.7rem); + fill: $gray-light; + margin-left: .25rem; + &:hover { + cursor: pointer; + fill: $red; + } + } .add-tag { color: $gray-light; &:hover { color: $primary-light; } } - .icon-plus { - @extend %large; + .icon-add { + @include svg-size(.9rem); } .add-tag-text { @extend %small; diff --git a/app/styles/components/taskboard-task.scss b/app/styles/components/taskboard-task.scss index 65788966..7fa2daa4 100644 --- a/app/styles/components/taskboard-task.scss +++ b/app/styles/components/taskboard-task.scss @@ -8,8 +8,8 @@ &:hover { .icon-edit, .icon-drag-h { - color: $card-dark; display: block; + fill: $card-dark; opacity: 1; transition: color .3s linear, opacity .3s linear; } @@ -25,14 +25,14 @@ background: $red; border: 1px solid darken($red, 10%); color: $white; - a, + svg, span { color: $white; + fill: $white; } &:hover { - .icon-edit, - .icon-drag-h { - color: $white; + .icon-edit { + fill: currentColor; } } } @@ -80,14 +80,15 @@ } } .icon-iocaine { - @extend %large; background: $black; border-radius: 5px; - color: $white; + fill: $white; + height: 1.75rem; left: .2rem; - padding: .1rem; + padding: .25rem; position: absolute; top: 1rem; + width: 1.75rem; } .task-assigned { @extend %small; @@ -118,26 +119,21 @@ bottom: .5rem; position: absolute; } - .icon-edit, - .icon-drag-h { - @extend %large; + .icon-edit { + @include svg-size(1.1rem); bottom: .5rem; - color: $card-hover; + cursor: pointer; + fill: $card-hover; opacity: 0; position: absolute; &:hover { - color: $card-dark; + fill: $card-dark; } } .icon-edit, .loading { right: 1rem; } - .icon-drag-h { - @extend %xlarge; - cursor: move; - right: 45%; - } } .task-drag { diff --git a/app/styles/components/track-btn.scss b/app/styles/components/track-btn.scss index ba944611..b4c108e9 100644 --- a/app/styles/components/track-btn.scss +++ b/app/styles/components/track-btn.scss @@ -12,25 +12,23 @@ display: inline-flex; position: relative; .track-inner { - align-items: stretch; + align-items: center; background: $whitish; 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($whitish, 5%); transition: background .3s; } - span { - align-self: center; - } - .icon-arrow-up { - margin-left: auto; - padding: 0 .5rem; - transform: rotate(180deg); + .icon-arrow-down { + height: .6rem; + margin: 0 .5rem 0 auto; + width: .6rem; } } &:hover { @@ -41,7 +39,7 @@ background: rgba($primary-light, .2); } .track-icon { - path { + svg { fill: $primary; } } @@ -53,13 +51,9 @@ .track-icon { padding: .3rem .6rem .3rem .75rem; svg { - height: 1.1rem; + fill: $grayer; position: relative; top: 2px; - width: 1.1rem; - } - path { - fill: $grayer; } } .track-button-counter { @@ -79,7 +73,7 @@ color: $whitish; transition: background .3s; } - path { + svg { fill: $red-light; } } @@ -121,7 +115,7 @@ .watch-check { height: 1.25rem; width: 1.25rem; - path { + svg { fill: $primary-light; } } @@ -155,7 +149,7 @@ background: rgba($primary-light, .2); color: $primary; transition: all .3s; - path { + svg { fill: $primary; } } @@ -163,22 +157,18 @@ background: $red; color: $whitish; svg { + fill: $red-light; transform: rotate(180deg); transition: all .3s; } - path { - fill: $red-light; - } } } svg { + fill: $gray-light; height: 1rem; width: 1rem; } span { display: block; } - path { - fill: $gray-light; - } } diff --git a/app/styles/components/user-list.scss b/app/styles/components/user-list.scss index 299014ae..e39f8016 100644 --- a/app/styles/components/user-list.scss +++ b/app/styles/components/user-list.scss @@ -33,7 +33,7 @@ .user-list-single { &:hover, &.selected { - background: lighten($primary, 58%); + background: rgba(lighten($primary-light, 30%), .3); cursor: pointer; } &:hover { @@ -41,18 +41,22 @@ transition-delay: .2s; } &.is-active { - background: lighten($primary, 55%); + background: rgba(lighten($primary-light, 30%), .3); cursor: pointer; margin-bottom: 1rem; position: relative; transition: background .3s linear; transition-delay: .1s; - .icon-delete { - opacity: 1; - position: absolute; - right: 1rem; - top: 1.5rem; - transition: opacity .2s ease-in; + } + .remove-assigned-to { + fill: $grayer; + opacity: 1; + position: absolute; + right: 1rem; + top: 1.5rem; + transition: all .2s ease-in; + &:hover { + fill: $red; } } } @@ -63,7 +67,7 @@ margin-top: 1rem; .user-list-single { &:hover { - .icon-delete { + .delete-watcher { opacity: 1; transition: opacity .2s ease-in; } @@ -73,14 +77,16 @@ flex: 1; position: relative; } - .icon-delete { + .delete-watcher { + cursor: pointer; + fill: currentColor; opacity: 0; position: absolute; right: .5rem; top: 0; transition: all .2s ease-in; &:hover { - color: $red; + fill: $red; transition: color .3s ease-in; } } diff --git a/app/styles/components/wysiwyg.scss b/app/styles/components/wysiwyg.scss index 56c46839..3953a8dc 100644 --- a/app/styles/components/wysiwyg.scss +++ b/app/styles/components/wysiwyg.scss @@ -48,6 +48,7 @@ } p { margin-bottom: 1rem; + word-wrap: break-word; } .codehilite { overflow: auto; diff --git a/app/styles/core/animation.scss b/app/styles/core/animation.scss index 50bc216c..74d4cd56 100644 --- a/app/styles/core/animation.scss +++ b/app/styles/core/animation.scss @@ -59,6 +59,21 @@ } } +// Drop Down element animations + +@keyframes dropdownFade { + 0% { + opacity: 0; + transform: translateY(-.25rem); + } + 60% { + opacity: 1; + } + 100% { + transform: translateY(0); + } +} + @keyframes blink { 85% { opacity: 1; diff --git a/app/styles/core/base.scss b/app/styles/core/base.scss index c2eba8f0..a531fad6 100644 --- a/app/styles/core/base.scss +++ b/app/styles/core/base.scss @@ -82,22 +82,20 @@ body { padding: 1rem 2rem; } -.icon { - @extend %taiga; -} - .hidden { // scss-lint:disable ImportantRule display: none !important; } .header-with-actions { - align-content: stretch; align-items: center; display: flex; flex-wrap: wrap; justify-content: space-between; margin-bottom: 1rem; + header { + flex: 1; + } .action-buttons { flex-shrink: 0; } diff --git a/app/styles/core/elements.scss b/app/styles/core/elements.scss index cfd2bbf5..3dc9f83e 100644 --- a/app/styles/core/elements.scss +++ b/app/styles/core/elements.scss @@ -31,10 +31,6 @@ sup { vertical-align: super; } -.icon { - vertical-align: middle; -} - .clickable { cursor: pointer; } diff --git a/app/styles/core/forms.scss b/app/styles/core/forms.scss index 1ef309d3..ebd15ecd 100644 --- a/app/styles/core/forms.scss +++ b/app/styles/core/forms.scss @@ -8,6 +8,7 @@ fieldset { input[type="text"], input[type="number"], input[type="password"], +input[type="url"], input[type="email"], input[type="date"], input[type="password"], @@ -40,9 +41,11 @@ textarea { } } .icon-capslock { - bottom: .6rem; - color: $gray; + bottom: .8rem; display: none; + fill: $gray; + height: .9rem; position: absolute; right: 1rem; + width: .9rem; } diff --git a/app/styles/core/typography.scss b/app/styles/core/typography.scss index f353c83c..85c74703 100755 --- a/app/styles/core/typography.scss +++ b/app/styles/core/typography.scss @@ -96,6 +96,10 @@ em { font-style: italic; } +small { + @extend %xsmall; +} + strong { font-weight: bold; } @@ -117,188 +121,3 @@ a:visited { transition: color .3s linear; } } - -// Taiga Icons -[data-icon]::before { - - // scss-lint:disable ImportantRule - content: attr(data-icon); - font-family: 'taiga' !important; - -moz-osx-font-smoothing: grayscale; - -webkit-font-smoothing: antialiased; - font-style: normal !important; - font-variant: normal !important; - font-weight: normal !important; - line-height: 1; - speak: none; - text-transform: none !important; -} - -[class^='icon-']::before, -[class*=' icon-']::before { - - // scss-lint:disable ImportantRule - font-family: 'taiga' !important; - -moz-osx-font-smoothing: grayscale; - -webkit-font-smoothing: antialiased; - font-style: normal !important; - font-variant: normal !important; - font-weight: normal !important; - line-height: 1; - speak: none; - text-transform: none !important; -} - -.icon-bug::before { - content: 'a'; -} -.icon-copy::before { - content: 'b'; -} -.icon-minimize::before { - content: 'c'; -} -.icon-maximize::before { - content: 'd'; -} -.icon-comment::before { - content: 'e'; -} -.icon-plus::before { - content: 'f'; -} -.icon-attachments::before { - content: 'g'; -} -.icon-edit::before { - content: 'h'; -} -.icon-documents::before { - content: 'i'; -} -.icon-delete::before { - content: 'j'; -} -.icon-arrow-bottom::before { - content: 'k'; -} -.icon-arrow-left::before { - content: 'l'; -} -.icon-arrow-right::before { - content: 'm'; -} -.icon-arrow-up::before { - content: 'n'; -} -.icon-briefcase::before { - content: 'o'; -} -.icon-caret-down::before { - content: 'p'; -} -.icon-caret-up::before { - content: 'q'; -} -.icon-check-square::before { - content: 'r'; -} -.icon-notification-error::before { - content: 's'; -} -.icon-settings::before { - content: 't'; -} -.icon-document::before { - content: 'u'; -} -.icon-warning::before { - content: 'v'; -} -.icon-move::before { - content: 'w'; -} -.icon-drag-v::before { - content: 'x'; -} -.icon-filter::before { - content: 'y'; -} -.icon-help::before { - content: 'z'; -} -.icon-reload::before { - content: 'A'; -} -.icon-writer::before { - content: 'B'; -} -.icon-stats::before { - content: 'C'; -} -.icon-floppy::before { - content: 'D'; -} -.icon-warning-alt::before { - content: 'E'; -} -.icon-video::before { - content: 'F'; -} -.icon-bulk::before { - content: 'G'; -} -.icon-vunfold::before { - content: 'H'; -} -.icon-tasks::before { - content: 'I'; -} -.icon-kanban::before { - content: 'J'; -} -.icon-search::before { - content: 'K'; -} -.icon-wiki::before { - content: 'L'; -} -.icon-team::before { - content: 'M'; -} -.icon-vfold::before { - content: 'N'; -} -.icon-issues::before { - content: 'O'; -} -.icon-iocaine::before { - content: 'P'; -} -.icon-archive::before { - content: 'Q'; -} -.icon-capslock::before { - content: 'R'; -} -.icon-upload::before { - content: 'S'; -} -.icon-github::before { - content: 'T'; -} -.icon-timeline::before { - content: 'U'; -} -.icon-scrum::before { - content: 'V'; -} -.icon-project::before { - content: 'W'; -} -.icon-heart::before { - content: 'X'; -} -.icon-eye::before { - content: 'Y'; -} diff --git a/app/styles/dependencies/helpers.scss b/app/styles/dependencies/helpers.scss index 15e473ee..f9080da8 100644 --- a/app/styles/dependencies/helpers.scss +++ b/app/styles/dependencies/helpers.scss @@ -6,13 +6,13 @@ %larger {font-size: 1.6rem;} %xlarge {font-size: 2rem;} %xxlarge {font-size: 3rem;} +%gigantic {font-size: 4rem;} // __Font Types__ // %title {font-family: 'OpenSans-CondLight', Arial, Helvetica, sans-serif; } %light {font-family: 'OpenSans-Light', Arial, Helvetica, sans-serif; } %text {font-family: 'OpenSans-Regular', Arial, Helvetica, sans-serif; } %bold {font-family: 'OpenSans-Semibold', Arial, Helvetica, sans-serif; } -%taiga {font-family: 'taiga'; } %mono {font-family: 'courier new', 'monospace';} %lightbox { @@ -25,14 +25,18 @@ top: 0; z-index: 99910; .close { - @extend %xlarge; - color: $gray; + @include svg-size(2rem); + cursor: pointer; + fill: $gray; position: absolute; - right: 2rem; - top: 1rem; - transition: color .2s; + right: 3rem; + top: 3rem; + transition: fill .2s; &:hover { - color: $primary; + fill: $red-light; + } + svg { + @include svg-size(2rem); } } &.open { @@ -47,6 +51,12 @@ opacity: 0; transition: opacity .3s ease; } + .lb-icon { + @include svg-size(6rem); + display: block; + fill: $whitish; + margin: 1rem auto; + } .title { text-align: center; } diff --git a/app/styles/dependencies/mixins.scss b/app/styles/dependencies/mixins.scss index b9101fad..746cc5d6 100644 --- a/app/styles/dependencies/mixins.scss +++ b/app/styles/dependencies/mixins.scss @@ -17,6 +17,15 @@ } } +@mixin placeholder { + $placeholders: ":-webkit-input" ":-moz" "-moz" "-ms-input"; + @each $placeholder in $placeholders { + &:#{$placeholder}-placeholder { + @content; + } + } +} + @mixin slide($max, $overflow, $min: 0) { max-height: $min; transition: max-height .5s ease-in; @@ -120,24 +129,18 @@ display: flex; .icon { display: block; - margin-right: .2rem; - width: 16px; + margin-right: .25rem; } &.active { color: $primary; - path { + .icon { fill: currentcolor; } } } .icon { - svg { - height: 1rem; - width: 1rem; - } - path { - fill: currentcolor; - } + @include svg-size(.75rem); + fill: $gray-light; } } diff --git a/app/styles/dependencies/mixins/project-card.scss b/app/styles/dependencies/mixins/project-card.scss index 2d1102e8..efd82701 100644 --- a/app/styles/dependencies/mixins/project-card.scss +++ b/app/styles/dependencies/mixins/project-card.scss @@ -25,8 +25,9 @@ display: flex; margin-top: auto; svg { - @include svg-size(.8rem); - fill: $gray-light; + @include svg-size(.75rem); + fill: currentColor; + margin-right: .25rem; } .svg-eye-closed { display: none; @@ -40,7 +41,7 @@ &.active { color: $primary; svg { - fill: $primary; + fill: currentColor; } } } @@ -71,10 +72,8 @@ } } .look-for-people { - svg { - @include svg-size(1rem); - fill: $gray-light; - margin: 0 .5rem; - } + @include svg-size(1rem); + fill: $gray-light; + margin: 0 .5rem; } } diff --git a/app/styles/layout/admin-memberships.scss b/app/styles/layout/admin-memberships.scss index 7d7ad3c4..a3349c34 100644 --- a/app/styles/layout/admin-memberships.scss +++ b/app/styles/layout/admin-memberships.scss @@ -1,9 +1,11 @@ .admin-membership { header { @include clearfix; - a { - float: right; - } + } + .limit-users-warning { + @extend %small; + color: $primary; + margin-right: 1rem; } .check { input { // IE needs smaller size diff --git a/app/styles/layout/backlog.scss b/app/styles/layout/backlog.scss index 77b905f8..044a93b4 100644 --- a/app/styles/layout/backlog.scss +++ b/app/styles/layout/backlog.scss @@ -11,8 +11,8 @@ padding: .4rem 1.5rem; &.active, &:hover { - background: $gray; - color: $whitish; + background: $gray-light; + color: $gray; } &.active { &:hover { diff --git a/app/styles/layout/not-found.scss b/app/styles/layout/not-found.scss index a7ced5bb..15f3345e 100644 --- a/app/styles/layout/not-found.scss +++ b/app/styles/layout/not-found.scss @@ -22,12 +22,9 @@ } h1 { color: $white; - margin-bottom: 3rem; + margin-bottom: 1rem; } a { - color: $primary; - &:hover { - color: $primary-light; - } + color: $primary-light; } } diff --git a/app/styles/layout/ticket-detail.scss b/app/styles/layout/ticket-detail.scss index b71fbed5..c2289163 100644 --- a/app/styles/layout/ticket-detail.scss +++ b/app/styles/layout/ticket-detail.scss @@ -79,7 +79,7 @@ width: 100%; } .us-title-text:hover { - .icon-edit { + .edit { opacity: 1; transition: opacity .3s linear; } @@ -99,13 +99,13 @@ padding-right: 1rem; width: 100%; } - .icon-edit, - .icon-floppy { - @extend %large; - color: $gray-light; + .edit, + .save { + cursor: pointer; + fill: $gray-light; margin-left: .5rem; } - .icon-edit { + .edit { opacity: 0; } .us-related-task { @@ -167,8 +167,9 @@ position: absolute; right: 1rem; top: 1rem; - a { - @extend %xlarge; + svg { + @include svg-size(1.2rem); + fill: currentColor; } } @@ -202,6 +203,7 @@ &:hover { .view-description { .edit { + opacity: 1; top: -1.5rem; transition: all .2s linear; @@ -240,23 +242,28 @@ } } .edit { - color: $grayer; + cursor: pointer; + fill: $gray; } .view-description { .edit { background: $whitish; + height: 2rem; left: 0; opacity: 0; padding: .2rem .5rem; position: absolute; top: 0; transition: all .2s linear; + width: 2rem; } } .edit-description { margin-bottom: 2rem; .save { - top: .4rem; + cursor: pointer; + position: relative; + top: .3rem; } .edit { position: absolute; diff --git a/app/styles/layout/wiki.scss b/app/styles/layout/wiki.scss index 50134ab9..dbec51e2 100644 --- a/app/styles/layout/wiki.scss +++ b/app/styles/layout/wiki.scss @@ -7,13 +7,11 @@ @extend %small; color: $gray-light; &:hover { - span { - color: $grayer; - transition: color .2s linear; - } + color: $red-light; + transition: color .1s linear; .icon { - color: $red; - transition: color .2s linear; + fill: $red-light; + transition: fill .1s linear; } } .icon { @@ -43,20 +41,25 @@ transition: all .2s linear; } } - .edit { - background: $whitish; - left: 0; - opacity: 0; - padding: .2rem .5rem; - position: absolute; - top: 0; - transition: all .2s linear; + } + .edit { + @include svg-size(2rem); + background: $whitish; + left: 0; + opacity: 0; + padding: .2rem .5rem; + position: absolute; + top: 0; + transition: all .2s linear; + &:hover { + cursor: pointer; } } .edit-wiki-content { .icon { &:hover { - color: $grayer; + cursor: pointer; + fill: $primary-dark; opacity: .3; transition: all .2s linear; } diff --git a/app/styles/modules/admin/admin-common.scss b/app/styles/modules/admin/admin-common.scss index b247f1e2..fe3fe486 100644 --- a/app/styles/modules/admin/admin-common.scss +++ b/app/styles/modules/admin/admin-common.scss @@ -10,11 +10,13 @@ } .total { @extend %large; + align-items: center; background-color: $whitish; color: $grayer; + display: flex; padding: .3rem 1rem; &:hover { - .edit-value { + .icon-edit { opacity: 1; transition: opacity .3s linear; } diff --git a/app/styles/modules/admin/admin-custom-attributes.scss b/app/styles/modules/admin/admin-custom-attributes.scss index ee7a21d5..ef5a1767 100644 --- a/app/styles/modules/admin/admin-custom-attributes.scss +++ b/app/styles/modules/admin/admin-custom-attributes.scss @@ -27,7 +27,7 @@ background: rgba($primary-light, .05); cursor: move; transition: background .2s linear; - .icon-drag-v, + .icon-drag, .custom-options { opacity: 1; transition: opacity .2s linear; @@ -47,15 +47,15 @@ border-bottom: 1px solid $whitish; color: $gray; } - .icon-drag-v { - color: $gray-light; + .icon-drag { + fill: $gray-light; opacity: 0; padding: 0 .1rem; transition: color .2s linear; vertical-align: middle; &:hover { - color: $gray; cursor: move; + fill: $gray; transition: color .2s linear; } } @@ -83,15 +83,20 @@ flex-shrink: 0; opacity: 0; text-align: center; - a { - color: $gray-light; + svg { + cursor: pointer; + fill: $gray-light; margin-right: .5rem; transition: color .2s linear; vertical-align: middle; &:hover { - color: $primary; + fill: $primary; transition: color .2s linear; } + &.icon-trash, + &.icon-close { + fill: $red-light; + } } } .custom-options-wrapper { diff --git a/app/styles/modules/admin/admin-functionalities.scss b/app/styles/modules/admin/admin-functionalities.scss index 1a02ff99..cc29e8e6 100644 --- a/app/styles/modules/admin/admin-functionalities.scss +++ b/app/styles/modules/admin/admin-functionalities.scss @@ -1,62 +1,75 @@ .admin-functionalities { - form { - display: flex; - flex-wrap: wrap; + .module-container { + max-width: 900px; + width: 100%; } - .functionality { + .module { align-content: center; - align-items: center; - background-color: $whitish; + align-items: flex-start; + border-bottom: 1px solid $whitish; display: flex; - flex-direction: column; - justify-content: center; - margin-bottom: .3rem; - margin-right: .3rem; - opacity: .5; - padding: 1rem; - position: relative; - transition: all .2s linear; - vertical-align: top; - width: 32%; + padding: 1rem 0; &.active { - background-color: rgba($primary, .3); - opacity: 1; - } - .icon { - @extend %xxlarge; - flex-basis: 60px; - margin: 0 auto; - min-width: 60px; - } - .desc { - text-align: center; - width: 100%; - } - .activate-input { - display: none; - +label { - color: $white; - cursor: pointer; - display: block; - text-align: center; + .module-icon .icon, + .module-name { + color: $primary; + fill: $primary; } } - .title { - @extend %bold; - display: block; - } - select { - margin-top: 1rem; + } + .module-icon { + flex-basis: 3rem; + flex-shrink: 0; + margin: 0 .5rem 0 0; + .icon { + @include svg-size(3rem); + fill: $gray-light; } } + .module-name { + @extend %bold; + @extend %large; + color: $gray-light; + flex-basis: 100px; + flex-shrink: 0; + margin: 0 .5rem; + } + .module-desc { + @extend %small; + color: $gray-light; + flex: 1; + margin: 0 2rem 0 0; + p { + margin: 0; + } + } + .module-desc-options, .videoconference-attributes { - select { - margin-bottom: .5rem; + align-items: flex-start; + display: flex; + margin-top: .5rem; + fieldset, + .icon { + margin: 0 .5rem; + } + .icon { + @include svg-size(2.5rem); + align-self: center; + cursor: pointer; + fill: $gray-light; + &:hover { + fill: $primary; + } } } - .button-green { - color: $white; - display: block; - text-align: center; + .module-scrum { + .icon { + align-self: flex-end; + } + } + .module-videoconference { + .icon { + align-self: flex-start; + } } } diff --git a/app/styles/modules/admin/admin-membership-table.scss b/app/styles/modules/admin/admin-membership-table.scss index 93b42f1d..5780eaf9 100644 --- a/app/styles/modules/admin/admin-membership-table.scss +++ b/app/styles/modules/admin/admin-membership-table.scss @@ -62,10 +62,10 @@ } } .delete { - @extend %large; - color: $gray-light; + fill: $gray-light; + transition: fill .2s; &:hover { - color: $red; + fill: $red; } } .pending { diff --git a/app/styles/modules/admin/admin-project-profile.scss b/app/styles/modules/admin/admin-project-profile.scss index 5e4e0483..fe3984be 100644 --- a/app/styles/modules/admin/admin-project-profile.scss +++ b/app/styles/modules/admin/admin-project-profile.scss @@ -1,5 +1,4 @@ @import '../dependencies/mixins/profile-form'; - .project-details { @include profile-form; .looking-for-people { @@ -31,7 +30,6 @@ animation-delay: .1s; } } - .delete-project { @extend %xsmall; display: block; @@ -52,9 +50,7 @@ vertical-align: middle; } } - } - .project-privacy-settings { display: flex; margin-bottom: .5rem; @@ -103,4 +99,76 @@ display: block; } } + .privacy-project[disabled] { + + label { + background: $whitish; + box-shadow: none; + color: $gray-light; + cursor: not-allowed; + opacity: .65; + &:hover { + background: $whitish; + color: $gray-light; + } + } + } +} +tg-admin-project-restrictions { + p { + @extend %xsmall; + text-align: center; + } + a { + color: $primary; + } + span { + display: block; + } + span:first-child { + &::before { + border: 1px solid $red-light; + border-radius: 6px; + color: $red-light; + content: '!'; + display: inline-block; + height: 12px; + line-height: 12px; + margin-right: .5rem; + text-align: center; + width: 12px; + } + } +} +.admin-project-profile-owner-actions { + align-items: center; + border-top: 1px solid $whitish; + display: flex; + justify-content: space-between; + padding-top: 1rem; + a { + color: $primary; + &:hover { + color: $primary-light; + transition: color .2s; + } + } + img { + width: 100%; + } + .owner-info { + flex: 1; + padding-left: .5rem; + } + .owner-info-title { + color: $gray-light; + } + .owner-name { + @extend %bold; + } + .owner-avatar { + width: 2.5rem; + } + .request { + flex-shrink: 0; + } } diff --git a/app/styles/modules/admin/admin-roles.scss b/app/styles/modules/admin/admin-roles.scss index b11656d4..cd817290 100644 --- a/app/styles/modules/admin/admin-roles.scss +++ b/app/styles/modules/admin/admin-roles.scss @@ -4,13 +4,23 @@ @extend %light; color: $grayer; } - .edit-value { - @extend %medium; - color: $gray-light; + .icon { + &:hover { + fill: $primary; + transition: fill .2s linear; + } + } + .icon-edit { cursor: pointer; + fill: $gray-light; margin-left: .5rem; opacity: 0; - transition: opacity .3s linear; + transition: opacity .2s linear; + } + .icon-save { + fill: $gray-light; + margin-left: .5rem; + transition: fill .2s linear; } .edit-role { background-color: $whitish; @@ -21,15 +31,6 @@ background-color: $white; width: 50%; } - .icon-floppy { - color: $gray-light; - margin-left: .5rem; - transition: color.3s linear; - &:hover { - color: $primary; - transition: color.3s linear; - } - } } .any-computable-role { background: $red; diff --git a/app/styles/modules/admin/admin-third-parties-webhooks.scss b/app/styles/modules/admin/admin-third-parties-webhooks.scss index 8ef4fa0c..825314eb 100644 --- a/app/styles/modules/admin/admin-third-parties-webhooks.scss +++ b/app/styles/modules/admin/admin-third-parties-webhooks.scss @@ -1,5 +1,6 @@ .admin-webhooks { .webhooks-table { + margin-bottom: 1rem; .row { border-bottom: 0; padding: .5rem 0; @@ -60,14 +61,13 @@ min-width: 100px; text-align: center; a { - color: $gray-light; margin-right: .5rem; - transition: color .2s linear; - vertical-align: middle; + } + svg { + fill: $gray-light; &:hover { - color: $primary; - transition: color .2s linear; - + fill: $primary; + transition: fill .2s linear; } } } diff --git a/app/styles/modules/admin/project-csv.scss b/app/styles/modules/admin/project-csv.scss index e6f16a08..4c370888 100644 --- a/app/styles/modules/admin/project-csv.scss +++ b/app/styles/modules/admin/project-csv.scss @@ -13,8 +13,12 @@ @extend %small; min-width: 110px; } - .icon { + .icon:not(.icon-clipboard) { + fill: currentColor; + height: .9rem; margin-right: .3rem; + vertical-align: middle; + width: .9rem; } } .field-with-options { diff --git a/app/styles/modules/admin/project-values.scss b/app/styles/modules/admin/project-values.scss index 7ef3ae5b..d55a0516 100644 --- a/app/styles/modules/admin/project-values.scss +++ b/app/styles/modules/admin/project-values.scss @@ -9,11 +9,11 @@ position: relative; } .icon { - @extend %large; - color: $gray-light; + cursor: pointer; + fill: $gray-light; opacity: 0; &:hover { - color: $grayer; + fill: $grayer; transition: all .2s ease-in; } } @@ -61,16 +61,10 @@ } .project-values-settings { - a { - @extend %large; - color: $gray; + svg { margin-right: .5rem; - &:hover { - color: $primary; - transition: color .3s linear; - .icon-delete { - color: $red; - } + &.icon-trash { + fill: $red-light; } } } diff --git a/app/styles/modules/backlog/backlog-table.scss b/app/styles/modules/backlog/backlog-table.scss index 9b84249f..934d5b64 100644 --- a/app/styles/modules/backlog/backlog-table.scss +++ b/app/styles/modules/backlog/backlog-table.scss @@ -28,25 +28,12 @@ flex-grow: 0; flex-shrink: 0; } - .votes { - color: $gray; - flex-basis: 65px; - flex-grow: 0; - flex-shrink: 0; - text-align: center; - &.inactive { - color: $gray-light; - } - &.is-voted { - color: $primary-light; - } - } .user-stories { overflow: hidden; width: 100%; } .status { - flex-basis: 100px; + flex-basis: 120px; flex-grow: 0; flex-shrink: 0; } @@ -56,6 +43,30 @@ } } + .votes { + color: $gray; + flex-basis: 65px; + flex-grow: 0; + flex-shrink: 0; + text-align: center; + &.inactive { + color: $gray-light; + svg { + fill: $gray-light; + } + } + &.is-voted { + color: $primary-light; + fill: $primary-light; + } + svg { + fill: $gray; + height: .75rem; + margin-right: .25rem; + vertical-align: middle; + width: .75rem; + } + } .status, .points { position: relative; @@ -70,7 +81,8 @@ } } .icon { - color: $gray-light; + @include svg-size(.75rem); + fill: currentColor; margin-left: .2rem; } } @@ -122,7 +134,7 @@ @extend %medium; border-bottom: 2px solid $gray-light; flex-wrap: nowrap; - padding-right: 30px; + padding-right: 1rem; } .points { cursor: pointer; @@ -145,7 +157,7 @@ transition: background .2s ease-in; transition-delay: .2s; .us-settings, - .icon-drag-v { + .icon-drag { opacity: 1; transition: all .2s ease-in; } @@ -165,6 +177,11 @@ cursor: text; } } + .icon-arrow-down { + fill: $gray-light; + height: .7rem; + width: .7rem; + } } .sortable-placeholder { background: $whitish; @@ -241,26 +258,24 @@ top: -3px; } } - .us-settings a, - .icon-drag-v { - @extend %large; - color: $gray-light; - transition: all .2s ease-in; - width: 30px; - &:hover { - color: $grayer; - transition: all .2s ease-in; - } - } .us-settings { flex-shrink: 0; - margin: 0 0 0 2rem; + margin-left: 2rem; opacity: 0; + svg { + fill: $gray-light; + margin-right: .5rem; + transition: fill .2s ease-in; + &:hover { + fill: $primary-light; + } + } } - .icon-drag-v { + .icon-drag { cursor: move; + fill: $gray-light; opacity: 0; - padding: .1rem .5rem 0 0; + padding: .1rem; } .readonly { cursor: auto; diff --git a/app/styles/modules/backlog/sprints.scss b/app/styles/modules/backlog/sprints.scss index 7ba4d2cb..7029229d 100644 --- a/app/styles/modules/backlog/sprints.scss +++ b/app/styles/modules/backlog/sprints.scss @@ -16,13 +16,9 @@ background: $primary-light; } svg { - height: 1.4rem; - max-height: 1.4rem; - max-width: 1.5rem; - width: 1.5rem; - } - path { fill: $whitish; + height: 1.4rem; + width: 1.5rem; } } .filter-closed-sprints { @@ -53,7 +49,7 @@ @extend %title; @include ellipsis($width: 90%); display: inline-block; - margin-right: 3px; + margin-right: .5rem; } } .sprint { @@ -69,24 +65,8 @@ transition: opacity .2s ease-in; } } - .icon { - display: inline-block; - } - .icon-arrow-up { - transform: rotate(90deg); - transition: all .2s linear; - vertical-align: baseline; - &.active { - transform: rotate(180deg); - transition: all .2s linear; - } - &:hover { - color: $primary-light; - transition: color .2s linear; - } - } - .icon-edit { - color: $gray-light; + .edit-sprint { + fill: $gray-light; opacity: 0; position: absolute; right: 0; @@ -94,8 +74,9 @@ transition: opacity .2s ease-in; vertical-align: baseline; &:hover { - color: $primary; - transition: color .2s ease-in; + cursor: pointer; + fill: $primary; + transition: fill .2s ease-in; } } .number { @@ -129,6 +110,20 @@ } } } + .compact-sprint { + transform: rotate(0); + transition: all .2s; + &.active { + transform: rotate(90deg); + transition: all .2s; + } + &:hover { + .icon { + fill: $primary-light; + transition: color .2s; + } + } + } .sprint-progress-bar { background: $gray-light; border-radius: 2px; diff --git a/app/styles/modules/backlog/taskboard-table.scss b/app/styles/modules/backlog/taskboard-table.scss index dae0c4fb..cd99e5a4 100644 --- a/app/styles/modules/backlog/taskboard-table.scss +++ b/app/styles/modules/backlog/taskboard-table.scss @@ -12,7 +12,7 @@ $column-margin: 0 10px 0 0; margin: 0; min-height: 0; .taskboard-task-inner { - padding: .2rem; + padding: .1rem; } .taskboard-tagline, .taskboard-text { @@ -89,11 +89,12 @@ $column-margin: 0 10px 0 0; } .icon { @extend %medium; - color: $gray-light; + fill: $gray-light; margin-right: .3rem; - transition: color .2s linear; + transition: fill .2s linear; &:hover { - color: $primary; + cursor: pointer; + fill: $primary; } &.hfold, &.hunfold { @@ -157,8 +158,8 @@ $column-margin: 0 10px 0 0; background: rgba($red, .6); } - .taskboard-userstory-box a, - .taskboard-userstory-box a:hover, + .taskboard-userstory-box svg, + .taskboard-userstory-box svg:hover, .points-value, .points-value:hover { color: $white; @@ -174,7 +175,7 @@ $column-margin: 0 10px 0 0; @include ellipsis(100%); } .points-value, - .icon-plus, + .icon-add, .icon-bulk { display: none; } @@ -184,21 +185,23 @@ $column-margin: 0 10px 0 0; .taskboard-userstory-box { padding: .5rem .5rem .5rem 1.5rem; .icon { - color: $gray-light; + cursor: pointer; + fill: $gray-light; position: absolute; right: .5rem; top: .7rem; - transition: color .2s linear; + transition: fill .2s linear; &:hover { - color: $primary; + fill: $primary; } - &.icon-plus { + &.icon-add { right: 2rem; } - &.icon-vfold, - &.icon-vunfold { + &.icon-fold-row, + &.icon-unfold-row { left: 0; right: inherit; + top: 1rem; } } } diff --git a/app/styles/modules/common/assigned-to.scss b/app/styles/modules/common/assigned-to.scss index 71a41c07..907c3255 100644 --- a/app/styles/modules/common/assigned-to.scss +++ b/app/styles/modules/common/assigned-to.scss @@ -7,11 +7,9 @@ padding: 1rem 0; position: relative; &:hover { - .assigned-to { - .icon-delete { - opacity: 1; - transition: opacity .3s linear; - } + .remove-user { + opacity: 1; + transition: opacity .3s linear; } } .loading-spinner { @@ -60,15 +58,33 @@ .assigned-to-options { display: inline-block; } - .icon-delete { - color: $gray-light; - opacity: 0; - position: absolute; - right: 0; - top: 2rem; + .user-assigned, + .assign-to-me { + color: $primary; + cursor: default; &:hover { - color: $red; + cursor: pointer; } + .icon { + fill: currentColor; + height: .75rem; + width: .75rem; + } + span { + @include ellipsis(80%); + } + } + } + .remove-user { + fill: $gray; + opacity: 0; + position: absolute; + right: .5rem; + top: 2rem; + &:hover { + cursor: pointer; + fill: $red; + transition: fill .2s; } } .user-assigned, diff --git a/app/styles/modules/common/category-config.scss b/app/styles/modules/common/category-config.scss index d0a29f25..43a5479d 100644 --- a/app/styles/modules/common/category-config.scss +++ b/app/styles/modules/common/category-config.scss @@ -9,6 +9,15 @@ display: flex; padding: 1rem; position: relative; + &.open-drawer { + .icon { + transform: rotate(90deg); + } + } + } + .icon { + transform: rotate(0); + transition: all .4s; } .resume-title { width: 280px; @@ -35,11 +44,6 @@ } } } - .icon { - @extend %xlarge; - flex: 1; - text-align: right; - } .category-items { @include slide(400px, hidden); background-color: $whitish; diff --git a/app/styles/modules/common/colors-table.scss b/app/styles/modules/common/colors-table.scss index 314c87de..fa1f15bb 100644 --- a/app/styles/modules/common/colors-table.scss +++ b/app/styles/modules/common/colors-table.scss @@ -10,6 +10,21 @@ padding-left: 50px; } } + .table-main { + .row:hover { + background: lighten($primary, 60%); + cursor: move; + transition: background .2s ease-in; + .icon { + opacity: 1; + transition: opacity .2s ease-in; + } + .options-column { + opacity: 1; + transition: opacity .3s linear; + } + } + } form { &:last-child { .row { @@ -23,19 +38,6 @@ display: flex; justify-content: center; padding: 1rem; - &:hover { - background: lighten($primary, 60%); - cursor: move; - transition: background .2s ease-in; - .icon { - opacity: 1; - transition: opacity .2s ease-in; - } - .options-column { - opacity: 1; - transition: opacity .3s linear; - } - } &:last-child { border: 0; } @@ -112,26 +114,27 @@ width: 40px; } .icon { - @extend %large; - color: $gray-light; + cursor: pointer; + fill: $gray-light; margin-right: 1rem; opacity: 0; &:hover { - color: $primary; + fill: $primary; transition: all .2s ease-in; } - &.icon-check-square { + &.icon-check { + cursor: default; + fill: $primary; opacity: 1; } - } - .icon-delete { - &:hover { - color: $red; + &.icon-drag { + cursor: move; + } + &.icon-trash { + &:hover { + fill: $red-light; + } } - } - .icon-check-square { - @extend %large; - color: $primary; } } diff --git a/app/styles/modules/common/custom-fields.scss b/app/styles/modules/common/custom-fields.scss index ed9816b2..4adab4e5 100644 --- a/app/styles/modules/common/custom-fields.scss +++ b/app/styles/modules/common/custom-fields.scss @@ -8,15 +8,8 @@ display: flex; justify-content: space-between; padding: .5rem 1rem; - .icon-arrow-bottom { - @extend %large; + .icon { cursor: pointer; - transform: rotate(-90deg); - transition: transform .2s linear; - &.open { - transform: rotate(0); - transition: transform .2s linear; - } } } .custom-fields-body { @@ -37,14 +30,16 @@ margin-top: .5rem; } } - .custom-field-options { - opacity: 0; - transition: opacity .2s linear; - a { - color: $gray-light; - } - a:hover { - color: $primary; + } + .custom-field-options { + margin: 0; + opacity: 0; + transition: opacity .2s linear; + svg { + cursor: pointer; + fill: $gray-light; + &:hover { + fill: $primary; } } } @@ -62,9 +57,6 @@ line-height: .9rem; } } - .custom-field-options { - margin: 0; - } .custom-field-value { @extend %light; align-items: flex-start; diff --git a/app/styles/modules/common/history.scss b/app/styles/modules/common/history.scss index 96e4fdf4..f39e2247 100644 --- a/app/styles/modules/common/history.scss +++ b/app/styles/modules/common/history.scss @@ -7,7 +7,7 @@ &:hover { .icon { color: $primary; - transform: rotate(180deg); + transform: rotate(90deg); transition: all .2s linear; } } @@ -40,33 +40,40 @@ } .history-tabs { @extend %title; - border-bottom: 3px solid $gray-light; + border-bottom: 1px solid $whitish; + border-top: 1px solid $whitish; margin-bottom: 0; - padding: .5rem 0; li { @extend %large; display: inline-block; &:first-child { - border-right: 1px solid $gray-light; + border-right: 1px solid $whitish; } &:last-child { border-right: 0; } } a { + background: $white; color: $gray-light; - padding: 0 2rem; + display: inline-block; + padding: .5rem 2rem; + position: relative; transition: color .2s ease-in; &.active { - color: $grayer; + color: $primary; + top: 1px; } &:hover { - color: $primary; + color: $grayer; transition: color .2s ease-in; } } .icon { + fill: currentColor; + height: .75rem; margin-right: .5rem; + width: .75rem; } } .add-comment { @@ -110,6 +117,14 @@ .preview-icon { position: absolute; right: 1rem; + top: .5rem; + } + .edit { + fill: $gray-light; + &:hover { + cursor: pointer; + fill: $primary; + } } .preview-icon { opacity: 0; @@ -252,14 +267,15 @@ margin-bottom: 0; } .comment-delete { - color: $red; + cursor: pointer; + fill: $red-light; opacity: 0; position: absolute; - right: 0; + right: .5rem; top: 2rem; transition: all .2s linear; &:hover { - color: $red-light; + fill: $red; transition: color .2s linear; } } diff --git a/app/styles/modules/common/lightbox.scss b/app/styles/modules/common/lightbox.scss index 7f57453c..def10271 100644 --- a/app/styles/modules/common/lightbox.scss +++ b/app/styles/modules/common/lightbox.scss @@ -1,8 +1,8 @@ .lightbox { @extend %lightbox; h2 { - @extend %larger; - @extend %text; + @extend %xlarge; + @extend %light; } } @@ -57,10 +57,14 @@ } .requirement, .iocaine { + vertical-align: middle; &:hover { background: $primary-light; border: 1px solid $primary; } + svg { + @include svg-size(.75rem); + } } .blocked { @@ -142,52 +146,62 @@ .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 { - position: relative; - &:first-child { - flex-basis: 400px; - flex-grow: 3; - } + display: inline-block; + flex: 1; + margin: 0 .5rem 0 0; &:last-child { - flex-basis: 200px; - flex-grow: 1; - margin-left: .5rem; + flex-basis: 30px; + flex-grow: 0; + flex-shrink: 0; } + &:first-child { + flex-basis: 20%; + } + } - .icon-delete { - @extend %large; - } - } - .extra-text { - margin-top: 1rem; - } - fieldset { - margin-bottom: 0; - } - select { - width: 80%; } .icon { - @extend %large; + @include svg-size(1.25rem); + fill: $gray; margin-left: .5rem; } - .icon-delete { - @extend %xlarge; + .icon-add { &:hover { - color: $red; + fill: $primary; + transition: fill .2s; } } - .button { - margin-top: 1rem; + .icon-trash { + fill: $red-light; + &:hover { + fill: $red; + transition: fill .2s; + } + } + .member-limit-warning { + @extend %small; + background: $red-light; + color: $white; + margin: 1rem 0; + padding: 1rem 2rem; + text-align: center; } .help-text { @extend %small; - padding: .5rem 1rem; + @extend %light; + margin-top: 1rem; } .checksley-error-list { right: .5rem; @@ -234,17 +248,18 @@ } .delete-sprint { @extend %small; - color: $grayer; - display: block; - margin-top: 1rem; - text-align: right; - a { - color: $gray-light; - margin-left: .5rem; + color: $gray; + float: right; + margin: 1rem .25rem 0 0; + transition: color .3s linear; + .icon { + fill: currentColor; + } + &:hover { + color: $red; transition: color .3s linear; - &:hover { - color: $red; - transition: color .3s linear; + .icon { + fill: currentColor; } } } @@ -316,9 +331,15 @@ } } } + .warning { + @extend %bold; + } } .lightbox-delete-account { + p { + text-align: center; + } form { flex-basis: 420px; flex-grow: 0; @@ -330,10 +351,6 @@ line-height: 2rem; text-align: center; } - .subtitle { - @extend %large; - @extend %title; - } .newsletter { margin: 1rem 0; text-align: center; @@ -491,7 +508,7 @@ .user-list-single { &:hover, &.selected { - background: lighten($primary, 58%); + background: rgba(lighten($primary-light, 30%), .3); cursor: pointer; } &:hover { @@ -505,6 +522,33 @@ padding: .5rem; text-align: center; } + .submit-button { + margin-top: 1rem; + } + .add-comment { + position: relative; + text-align: center; + .icon-close { + cursor: pointer; + fill: $gray; + position: absolute; + right: 0; + top: 0; + transition: fill .2s; + &:hover { + fill: $red-light; + } + svg { + @include svg-size(2rem); + } + } + textarea { + margin-top: 1rem; + } + a { + color: $primary; + } + } } .lb-create-edit-userstory { @@ -523,8 +567,47 @@ margin-right: 0; } &:last-child { + flex-basis: 100%; margin: .1rem 0; min-width: 100%; } } } + +.lightbox-import-error { + text-align: center; + .content { + width: 500px; + } + h2 { + margin-top: 1rem; + } + .description { + a { + color: $primary; + } + } + img { + height: 5rem; + } +} + +.lightbox-leave-project-warning { + text-align: center; + .icon { + fill: $gray-light; + height: 3rem; + margin-bottom: 1rem; + width: 3rem; + } + .content { + width: 500px; + } +} + +.lightbox-request-ownership { + text-align: center; + .content { + width: 500px; + } +} diff --git a/app/styles/modules/common/nav.scss b/app/styles/modules/common/nav.scss index 5f49450c..5703357b 100644 --- a/app/styles/modules/common/nav.scss +++ b/app/styles/modules/common/nav.scss @@ -3,12 +3,12 @@ $label-arrow-wh: 12px; tg-project-menu { background-position: 0 -300px; display: inline-block; - min-height: 95%; + min-height: calc(100vh - 40px); min-width: 50px; padding: 1rem 0; position: relative; text-transform: uppercase; - z-index: 9; + z-index: 99; .menu { &.menu-fixed { position: fixed; @@ -23,15 +23,17 @@ tg-project-menu { position: relative; text-align: center; a { - color: $white; display: block; - padding: .75rem .8rem; + padding: 1.1rem .8rem; position: relative; } a:hover { background: rgba($black, .2); - color: $primary-light; transition: color .3s linear; + svg { + fill: $primary-light; + transition: fill .3s linear; + } .helper { @extend %small; animation: slideLeft 200ms ease-in-out both; @@ -60,6 +62,7 @@ tg-project-menu { } } svg { + fill: $white; height: 1.5rem; width: 1.5rem; path { diff --git a/app/styles/modules/common/related-tasks.scss b/app/styles/modules/common/related-tasks.scss index 231f0b8c..241cb037 100644 --- a/app/styles/modules/common/related-tasks.scss +++ b/app/styles/modules/common/related-tasks.scss @@ -4,7 +4,7 @@ } .related-tasks-header { - align-content: space-between; + align-content: center; align-items: center; background: $whitish; display: flex; @@ -101,7 +101,8 @@ } } .icon { - color: $gray-light; + @include svg-size(.8rem); + fill: $gray-light; margin-left: .2rem; opacity: 0; } @@ -116,6 +117,7 @@ } .task-name { display: flex; + justify-content: space-between; position: relative; a { display: inline-block; @@ -123,6 +125,10 @@ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; + svg, + span { + margin-right: .25rem; + } } svg, span { @@ -144,26 +150,6 @@ } } } - .blocked, - .blocked:hover { - background: $red-light; - color: $white; - a { - color: $white; - &:hover { - color: $white; - } - } - .icon { - color: $white; - &:hover { - color: $white; - } - } - } - .icon-iocaine { - display: none; - } .iocaine, .iocaine:hover { background: rgba($primary-light, .3); @@ -173,21 +159,48 @@ margin-right: .5rem; vertical-align: top; } + a, + svg { + color: $primary-dark; + fill: $primary-dark; + &:hover { + color: currentColor; + fill: currentColor; + } + } + } + .blocked, + .blocked:hover { + background: $red-light; + color: $white; + a, + svg { + color: $white; + fill: $white; + &:hover { + color: currentColor; + fill: currentColor; + } + } + } + .icon-iocaine { + display: none; } .task-settings { - margin: 0 0 0 2rem; + align-items: center; + display: flex; opacity: 0; - position: absolute; - right: 0; - top: 0; - width: 10%; - a { - @extend %large; - color: $gray-light; - transition: all .2s ease-in; + svg { + @include svg-size(1.1rem); + fill: $gray-light; + margin-right: 2rem; + transition: fill .2s ease-in; &:hover { - color: $grayer; - transition: all .2s ease-in; + cursor: pointer; + fill: $grayer; + } + &.icon-close:hover { + fill: $red-light; } } } @@ -213,6 +226,8 @@ white-space: nowrap; } .icon { + @include svg-size(.8rem); + fill: $gray-light; opacity: 0; position: absolute; right: .5rem; diff --git a/app/styles/modules/common/ticket-data.scss b/app/styles/modules/common/ticket-data.scss index c97d7e36..b5723c38 100644 --- a/app/styles/modules/common/ticket-data.scss +++ b/app/styles/modules/common/ticket-data.scss @@ -11,17 +11,20 @@ } .detail-status { @extend %small; - display: inline-block; + display: flex; margin-left: .25rem; position: relative; - .icon-arrow-bottom { + .icon-arrow-down { + @include svg-size(.75rem); + fill: currentColor; margin-left: .25rem; } } .detail-status-inner { + align-items: center; color: $white; display: flex; - justify-content: center; + justify-content: flex-start; padding: .15rem .25rem; text-transform: uppercase; } @@ -44,6 +47,8 @@ @extend %normal; margin-bottom: 1rem; .icon { + @include svg-size(.7rem); + color: currentColor; margin-left: .25rem; } } @@ -115,7 +120,8 @@ .ticket-watch-inner { display: flex; } - .track-icon { + svg { + margin-right: .25rem; position: relative; top: 2px; } @@ -130,7 +136,7 @@ text-align: center; text-transform: uppercase; transition: background .25s; - path { + svg { fill: $white; } &:hover { diff --git a/app/styles/modules/common/wizard.scss b/app/styles/modules/common/wizard.scss index 75c60ac7..81a1b6c0 100644 --- a/app/styles/modules/common/wizard.scss +++ b/app/styles/modules/common/wizard.scss @@ -1,73 +1,109 @@ .wizard-create-project { @extend %lightbox; - @extend %background-taiga; - background-size: cover; - color: $white; - text-align: center; - form { - width: 500px; - } - .title { - width: 100%; - } - h1, - p { - color: $white; - } - h1 { - line-height: 1.5rem; - } - p { - @extend %small; - opacity: .8; - } - input, - textarea, - select { - background: rgba($white, .7); - @include placeholder { - color: $grayer; - } - } .close { - color: $white; - &:hover { - color: $red-light; + @include svg-size(2rem); + } + form { + width: 700px; + } + header { + margin-bottom: 3rem; + .title { + margin-bottom: 0; + } + .subtitle { + @extend %small; + color: $gray-light; + text-align: center; } } - .wizard-step { - animation: formSlide .4s ease-in-out; - animation-direction: alternate-reverse; - display: none; - &.active { - animation: formSlide .4s ease-in-out; - &.create-step2, - &.create-step3, - &.create-step1 { - display: block; - } - } + .more-info { + @extend %small; + color: $primary; } - .wizard-action { - div { - display: flex; + .template-selector-title { + display: flex; + justify-content: space-between; + margin-bottom: 1rem; + } + .template-selector { + display: flex; + margin-bottom: 1rem; + input { + display: none; } - a { - color: $white; - display: inline-block; - flex-basis: 40%; - flex-grow: 1; + fieldset { &:first-child { margin-right: .5rem; } } } - .create-step1 { - .template-inner { - display: flex; + 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.4rem); + fill: currentColor; + margin-right: 1rem; + vertical-align: text-top; + } + .template-name { + @extend %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 { - flex-grow: 1; + margin-bottom: 0; &:first-child { margin-right: .5rem; } @@ -75,105 +111,37 @@ input { display: none; } - input:checked { - +label { - background: rgba($primary-light, .7); - transition: background .3s ease-in; - } + label { + display: block; + text-align: center; + text-transform: uppercase; + } input+label { - background: rgba($whitish, .7); - cursor: pointer; - display: block; - margin-bottom: 1rem; padding: 1rem; - text-align: center; - transition: background .3s ease-in; - &:hover { - background: rgba($primary, .7); - transition: background .3s ease-in; - } - .icon { - @extend %xxlarge; - color: $white; - } } - h2 { - color: $white; - margin: 0; - margin-top: .5rem; - text-transform: uppercase; - } - p { - text-align: center; + svg { + @include svg-size(.7rem); } } - .progress-bar { - bottom: 0; - height: .5rem; - left: 0; - position: absolute; - width: 100%; - } - .step1 { - .bar { - transition: width .6s ease-in-out; - width: 25%; + .create-warning { + @extend %small; + padding: 1rem; + text-align: center; + .icon-exclamation { + fill: $red-light; + margin-right: .5rem; + vertical-align: middle; } - .progress-state { - span:nth-child(1) { - color: rgba($white, 1); - transition: color .3s ease-in-out; - transition-delay: .6s; - } - } - } - .step2 { - .bar { - transition: width .6s ease-in-out; - // width: 50%; - width: 75%; - } - .progress-state { - span:nth-child(1), - span:nth-child(2) { - color: rgba($white, 1); - transition: color .3s ease-in-out; - transition-delay: .6s; - } - } - } - - .progress-state { - position: absolute; - width: 100%; - span { - color: rgba($white, .5); + a { + color: $primary; display: inline-block; - margin-left: -100px; - position: absolute; - text-align: center; - top: -2rem; - transition: all 1s ease-in; - width: 200px; - &:nth-child(1) { - left: 25%; - } - &:nth-child(2) { - left: 75%; - } + margin-left: .25rem; } } - .progress-bar-wrapper { - background: rgba($white, .3); - height: .5rem; - } - .bar { - background: rgba($primary-light, .9); - height: .5rem; - left: 0; - position: absolute; - top: 0; - width: 0; + .button-green { + display: block; + margin: 1rem 5rem; + width: calc(100% - 10rem); } } diff --git a/app/styles/modules/filters/filters.scss b/app/styles/modules/filters/filters.scss index 527f44cc..e1309796 100644 --- a/app/styles/modules/filters/filters.scss +++ b/app/styles/modules/filters/filters.scss @@ -8,13 +8,17 @@ vertical-align: baseline; } } - h2 { + .breadcrumb { @extend %large; margin-top: 1rem; .icon-arrow-right { - @extend %medium; + @include svg-size(.7rem); + margin: 0 .25rem; vertical-align: middle; } + .back { + color: $gray-light; + } } input { background: $grayer; @@ -79,8 +83,10 @@ } } a { + align-items: center; color: $grayer; - display: block; + display: flex; + justify-content: space-between; padding: .5rem 0 .5rem .5rem; transition: color .2s ease-in; &:hover { @@ -93,9 +99,11 @@ } } .icon { - color: $grayer; + fill: currentColor; float: right; + height: .9rem; opacity: 0; transition: opacity .2s ease-in; + width: .9rem; } } diff --git a/app/styles/modules/home-project.scss b/app/styles/modules/home-project.scss index a58aab65..074c7414 100644 --- a/app/styles/modules/home-project.scss +++ b/app/styles/modules/home-project.scss @@ -30,6 +30,9 @@ margin-bottom: 0; vertical-align: middle; } + .private { + @include svg-size(1.1rem); + } .like-watch-container { margin-left: auto; } @@ -96,6 +99,7 @@ li { flex-basis: 24%; margin-right: .14rem; + position: relative; &:nth-child(4n) { margin-right: 0; } @@ -107,5 +111,13 @@ border-radius: .2rem; width: 100%; } + .icon-badge { + @include svg-size(1.2rem); + background: rgba($black, .5); + bottom: 5%; + padding: .1rem; + position: absolute; + right: 5%; + } } } diff --git a/app/styles/modules/issues/issues-table.scss b/app/styles/modules/issues/issues-table.scss index d9468859..9b03dc47 100644 --- a/app/styles/modules/issues/issues-table.scss +++ b/app/styles/modules/issues/issues-table.scss @@ -73,6 +73,12 @@ &.is-voted { color: $primary-light; } + svg { + @include svg-size(.75rem); + fill: $gray; + margin-right: .25rem; + vertical-align: middle; + } } .subject { overflow: hidden; @@ -99,6 +105,12 @@ padding: 0 1rem; position: relative; text-align: left; + .icon { + @include svg-size(.75rem); + fill: currentColor; + margin-left: .25rem; + vertical-align: middle; + } } .assigned-field { flex: 0 0 160px; @@ -120,10 +132,11 @@ white-space: nowrap; } .icon { + @include svg-size(.75rem); opacity: 0; position: absolute; right: 0; - top: .5rem; + top: .75rem; transition: opacity .3s linear; } } diff --git a/app/styles/modules/kanban/kanban-table.scss b/app/styles/modules/kanban/kanban-table.scss index 817c8a58..5de4736d 100644 --- a/app/styles/modules/kanban/kanban-table.scss +++ b/app/styles/modules/kanban/kanban-table.scss @@ -21,12 +21,7 @@ $column-margin: 0 10px 0 0; opacity: .8; padding: .5rem 0; transition: opacity .3s linear; - .icon-plus, - .icon-bulk, - .icon-vfold, - .icon-vunfold, - .icon-open-eye, - .icon-closed-eye, + .option:not(.hunfold), span { display: none; } @@ -86,51 +81,19 @@ $column-margin: 0 10px 0 0; span { @include ellipsis(65%); } - .icon { - @extend %medium; - color: $gray-light; + .option { margin-right: .3rem; - transition: color .2s linear; - &.hfold, - &.hunfold { - display: inline-block; - transform: rotate(90deg); - } } - } - .icon-open-eye, - .icon-closed-eye { - display: inline-block; - svg { + .icon { fill: $gray-light; - height: 1.1rem; - margin-top: .25rem; - width: 1.1rem; - - } - &:hover { - svg { + height: 1rem; + transition: color .2s linear; + width: 1rem; + &:hover { fill: $primary; - } } } - .icon-open-eye { - .svg-eye-closed { - display: none; - } - .svg-eye-open { - display: block; - } - } - .icon-closed-eye { - .svg-eye-closed { - display: block; - } - .svg-eye-open { - display: none; - } - } } .kanban-table-body { diff --git a/app/styles/modules/search/search-filter.scss b/app/styles/modules/search/search-filter.scss index 742bd0b7..b25c5fc0 100644 --- a/app/styles/modules/search/search-filter.scss +++ b/app/styles/modules/search/search-filter.scss @@ -11,12 +11,12 @@ padding: 1rem 1.25rem; &:hover { transition: color .3s linear; - .icon { - margin-right: .4rem; - } .name { padding-left: 5px; } + .icon { + fill: currentColor; + } } &.active { border-left: 1px solid $whitish; @@ -25,11 +25,12 @@ position: relative; top: 1px; .icon { - color: $primary-light; + fill: $primary-light; } } } .icon { + fill: currentColor; margin-right: .4rem; } .name { diff --git a/app/styles/modules/search/search-in.scss b/app/styles/modules/search/search-in.scss index 19eecf56..8b30b855 100644 --- a/app/styles/modules/search/search-in.scss +++ b/app/styles/modules/search/search-in.scss @@ -12,7 +12,7 @@ top: .7rem; } .icon-search { - color: $gray-light; + fill: $gray-light; } .loading-spinner { margin-top: .1rem; diff --git a/app/styles/modules/team/team-filters.scss b/app/styles/modules/team/team-filters.scss index e638fe0d..e32092b1 100644 --- a/app/styles/modules/team/team-filters.scss +++ b/app/styles/modules/team/team-filters.scss @@ -3,37 +3,38 @@ margin-bottom: 1rem; position: relative; } - nav { - li { - @extend %larger; - @extend %title; - border-bottom: 1px solid $gray-light; - text-transform: uppercase; - &:last-child { - border-bottom: 0; - } - } - a { - display: block; - padding: 1rem 0 1rem 1rem; - &:hover, - &.active { - color: $primary; - transition: color .3s linear; - } - &.active.icon { - opacity: 1; - transition: opacity .3s linear; - } - } - .active { - opacity: 1; - transition: opacity .3s linear; + li { + @extend %large; + @extend %text; + border-bottom: 1px solid $gray-light; + text-transform: uppercase; + &:last-child { + border-bottom: 0; } .icon { - color: $blackish; - float: right; + fill: $blackish; opacity: 0; + transition: opacity .3s linear; } } + a { + align-content: center; + align-items: center; + display: flex; + justify-content: space-between; + padding: 1rem 0 1rem 1rem; + &:hover, + &.active { + color: $primary; + transition: color .3s linear; + .icon { + fill: currentColor; + opacity: 1; + } + } + } + .active { + opacity: 1; + transition: opacity .3s linear; + } } diff --git a/app/styles/modules/team/team-table.scss b/app/styles/modules/team/team-table.scss index a75332d4..c7927a87 100644 --- a/app/styles/modules/team/team-table.scss +++ b/app/styles/modules/team/team-table.scss @@ -19,8 +19,8 @@ position: relative; text-align: center; .icon { - color: $blackish; - font-size: 1.8rem; + @include svg-size(1.75rem); + fill: $gray; } .points { @extend %larger; @@ -28,7 +28,7 @@ color: $grayer; } .top { - color: $primary-light; + fill: $primary-light; opacity: 1; } &:hover { @@ -39,15 +39,17 @@ } .leave-project { @extend %small; - color: $gray-light; - display: block; + color: $red-light; .icon { + @include svg-size(.8rem); + fill: currentColor; margin-right: .2rem; } &:hover { + color: $red; .icon { - color: $red; - transition: color .3s linear; + color: currentColor; + transition: fill .3s linear; } } } @@ -59,9 +61,10 @@ .hero { width: 100%; .row { - background: $whitish; - border-bottom: 0; + border-bottom: 1px solid $whitish; + border-top: 1px solid $whitish; margin: 1rem 0; + padding: 1.5rem 1rem; } } .avatar { @@ -69,12 +72,12 @@ display: flex; img { flex-basis: 66px; - flex-grow: 1; - max-width: 66px; + flex-grow: 0; + flex-shrink: 0; + width: 66px; } - figcaption { + .avatar-data { margin-left: 1rem; - width: 65%; span { overflow: hidden; text-overflow: ellipsis; @@ -98,4 +101,8 @@ .popover { @include popover(100%, '', 0, 30px, '', 15px, '', 50%, -5px); } + .icon-badge { + position: relative; + top: .15rem; + } } diff --git a/app/styles/modules/wiki/wiki-nav.scss b/app/styles/modules/wiki/wiki-nav.scss index 39c20db9..f1f72c76 100644 --- a/app/styles/modules/wiki/wiki-nav.scss +++ b/app/styles/modules/wiki/wiki-nav.scss @@ -7,21 +7,26 @@ &:hover { .icon { opacity: 1; - transition: opacity 1s linear; + transition: opacity .2s linear; + transition-delay: .2s; } } a { - display: block; + align-items: center; + display: flex; + justify-content: space-between; padding: 1rem 0 1rem 1rem; span { cursor: pointer; } } .icon { - color: $blackish; - float: right; + fill: $gray-light; opacity: 0; - transition: opacity 1s linear; + &:hover { + cursor: pointer; + fill: $red; + } } input { @extend %text; diff --git a/app/svg/activity.svg b/app/svg/activity.svg deleted file mode 100644 index 66e8684f..00000000 --- a/app/svg/activity.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/app/svg/add.svg b/app/svg/add.svg deleted file mode 100644 index 77a2901a..00000000 --- a/app/svg/add.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/svg/attachment.svg b/app/svg/attachment.svg deleted file mode 100644 index 784be839..00000000 --- a/app/svg/attachment.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/svg/check.svg b/app/svg/check.svg deleted file mode 100644 index d97a17c3..00000000 --- a/app/svg/check.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/app/svg/client-requirement.svg b/app/svg/client-requirement.svg deleted file mode 100644 index fd20989a..00000000 --- a/app/svg/client-requirement.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - diff --git a/app/svg/dashboard.svg b/app/svg/dashboard.svg deleted file mode 100644 index 1b2061a2..00000000 --- a/app/svg/dashboard.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/app/svg/discover.svg b/app/svg/discover.svg deleted file mode 100644 index 5334c1bb..00000000 --- a/app/svg/discover.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/svg/empty-project.svg b/app/svg/empty-project.svg deleted file mode 100644 index fdc92148..00000000 --- a/app/svg/empty-project.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/app/svg/eye.svg b/app/svg/eye.svg deleted file mode 100644 index 98489d10..00000000 --- a/app/svg/eye.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - diff --git a/app/svg/flag.svg b/app/svg/flag.svg deleted file mode 100644 index 2612a5cf..00000000 --- a/app/svg/flag.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/svg/gallery.svg b/app/svg/gallery.svg deleted file mode 100644 index d9f205bc..00000000 --- a/app/svg/gallery.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/svg/graph.svg b/app/svg/graph.svg deleted file mode 100644 index b4a28d94..00000000 --- a/app/svg/graph.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/svg/help.svg b/app/svg/help.svg deleted file mode 100644 index b822b8fd..00000000 --- a/app/svg/help.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/svg/hide.svg b/app/svg/hide.svg deleted file mode 100644 index 0abadf8e..00000000 --- a/app/svg/hide.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/svg/icons/block-user.svg b/app/svg/icons/block-user.svg new file mode 100644 index 00000000..3c43c532 --- /dev/null +++ b/app/svg/icons/block-user.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/app/svg/icons/multi-block-project.svg b/app/svg/icons/multi-block-project.svg new file mode 100644 index 00000000..bc13957a --- /dev/null +++ b/app/svg/icons/multi-block-project.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/svg/icons/project-limit.svg b/app/svg/icons/project-limit.svg new file mode 100644 index 00000000..7c25bdff --- /dev/null +++ b/app/svg/icons/project-limit.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/svg/icons/team-question.svg b/app/svg/icons/team-question.svg new file mode 100644 index 00000000..e8678f64 --- /dev/null +++ b/app/svg/icons/team-question.svg @@ -0,0 +1,4 @@ + + + diff --git a/app/svg/iocaine.svg b/app/svg/iocaine.svg deleted file mode 100644 index 868c76d0..00000000 --- a/app/svg/iocaine.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - diff --git a/app/svg/like.svg b/app/svg/like.svg deleted file mode 100644 index dd7c202d..00000000 --- a/app/svg/like.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/svg/list.svg b/app/svg/list.svg deleted file mode 100644 index f2ef5c24..00000000 --- a/app/svg/list.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/svg/location.svg b/app/svg/location.svg deleted file mode 100644 index 2e4b6957..00000000 --- a/app/svg/location.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - Location - - - diff --git a/app/svg/lock.svg b/app/svg/lock.svg deleted file mode 100644 index d39b2ba0..00000000 --- a/app/svg/lock.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/svg/organizations.svg b/app/svg/organizations.svg deleted file mode 100644 index 4dca4867..00000000 --- a/app/svg/organizations.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/app/svg/project.svg b/app/svg/project.svg deleted file mode 100644 index 6e3ce332..00000000 --- a/app/svg/project.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/svg/projects.svg b/app/svg/projects.svg deleted file mode 100644 index e8c66014..00000000 --- a/app/svg/projects.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/app/svg/promote.svg b/app/svg/promote.svg deleted file mode 100644 index 329e718f..00000000 --- a/app/svg/promote.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/svg/recruit.svg b/app/svg/recruit.svg deleted file mode 100644 index fa8dcf32..00000000 --- a/app/svg/recruit.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - diff --git a/app/svg/remove.svg b/app/svg/remove.svg deleted file mode 100644 index 6097c7df..00000000 --- a/app/svg/remove.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/svg/search.svg b/app/svg/search.svg deleted file mode 100644 index 8c58b6ec..00000000 --- a/app/svg/search.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/app/svg/sprite.svg b/app/svg/sprite.svg new file mode 100644 index 00000000..0a5d3ec6 --- /dev/null +++ b/app/svg/sprite.svg @@ -0,0 +1,433 @@ + + + + iocaine + + + + lock + + + + promote + + + + trash + + + + unlock + + + + client-requirement + + + + project + + + + team-requirement + + + + add + + + + scrum + + + + bulk + + + + close + + + + dashboard + + + + discover + + + + drag + + + + exclamation + + + + flag + + + + fold-column + + + + fold-row + + + + graph + + + + issues + + + + kanban + + + + like-empty + + + + like + + + + activity + + + + question + + + + search + + + + settings + + + + team + + + + timeline + + + + unfold-column + + + + unfold-row + + + + unwatch + + + + user + + + + wiki + + + + archive + + + + arrow-down + + + + arrow-left + + + + arrow-right + + + + arrow-up + + + + attachment + + + + briefcase + + + + bubble-empty + + + + bubble + + + + bug + + + + capslock + + + + check + + + + clipboard + + + + document + + + + documents + + + + downvote + + + + edit + + + + error + + + + filters-empty + + + + filters + + + + github + + + + maximize + + + + minimize + + + + move + + + + reload + + + + save + + + + upload + + + + upvote + + + + writer + + + + watch + + + + check-empty + + + + task + + + + api + + + + customize + + + + feel-love + + + + highly-designed + + + + integration + + + + lend-hand + + + + powerful + + + + smiley + + + + social-management + + + + speak-up + + + + gallery + + + + list + + + + Looking for people + + + + Owner Badge + + + + Exclamation + + + + Blocked Project + + + + + diff --git a/app/svg/team-requirement.svg b/app/svg/team-requirement.svg deleted file mode 100644 index 154ea48c..00000000 --- a/app/svg/team-requirement.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - diff --git a/app/svg/team.svg b/app/svg/team.svg deleted file mode 100644 index fc0fc652..00000000 --- a/app/svg/team.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - diff --git a/app/svg/timeline.svg b/app/svg/timeline.svg deleted file mode 100644 index 56c0347a..00000000 --- a/app/svg/timeline.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/svg/trash.svg b/app/svg/trash.svg deleted file mode 100644 index 281f1d29..00000000 --- a/app/svg/trash.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/svg/unlock.svg b/app/svg/unlock.svg deleted file mode 100644 index fe3188a5..00000000 --- a/app/svg/unlock.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/svg/unwatch.svg b/app/svg/unwatch.svg deleted file mode 100644 index 9a305958..00000000 --- a/app/svg/unwatch.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/svg/upvote.svg b/app/svg/upvote.svg deleted file mode 100644 index 187d6159..00000000 --- a/app/svg/upvote.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - diff --git a/app/svg/watch.svg b/app/svg/watch.svg deleted file mode 100644 index cfce30c5..00000000 --- a/app/svg/watch.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/themes/high-contrast/custom.scss b/app/themes/high-contrast/custom.scss index 0ad07c93..d4527fc9 100644 --- a/app/themes/high-contrast/custom.scss +++ b/app/themes/high-contrast/custom.scss @@ -78,6 +78,7 @@ a { input[type="text"], input[type="number"], input[type="password"], +input[type="url"], input[type="email"], input[type="date"], input[type="password"], @@ -157,12 +158,12 @@ tg-project-menu { } .main-nav { - svg path { + svg { fill: $white; } .active { background: $white; - svg path { + svg { fill: $black; } } @@ -179,7 +180,7 @@ tg-project-menu { background: lighten($white, 20%); border-top: 3px solid $black; .icon { - color: $black; + fill: $black; } } } @@ -197,7 +198,7 @@ tg-project-menu { //Kanban table .kanban-table-header { .task-colum-name { - background: lighten($white, 20%); + background: lighten($whitish, 50%); border-top: 3px solid $black; .icon { color: $black; @@ -207,7 +208,7 @@ tg-project-menu { .kanban-table-body { .kanban-uses-box { - background: $whitish; + background: lighten($whitish, 50%); } } diff --git a/app/themes/material-design/custom.scss b/app/themes/material-design/custom.scss index e37abb23..987d7cd1 100644 --- a/app/themes/material-design/custom.scss +++ b/app/themes/material-design/custom.scss @@ -73,6 +73,7 @@ a { input[type="text"], input[type="number"], input[type="password"], +input[type="url"], input[type="email"], input[type="date"], input[type="password"], @@ -154,7 +155,7 @@ tg-project-menu { background: lighten($primary-light, 20%); border-top: 3px solid $primary; .icon { - color: $primary; + fill: $primary; } } } @@ -171,7 +172,7 @@ tg-project-menu { //Kanban table .kanban-table-header { .task-colum-name { - background: lighten($primary-light, 20%); + background: lighten($whitish, 5%); border-top: 3px solid $primary; .icon { color: $primary; @@ -181,6 +182,6 @@ tg-project-menu { .kanban-table-body { .kanban-uses-box { - background: $whitish; + background: lighten($whitish, 5%); } } diff --git a/app/themes/taiga/custom.scss b/app/themes/taiga/custom.scss index 08adf274..3c6a40dd 100644 --- a/app/themes/taiga/custom.scss +++ b/app/themes/taiga/custom.scss @@ -55,16 +55,17 @@ a { input[type="text"], input[type="number"], input[type="password"], +input[type="url"], input[type="email"], input[type="date"], input[type="password"], select, textarea { - background: $whitish; + background: lighten($whitish, 6%); border-color: $gray-light; color: $grayer; @include placeholder { - color: darken($gray-light, 10%); + color: lighten($gray-light, 10%); } &.checksley-error { border: 1px solid $red; @@ -131,16 +132,16 @@ tg-project-menu { //Taskboard table .taskboard-table-header { .task-colum-name { - background: $whitish; + background: lighten($whitish, 5%); border-top: 3px solid $gray-light; .icon { - color: $gray-light; + fill: $gray-light; } } } .taskboard-table-body { .taskboard-tasks-box { - background: $whitish; + background: lighten($whitish, 5%); } } @@ -151,7 +152,7 @@ tg-project-menu { //Kanban table .kanban-table-header { .task-colum-name { - background: $whitish; + background: lighten($whitish, 5%); border-top: 3px solid $gray-light; .icon { color: $gray-light; @@ -161,6 +162,6 @@ tg-project-menu { .kanban-table-body { .kanban-uses-box { - background: $whitish; + background: lighten($whitish, 5%); } } diff --git a/app/themes/taiga/variables.scss b/app/themes/taiga/variables.scss index 4de07219..963d7dcb 100755 --- a/app/themes/taiga/variables.scss +++ b/app/themes/taiga/variables.scss @@ -7,13 +7,13 @@ $black: #000; $blackish: #050505; $grayer: #444; $gray: #555; -$gray-light: #b8b8b8; -$whitish: #f5f5f5; +$gray-light: #767676; +$whitish: #e4e3e3; $white: #fff; // Primary colors $primary-light: #9dce0a; -$primary: #72a114; +$primary: #5b8200; $primary-dark: #879b89; //Warning colors diff --git a/bower.json b/bower.json index 3fdfcc74..400a03c8 100644 --- a/bower.json +++ b/bower.json @@ -47,7 +47,6 @@ "tests" ], "dependencies": { - "lodash": "~2.4.2", "emoticons": "~0.1.7", "jquery-flot": "~0.8.2", "angular": "1.4.7", @@ -82,10 +81,11 @@ "eventemitter2": "~0.4.14", "immutable": "~3.7.6", "bluebird": "~2.10.2", - "intro.js": "~1.1.1" + "intro.js": "~1.1.1", + "lodash": "~4.0.0" }, "resolutions": { - "lodash": "~2.4.2", + "lodash": "~4.0.0", "moment": "~2.10.6", "jquery": "~2.1.1", "angular": "1.4.7" diff --git a/conf.e2e.js b/conf.e2e.js index bca55590..b6b82dee 100644 --- a/conf.e2e.js +++ b/conf.e2e.js @@ -1,6 +1,5 @@ -require("babel/register")({ - stage: 1 -}); +require("babel-register"); +require("babel-polyfill"); var utils = require('./e2e/utils'); @@ -20,9 +19,13 @@ exports.config = { }, mochaOpts: { timeout: 45000, - compilers: 'js:babel/register' + compilers: 'js:babel-register', + require: 'babel-polyfill' }, // capabilities: { + // 'browserName': 'firefox' + // }, + // capabilities: { // browserName: 'internet explorer', // version: '11' // }, @@ -99,10 +102,6 @@ exports.config = { browser.driver.manage().window().maximize(); - browser.getCapabilities().then(function (cap) { - browser.browserName = cap.caps_.browserName; - }); - browser.get(browser.params.glob.host + 'login'); var username = $('input[name="username"]'); @@ -125,11 +124,6 @@ exports.config = { .then(function() { return utils.common.closeJoyride(); }) - .then(function() { - return browser.getCapabilities(); - }).then(function (cap) { - browser.browserName = cap.caps_.browserName; - }) .then(function() { return browser.get(browser.params.glob.host); }); diff --git a/e2e/capabilities.js b/e2e/capabilities.js index f754e79f..5ae4ea92 100644 --- a/e2e/capabilities.js +++ b/e2e/capabilities.js @@ -8,10 +8,20 @@ module.exports = browser.getCapabilities().then(function(s) { var shortName, shortVersion; var ie, ff, ch, sa; var platform; - platform = s.caps_.platform; - browserName = s.caps_.browserName; - browserVersion = s.caps_.version; + + var capabilities = {}; + + for(let item of s) { + capabilities[item[0]] = item[1]; + } + + platform = capabilities.platform; + browserName = capabilities.browserName; + browserVersion = capabilities.version; shortVersion = browserVersion.split('.')[0]; + + browser.browserName = browserName; + ie = /i.*explore/.test(browserName); ff = /firefox/.test(browserName); ch = /chrome/.test(browserName); @@ -86,7 +96,7 @@ module.exports = browser.getCapabilities().then(function(s) { }; // Save current webdriver session id for later use - browser.webdriverRemoteSessionId = s.caps_['webdriver.remote.sessionid']; + browser.webdriverRemoteSessionId = capabilities['webdriver.remote.sessionid']; browser.inSauceLabs = function() { return !!(browser.params.inSauceLabs); diff --git a/e2e/helpers/admin-attributes-helper.js b/e2e/helpers/admin-attributes-helper.js index ad02791b..00ade8b7 100644 --- a/e2e/helpers/admin-attributes-helper.js +++ b/e2e/helpers/admin-attributes-helper.js @@ -16,7 +16,7 @@ helper.getSection = function(item) { return section.$$('.ui-sortable > div'); }, delete: function(row) { - let deleteButton = row.$$('.icon-delete').first(); + let deleteButton = row.$$('.icon-trash').first(); return browser.actions() .mouseMove(deleteButton) @@ -41,7 +41,7 @@ helper.getStatusNames = function(section) { helper.getForm = function(form) { return { save: function() { - let saveButton = form.$('.icon-floppy'); + let saveButton = form.$('.icon-save'); browser.actions() .mouseMove(saveButton) diff --git a/e2e/helpers/admin-memberships.js b/e2e/helpers/admin-memberships.js index 5fbe7c34..bcef88a6 100644 --- a/e2e/helpers/admin-memberships.js +++ b/e2e/helpers/admin-memberships.js @@ -7,7 +7,7 @@ helper.openNewMemberLightbox = function() { }; helper.getNewMemberLightbox = function() { - let el = $('div[tg-lb-create-members]'); + let el = $('div[tg-lb-add-members]'); let obj = { el: el, @@ -35,10 +35,30 @@ helper.getNewMemberLightbox = function() { return obj; }; +helper.leavingProjectWarningLb = function() { + return $('div[tg-lightbox-leave-project-warning]'); +}; + +helper.isLeaveProjectWarningOpen = function() { + return helper.leavingProjectWarningLb().isPresent(); +}; + helper.getMembers = function() { return $$('.admin-membership-table .row'); }; +helper.getOwner = function() { + return helper.getMembers().filter(async (member) => { + return !!await member.$$('.icon-badge').count(); + }).first(); +}; + +helper.excludeOwner = function(members) { + return members.filter(async (member) => { + return !await member.$$('.icon-badge').count(); + }); +}; + helper.isActive = function(elm) { return utils.common.hasClass(elm, 'active'); }; diff --git a/e2e/helpers/admin-permissions.js b/e2e/helpers/admin-permissions.js index 7a4c28d8..c21ecc13 100644 --- a/e2e/helpers/admin-permissions.js +++ b/e2e/helpers/admin-permissions.js @@ -16,8 +16,8 @@ helper.getRoles = function() { }; helper.editRole = async function(roleName) { - let elm = $('div[tg-edit-role]'); - let editButton = elm.$('.icon-edit'); + let elm = $('tg-edit-role'); + let editButton = elm.$('.edit-value'); await browser.actions() .mouseMove(editButton) diff --git a/e2e/helpers/backlog-helper.js b/e2e/helpers/backlog-helper.js index b6021bc2..37b06495 100644 --- a/e2e/helpers/backlog-helper.js +++ b/e2e/helpers/backlog-helper.js @@ -87,7 +87,7 @@ helper.getCreateEditMilestone = function() { el.$('button[type="submit"]').click(); }, delete: function() { - el.$('.delete-sprint .icon-delete').click(); + el.$('.delete-sprint').click(); } }; @@ -197,3 +197,9 @@ helper.getSprintsTitles = function() { helper.goBackFilters = function() { return $$('.filters-step-cat .breadcrumb a').first().click(); }; + +helper.fiterRole = async function(value) { + let rolePointsSelector = $('div[tg-us-role-points-selector]'); + + return utils.popover.open(rolePointsSelector, value); +}; diff --git a/e2e/helpers/common-helper.js b/e2e/helpers/common-helper.js index df99bd9f..37f95d9d 100644 --- a/e2e/helpers/common-helper.js +++ b/e2e/helpers/common-helper.js @@ -19,7 +19,7 @@ helper.assignToLightbox = function() { return utils.lightbox.close(el); }, close: function() { - el.$$('.icon-delete').first().click(); + el.$$('.icon-close').first().click(); }, selectFirst: function() { el.$$('div[data-user-id]').first().click(); diff --git a/e2e/helpers/create-project-helper.js b/e2e/helpers/create-project-helper.js index c87f5fac..8323b73d 100644 --- a/e2e/helpers/create-project-helper.js +++ b/e2e/helpers/create-project-helper.js @@ -23,13 +23,13 @@ helper.createProjectLightbox = function() { await browser.sleep(1000); }, submit: function() { - return $('.wizard-step.active .button-green').click(); + return $('div[tg-lb-create-project] .button-green').click(); }, name: function() { - return $$('.create-step2 input').get(0); + return $$('div[tg-lb-create-project] input[type="text"]').get(0); }, description: function() { - return $$('.create-step2 textarea'); + return $('div[tg-lb-create-project] textarea'); }, errors: function() { return $$('.checksley-error-list li'); diff --git a/e2e/helpers/custom-fields-helper.js b/e2e/helpers/custom-fields-helper.js index 5420a98e..84a6d5ef 100644 --- a/e2e/helpers/custom-fields-helper.js +++ b/e2e/helpers/custom-fields-helper.js @@ -2,20 +2,19 @@ var utils = require('../utils'); var helper = module.exports; -helper.create = function(indexType, name, desc, option) { +helper.create = async function(indexType, name, desc, option) { let type = $$('div[tg-project-custom-attributes]').get(indexType); type.$('.js-add-custom-field-button').click(); - let form = type.$$('form').last(); - form.$('input[name="name"]').sendKeys(name); - form.$('input[name="description"]').sendKeys(desc); + await form.$('input[name="name"]').sendKeys(name); + await form.$('input[name="description"]').sendKeys(desc); form.$(`select option:nth-child(${option})`).click(); let saveButton = form.$('.js-create-custom-field-button'); - browser.actions() + return browser.actions() .mouseMove(saveButton) .click() .perform(); diff --git a/e2e/helpers/detail-helper.js b/e2e/helpers/detail-helper.js index 81c16bf1..0bd06a59 100644 --- a/e2e/helpers/detail-helper.js +++ b/e2e/helpers/detail-helper.js @@ -294,7 +294,8 @@ helper.attachment = function() { return !!count; }, 5000); - await el.$$('tg-attachment .editable-attachment-comment input').last().sendKeys(name); + + await el.$('tg-attachment .editable-attachment-comment input').sendKeys(name); await browser.actions().sendKeys(protractor.Key.ENTER).perform(); await browser.executeScript(toggleInput); await browser.waitForAngular(); @@ -303,7 +304,17 @@ helper.attachment = function() { renameLastAttchment: async function (name) { await browser.actions().mouseMove(el.$$('tg-attachment').last()).perform(); - await el.$$('tg-attachment .attachment-settings .icon-edit').last().click(); + + let settingsGroup = el.$$('tg-attachment .attachment-settings').last(); + + await settingsGroup.$$('.settings').first().click(); + + await browser.wait(async () => { + let count = await $$('tg-attachment .editable-attachment-comment input').count(); + + return !!count; + }, 5000); + await el.$$('tg-attachment .editable-attachment-comment input').last().sendKeys(name); await browser.actions().sendKeys(protractor.Key.ENTER).perform(); await browser.waitForAngular(); @@ -341,7 +352,7 @@ helper.attachment = function() { await browser.actions().mouseMove(el.$$('tg-attachment').last()).perform(); await el.$$('tg-attachment .attachment-settings .icon-edit').last().click(); await el.$$('tg-attachment .editable-attachment-deprecated input').last().click(); - await el.$$('tg-attachment .attachment-settings .editable-settings.icon-floppy').last().click(); + await el.$$('tg-attachment .attachment-settings').last().$$('.editable-settings').first().click(); await browser.waitForAngular(); }, @@ -358,7 +369,7 @@ helper.attachment = function() { // close edit if(isEditable) { - let iconDelete = await attachment.$('.attachment-settings .icon-delete'); + let iconDelete = await attachment.$$('.attachment-settings a').get(1); await browser.actions().mouseMove(iconDelete).perform(); iconDelete.click(); @@ -366,7 +377,7 @@ helper.attachment = function() { await browser.waitForAngular(); } - let iconDelete = await attachment.$('.attachment-settings .icon-delete'); + let iconDelete = await attachment.$$('.attachment-settings a').get(1); await browser.actions().mouseMove(iconDelete).perform(); iconDelete.click(); @@ -377,8 +388,8 @@ helper.attachment = function() { dragLastAttchmentToFirstPosition: async function() { await browser.actions().mouseMove(el.$$('tg-attachment').last()).perform(); - let lastDraggableAttachment = el.$$('tg-attachment .attachment-settings .icon-drag-v').last(); - let destination = el.$$('tg-attachment .attachment-settings .icon-drag-v').first(); + let lastDraggableAttachment = el.$$('tg-attachment .attachment-settings a').last(); + let destination = el.$$('tg-attachment .attachment-settings').first(); await utils.common.drag(lastDraggableAttachment, destination); }, @@ -415,11 +426,13 @@ helper.watchers = function() { }, removeAllWatchers: async function() { - let totalWatchers = await await el.$$('.icon-delete').count(); + let totalWatchers = await await el.$$('.js-delete-watcher').count(); + + if(!totalWatchers) return; let htmlChanges = htmlChanges = await utils.common.outerHtmlChanges(el); while (totalWatchers > 0) { - await el.$$('.icon-delete').first().click(); + await el.$$('.js-delete-watcher').first().click(); await utils.lightbox.confirm.ok(); totalWatchers --; } @@ -442,7 +455,7 @@ helper.watchersLightbox = function() { return utils.lightbox.close(el); }, close: function() { - el.$$('.icon-delete').first().click(); + el.$$('.icon-close').first().click(); }, selectFirst: async function() { el.$$('div[data-user-id]').first().click(); diff --git a/e2e/helpers/issues-helper.js b/e2e/helpers/issues-helper.js index dad32765..ec081fc6 100644 --- a/e2e/helpers/issues-helper.js +++ b/e2e/helpers/issues-helper.js @@ -120,12 +120,12 @@ helper.backToFilters = function() { }; helper.removeFilters = async function() { - let count = await $$('.filters-applied .icon-delete').count(); + let count = await $$('.filters-applied .single-filter.selected').count(); while(count) { - $$('.filters-applied .icon-delete').get(0).click(); + $$('.single-filter.selected').get(0).click(); - count = await $$('.filters-applied .icon-delete').count(); + count = await $$('.single-filter.selected').count(); } }; @@ -134,13 +134,13 @@ helper.getCustomFilters = function() { }; helper.removeCustomFilters = async function() { - let count = await $$('.filter-list .icon-delete').count(); + let count = await $$('.filter-list .remove-filter').count(); while(count) { - $$('.filter-list .icon-delete').get(0).click(); + $$('.filter-list .remove-filter').get(0).click(); await utils.lightbox.confirm.ok(); - count = await $$('.filter-list .icon-delete').count(); + count = await $$('.filter-list .remove-filter').count(); } }; diff --git a/e2e/helpers/kanban-helper.js b/e2e/helpers/kanban-helper.js index 424415d9..3e0e343c 100644 --- a/e2e/helpers/kanban-helper.js +++ b/e2e/helpers/kanban-helper.js @@ -7,7 +7,7 @@ helper.getHeaderColumns = function() { }; helper.openNewUsLb = function(column) { - helper.getHeaderColumns().get(column).$('.icon-plus').click(); + helper.getHeaderColumns().get(column).$$('.option').get(4).click(); }; helper.getColumns = function() { diff --git a/e2e/helpers/project-detail-helper.js b/e2e/helpers/project-detail-helper.js index 096dab63..efc676f5 100644 --- a/e2e/helpers/project-detail-helper.js +++ b/e2e/helpers/project-detail-helper.js @@ -25,3 +25,52 @@ helper.editLogo = function() { helper.getLogoSrc = function() { return $('.image-container .image'); }; + +helper.requestOwnershipLb = function() { + return $('div[tg-lb-request-ownership]'); +}; + +helper.requestOwnership = function() { + $('tg-admin-project-request-ownership .request').click(); +}; + +helper.changeOwner = function() { + $('tg-admin-project-change-owner .request').click(); +}; + +helper.acceptRequestOwnership = function() { + helper.requestOwnershipLb().$('.button-green').click(); +}; + +helper.changeOwnerSuccessLb = function() { + return $('.lightbox-generic-success'); +}; + +helper.getChangeOwnerLb = function() { + let el = $('div[tg-lb-change-owner]'); + + let obj = { + el: el, + waitOpen: function() { + return utils.lightbox.open(el); + }, + waitClose: function() { + return utils.lightbox.close(el); + }, + search: function(q) { + el.$$('input').get(0).sendKeys(q); + }, + select: function(index) { + el.$$('.user-list-single').get(index).click(); + }, + addComment: function(text) { + el.$('.add-comment a').click(); + el.$('textarea').sendKeys(text); + }, + send: function() { + el.$('.submit-button').click(); + } + }; + + return obj; +}; diff --git a/e2e/helpers/taskboard-helper.js b/e2e/helpers/taskboard-helper.js index 6ca5c2b8..44e9971e 100644 --- a/e2e/helpers/taskboard-helper.js +++ b/e2e/helpers/taskboard-helper.js @@ -19,7 +19,7 @@ helper.getBoxTasks = function(row, column) { helper.openNewTaskLb = function(row) { let us = helper.usertories().get(row); - us.$('.icon-plus').click(); + us.$('.icon-add').click(); }; helper.openBulkTaskLb = function(row) { @@ -29,25 +29,25 @@ helper.openBulkTaskLb = function(row) { }; helper.foldRow = function(row) { - let icon = $$('.icon-vfold.vfold').get(row); + let icon = $$('.icon-fold-row.vfold').get(row); icon.click(); }; helper.unFoldRow = function(row) { - let icon = $$('.icon-vunfold.vunfold').get(row); + let icon = $$('.icon-unfold-row.vunfold').get(row); icon.click(); }; helper.foldColumn = function(row) { - let icon = $$('.icon-vfold.hfold').get(row); + let icon = $$('.icon-fold-row.hfold').get(row); icon.click(); }; helper.unFoldColumn = function(row) { - let icon = $$('.icon-vunfold.hunfold').get(row); + let icon = $$('.icon-fold-row.hunfold').get(row); icon.click(); }; @@ -57,7 +57,7 @@ helper.editTask = function(row, column, task) { }; helper.toggleGraph = function() { - $('.large-summary svg').click(); + $('.icon-graph').click(); }; helper.getCreateTask = function() { diff --git a/e2e/helpers/team-helper.js b/e2e/helpers/team-helper.js index 3517cf7e..d5aa011c 100644 --- a/e2e/helpers/team-helper.js +++ b/e2e/helpers/team-helper.js @@ -53,3 +53,11 @@ helper.filters = function() { return obj; }; + +helper.leavingProjectWarningLb = function() { + return $('div[tg-lightbox-leave-project-warning]'); +}; + +helper.isLeaveProjectWarningOpen = function() { + return helper.leavingProjectWarningLb().isPresent(); +}; diff --git a/e2e/helpers/us-detail-helper.js b/e2e/helpers/us-detail-helper.js index ebc1ff80..563530ae 100644 --- a/e2e/helpers/us-detail-helper.js +++ b/e2e/helpers/us-detail-helper.js @@ -44,7 +44,7 @@ helper.clientRequirement = function() { }; helper.relatedTaskForm = async function(form, name, status, assigned_to) { - form.$('input').sendKeys(name); + await form.$('input').sendKeys(name); let taskStatus = form.$('.task-status'); @@ -58,7 +58,12 @@ helper.relatedTaskForm = async function(form, name, status, assigned_to) { await assignToLightbox.selectFirst(); await assignToLightbox.waitClose(); - form.$('.icon-floppy').click(); + let saveBtn = form.$('.icon-save'); + + await browser.actions() + .mouseMove(saveBtn) + .click() + .perform(); }; helper.createRelatedTasks = function(name, status, assigned_to) { @@ -86,7 +91,7 @@ helper.deleteRelatedTask = function(taskIndex, name, status, assigned_to) { browser .actions() - .mouseMove(task.$('.icon-delete')) + .mouseMove(task.$('.icon-trash')) .click() .perform(); @@ -94,5 +99,5 @@ helper.deleteRelatedTask = function(taskIndex, name, status, assigned_to) { }; helper.relatedTasks = function() { - return $$('.related-tasks-body .single-related-task'); + return $$('.js-related-task'); }; diff --git a/e2e/helpers/wiki-helper.js b/e2e/helpers/wiki-helper.js index 829ddb23..dcbabea9 100644 --- a/e2e/helpers/wiki-helper.js +++ b/e2e/helpers/wiki-helper.js @@ -22,7 +22,7 @@ helper.links = function() { }, deleteLink: async function(link){ - link.$(".icon-delete").click(); + link.$(".icon-trash").click(); await utils.lightbox.confirm.ok(); await browser.waitForAngular(); } diff --git a/e2e/shared/detail.js b/e2e/shared/detail.js index 5f6dc991..40bac601 100644 --- a/e2e/shared/detail.js +++ b/e2e/shared/detail.js @@ -65,6 +65,7 @@ shared.statusTesting = async function(status1 , status2) { await statusHelper.setStatus(1); let selectedStatus = await statusHelper.getSelectedStatus(); + expect(selectedStatus).to.be.equal(status1); // Status 2 @@ -104,7 +105,9 @@ shared.assignedToTesting = function() { await assignedTo.clear(); - expect(assignedTo.isUnassigned()).to.be.eventually.true; + let isUnsassigned = assignedTo.isUnassigned(); + + expect(isUnsassigned).to.be.equal.true; }); it('filter', async function () { @@ -117,19 +120,18 @@ shared.assignedToTesting = function() { let names = await assignToLightbox.getNames(); - await assignToLightbox.filter(names[0]); + await assignToLightbox.filter(names[1]); let newNames = await assignToLightbox.getNames(); - expect(newNames).to.have.length(1); + expect(newNames).to.have.length.below(3); assignToLightbox.selectFirst(); await assignToLightbox.waitClose(); - await notifications.success.close(); }); - it('keyboard navigatin', async function() { + it('keyboard navigation', async function() { let assignedTo = detailHelper.assignedTo(); let assignToLightbox = commonHelper.assignToLightbox(); @@ -332,7 +334,6 @@ shared.watchersTesting = function() { await watchersLightboxHelper.selectFirst(); await watchersLightboxHelper.waitClose(); - await notifications.success.close(); }); it('keyboard navigatin', async function() { @@ -366,7 +367,9 @@ shared.customFields = function(typeIndex) { before(async function() { let url = await browser.getCurrentUrl(); let rootUrl = await commonUtil.getProjectUrlRoot(); - browser.get(rootUrl + '/admin/project-values/custom-fields'); + + await browser.get(rootUrl + '/admin/project-values/custom-fields'); + await browser.sleep(2000); await customFieldsHelper.create(typeIndex, 'detail-test-custom-fields-text', 'desc1', 1); @@ -386,13 +389,12 @@ shared.customFields = function(typeIndex) { it('text create', async function() { let customFields = customFieldsHelper.getDetailFields(); - // await browser.sleep(4000); let count = await customFields.count(); let textField = customFields.get(count - 2); textField.$('input').sendKeys('test text'); - textField.$('.icon-floppy').click(); + textField.$('.js-save-description').click(); // debounce await browser.sleep(2000); @@ -408,10 +410,10 @@ shared.customFields = function(typeIndex) { let textField = customFields.get(count - 2); - textField.$('.icon-edit').click(); + textField.$('.js-edit-description').click(); textField.$('input').sendKeys('test text edit'); - textField.$('.icon-floppy').click(); + textField.$('.js-save-description').click(); // debounce await browser.sleep(2000); @@ -428,7 +430,7 @@ shared.customFields = function(typeIndex) { let textField = customFields.get(count - 1); textField.$('textarea').sendKeys('test text2'); - textField.$('.icon-floppy').click(); + textField.$('.js-save-description').click(); // debounce await browser.sleep(2000); @@ -446,7 +448,7 @@ shared.customFields = function(typeIndex) { textField.$('.icon-edit').click(); textField.$('textarea').sendKeys('test text2 edit'); - textField.$('.icon-floppy').click(); + textField.$('.js-save-description').click(); // // debounce await browser.sleep(2000); diff --git a/e2e/suites/admin/members.e2e.js b/e2e/suites/admin/members.e2e.js index 9a024a12..399d2ffe 100644 --- a/e2e/suites/admin/members.e2e.js +++ b/e2e/suites/admin/members.e2e.js @@ -78,7 +78,7 @@ describe('admin - members', function() { it('delete member', async function() { let initMembersCount = await adminMembershipsHelper.getMembers().count(); - let member = adminMembershipsHelper.getMembers().last(); + let member = adminMembershipsHelper.excludeOwner(adminMembershipsHelper.getMembers()).last(); adminMembershipsHelper.delete(member); @@ -89,6 +89,29 @@ describe('admin - members', function() { let membersCount = await adminMembershipsHelper.getMembers().count(); expect(membersCount).to.be.equal(initMembersCount - 1); + + await utils.notifications.success.close(); + }); + + it('trying to delete owner', async function() { + let member = await adminMembershipsHelper.getOwner(); + + adminMembershipsHelper.delete(member); + + utils.common.takeScreenshot('memberships', 'delete-owner-lb'); + + let isLeaveProjectWarningOpen = await adminMembershipsHelper.isLeaveProjectWarningOpen(); + + expect(isLeaveProjectWarningOpen).to.be.equal(true); + + let lb = adminMembershipsHelper.leavingProjectWarningLb(); + + await utils.lightbox.open(lb); + + utils.lightbox.exit(lb); + + let isPresent = await lb.isPresent(); + expect(isPresent).to.be.false; }); it('change role', async function() { diff --git a/e2e/suites/admin/project/create-delete.e2e.js b/e2e/suites/admin/project/create-delete.e2e.js index 06048212..fa338d0a 100644 --- a/e2e/suites/admin/project/create-delete.e2e.js +++ b/e2e/suites/admin/project/create-delete.e2e.js @@ -22,33 +22,31 @@ describe('create-delete project', function() { createProject.openWizard(); await lb.waitOpen(); + + utils.common.takeScreenshot('project-wizard', 'create-project'); }); - it('create - step 1', async function() { - utils.common.takeScreenshot('project-wizard', 'step1'); - - await lb.next(); - }); - - it('create - step 2 errors', async function() { - utils.common.takeScreenshot('project-wizard', 'step2'); + it('create project error', async function() { + utils.common.takeScreenshot('project-wizard', 'create-project-errors'); await lb.submit(); - utils.common.takeScreenshot('project-wizard', 'step2-error'); - let errors = await lb.errors().count(); expect(errors).to.be.equal(2); }); - it('create - step 2', async function() { + it('create project', async function() { lb.name().sendKeys('aaa'); lb.description().sendKeys('bbb'); await lb.submit(); - expect(utils.notifications.success.open()).to.be.eventually.true; + let open = utils.notifications.success.open(); + + expect(open).to.be.equal.true; + + await utils.notifications.success.close(); }); it('delete', async function() { diff --git a/e2e/suites/admin/project/modules.e2e.js b/e2e/suites/admin/project/modules.e2e.js index 42ea3c3d..4e56f925 100644 --- a/e2e/suites/admin/project/modules.e2e.js +++ b/e2e/suites/admin/project/modules.e2e.js @@ -16,19 +16,17 @@ describe('modules', function() { }); it('disable module', async function() { - let functionalities = $$('.functionality'); + let functionalities = $$('.module'); let functionality = functionalities.get(0); - let label = functionality.$('label'); + let input = functionality.$('.check input'); browser.actions() - .mouseMove(label) + .mouseMove(input) .click() .perform(); - $('button[type="submit"]').click(); - let active = await utils.common.hasClass(functionality, 'active'); expect(utils.notifications.success.open()).to.be.eventually.equal(true); @@ -38,19 +36,17 @@ describe('modules', function() { }); it('enable module', async function() { - let functionalities = $$('.functionality'); + let functionalities = $$('.module'); let functionality = functionalities.get(0); - let label = functionality.$('label'); + let input = functionality.$('.check input'); browser.actions() - .mouseMove(label) + .mouseMove(input) .click() .perform(); - $('button[type="submit"]').click(); - let active = await utils.common.hasClass(functionality, 'active'); expect(utils.notifications.success.open()).to.be.eventually.equal(true); @@ -60,24 +56,24 @@ describe('modules', function() { }); it('enable videoconference', async function() { - let functionality = $$('.functionality').get(4); + let functionality = $$('.module').get(4); - let label = functionality.$('label'); + let input = functionality.$('.check input'); browser.actions() - .mouseMove(label) + .mouseMove(input) .click() .perform(); let videoconference = functionality.$$('select').get(0); - videoconference.$(`option:nth-child(1)`).click(); + videoconference.$(`option:nth-child(2)`).click(); - let salt = functionality.$$('select').get(0); + let salt = $('#videoconference-prefix'); salt.sendKeys('abccceee'); - $('button[type="submit"]').click(); + functionality.$('.icon-save').click(); expect(utils.notifications.success.open()).to.be.eventually.equal(true); }); }); diff --git a/e2e/suites/admin/project/project-detail.e2e.js b/e2e/suites/admin/project/project-detail.e2e.js index 2ebb94a1..90e1a468 100644 --- a/e2e/suites/admin/project/project-detail.e2e.js +++ b/e2e/suites/admin/project/project-detail.e2e.js @@ -78,4 +78,43 @@ describe('project detail', function() { expect(src).to.contains('upload-image-test.png'); }); + + it('request ownership', async function() { + adminHelper.requestOwnership(); + + await utils.lightbox.open(adminHelper.requestOwnershipLb()); + + expect(utils.notifications.success.open()).to.be.eventually.true; + }); + + it('change ownership', async function() { + await utils.common.createProject(['user5@taigaio.demo']); + + await utils.nav + .init() + .admin() + .go(); + + adminHelper.changeOwner(); + + let lb = adminHelper.getChangeOwnerLb(); + + await lb.waitOpen(); + + lb.search('Alicia Flores'); + lb.select(0); + lb.addComment('text'); + + utils.common.takeScreenshot('admin', 'project-transfer-lb'); + + lb.send(); + + let changeOwnerSuccessLb = adminHelper.changeOwnerSuccessLb(); + + await utils.lightbox.open(changeOwnerSuccessLb); + + changeOwnerSuccessLb.$('.button-green').click(); + + await utils.lightbox.close(changeOwnerSuccessLb); + }); }); diff --git a/e2e/suites/auth/auth.e2e.js b/e2e/suites/auth/auth.e2e.js index 9cac8f62..0e9dbc5f 100644 --- a/e2e/suites/auth/auth.e2e.js +++ b/e2e/suites/auth/auth.e2e.js @@ -7,6 +7,10 @@ chai.use(chaiAsPromised); var expect = chai.expect; describe('auth', function() { + before(async function() { + await utils.common.logout(); + }); + it('login', async function() { browser.get(browser.params.glob.host + 'login'); @@ -32,8 +36,8 @@ describe('auth', function() { describe('page without perms', function() { let path = 'project/project-4/'; - before(function() { - return utils.common.topMenuOption(6); + before(async function() { + await utils.common.logout(); }); it("redirect to login", async function() { @@ -58,8 +62,8 @@ describe('auth', function() { describe("user", function() { var user = {}; - before(function() { - utils.common.login('admin', '123123'); + before(async function() { + await utils.common.logout(); }); it("logout", async function() { @@ -96,7 +100,7 @@ describe('auth', function() { expect($$('.checksley-required').count()).to.be.eventually.equal(4); }); - it('register ok', function() { + it('register ok', async function() { browser.get(browser.params.glob.host + 'register'); user.username = "username-" + Math.random(); @@ -111,40 +115,57 @@ describe('auth', function() { $('.submit-button').click(); - expect(browser.getCurrentUrl()).to.be.eventually.equal(browser.params.glob.host); + await utils.common.waitLoader(); + + let currentUrl = await browser.getCurrentUrl(); + + expect(currentUrl).to.be.equal(browser.params.glob.host); + + browser.get(browser.params.glob.host + '/'); + + await utils.common.waitLoader(); + await utils.common.closeJoyride(); }); }); describe("change password", function() { - beforeEach(async function() { - await utils.common.login(user.username, user.password); + it("error", async function() { + browser.get(browser.params.glob.host + 'user-settings/user-change-password'); + await browser.waitForAngular(); - return browser.get(browser.params.glob.host + 'user-settings/user-change-password'); - }); - - it("error", function() { $('#current-password').sendKeys('wrong'); $('#new-password').sendKeys('123123'); $('#retype-password').sendKeys('123123'); $('.submit-button').click(); - expect(utils.notifications.error.open()).to.be.eventually.equal(true); + let open = await utils.notifications.error.open(); + expect(open).to.be.equal(true); }); - it("success", function() { + it("success", async function() { + browser.get(browser.params.glob.host + 'user-settings/user-change-password'); + await browser.waitForAngular(); + $('#current-password').sendKeys(user.password); $('#new-password').sendKeys(user.password); $('#retype-password').sendKeys(user.password); $('.submit-button').click(); - expect(utils.notifications.success.open()).to.be.eventually.equal(true); + let open = await utils.notifications.success.open(); + expect(open).to.be.equal(true); + + await utils.notifications.success.close(); }); }); describe("remember password", function() { - beforeEach(function() { + before(async function() { + await utils.common.logout(); + }); + + beforeEach(async function() { browser.get(browser.params.glob.host + 'forgot-password'); }); @@ -176,8 +197,8 @@ describe('auth', function() { }); describe("accout", function() { - before(function() { - utils.common.login(user.username, user.password); + before(async function() { + await utils.common.login(user.username, user.password); }); it("delete", async function() { @@ -188,7 +209,7 @@ describe('auth', function() { utils.common.takeScreenshot("auth", "delete-account"); - $('.lightbox-delete-account .button-green').click(); + $('.lightbox-delete-account .button-red').click(); let url = await browser.getCurrentUrl(); diff --git a/e2e/suites/backlog.e2e.js b/e2e/suites/backlog.e2e.js index 1d7fd0d5..1fef1b0e 100644 --- a/e2e/suites/backlog.e2e.js +++ b/e2e/suites/backlog.e2e.js @@ -203,7 +203,7 @@ describe('backlog', function() { let dragableElements = backlogHelper.userStories(); let dragElement = dragableElements.get(1); - let dragElementHandler = dragElement.$('.icon-drag-v'); + let dragElementHandler = dragElement.$('.icon-drag'); let draggedElementRef = await backlogHelper.getUsRef(dragElement); await utils.common.drag(dragElementHandler, dragableElements.get(0)); @@ -254,7 +254,7 @@ describe('backlog', function() { // the us 1 and 2 are selected on the previous test let dragElement = dragableElements.get(0); - let dragElementHandler = dragElement.$('.icon-drag-v'); + let dragElementHandler = dragElement.$('.icon-drag'); await utils.common.drag(dragElementHandler, sprint); await browser.waitForAngular(); @@ -269,7 +269,7 @@ describe('backlog', function() { let dragableElements = backlogHelper.userStories(); let dragElement = dragableElements.get(0); - let dragElementHandler = dragElement.$('.icon-drag-v'); + let dragElementHandler = dragElement.$('.icon-drag'); let draggedElementRef = await backlogHelper.getUsRef(dragElement); @@ -354,6 +354,16 @@ describe('backlog', function() { expect(count).to.be.equal(4); }); + it('role filters', async function() { + await backlogHelper.fiterRole(1); + + utils.common.takeScreenshot('backlog', 'backlog-role-filters'); + + let usPoints = await backlogHelper.getUsPoints(0); + + expect(usPoints).to.match(/[0-9?]+\s\/\s[0-9?]+/); + }); + describe('milestones', function() { it('create', async function() { backlogHelper.openNewMilestone(); @@ -393,7 +403,8 @@ describe('backlog', function() { createMilestoneLightbox.name().sendKeys(sprintName); createMilestoneLightbox.submit(); - await browser.waitForAngular(); + + await createMilestoneLightbox.waitClose(); let sprintTitles = await backlogHelper.getSprintsTitles(); @@ -595,7 +606,7 @@ describe('backlog', function() { await backlogHelper.setUsStatus(2, 5); let dragElement = backlogHelper.userStories().get(2); - let dragElementHandler = dragElement.$('.icon-drag-v'); + let dragElementHandler = dragElement.$('.icon-drag'); let sprint = backlogHelper.sprints().last(); await utils.common.drag(dragElementHandler, sprint); @@ -630,7 +641,7 @@ describe('backlog', function() { await backlogHelper.setUsStatus(1, 0); let dragElement = backlogHelper.userStories().get(0); - let dragElementHandler = dragElement.$('.icon-drag-v'); + let dragElementHandler = dragElement.$('.icon-drag'); let sprint = backlogHelper.sprints().last(); await utils.common.drag(dragElementHandler, sprint); diff --git a/e2e/suites/discover/discover-home.e2e.js b/e2e/suites/discover/discover-home.e2e.js index 60387e61..2a2ebb4b 100644 --- a/e2e/suites/discover/discover-home.e2e.js +++ b/e2e/suites/discover/discover-home.e2e.js @@ -28,13 +28,15 @@ describe('discover', () => { }); it('rearrange', async () => { + let projects = discoverHelper.likedProjects(); + let discoverCount = await projects.count(); + discoverHelper.rearrangeLike(3); let filterText = await discoverHelper.getLikeFilterText(); - let projects = discoverHelper.likedProjects(); expect(filterText).to.be.equal('All time'); - expect(await projects.count()).to.be.equal(5); + expect(await projects.count()).to.be.equal(discoverCount); }); }); @@ -47,13 +49,15 @@ describe('discover', () => { }); it('rearrange', async () => { + let projects = discoverHelper.activeProjects(); + let discoverCount = await projects.count(); + discoverHelper.rearrangeActive(3); let filterText = await discoverHelper.getActiveFilterText(); - let projects = discoverHelper.activeProjects(); expect(filterText).to.be.equal('All time'); - expect(await projects.count()).to.be.equal(5); + expect(await projects.count()).to.be.equal(discoverCount); }); }); diff --git a/e2e/suites/home.e2e.js b/e2e/suites/home.e2e.js index aecc8460..e0092086 100644 --- a/e2e/suites/home.e2e.js +++ b/e2e/suites/home.e2e.js @@ -41,7 +41,7 @@ describe('home', function() { }); it('close create project lightbox', async function() { - $('div[tg-lb-create-project] .icon-delete').click(); + $('div[tg-lb-create-project] .icon-close').click(); return expect(await utils.lightbox.close('div[tg-lb-create-project]')).to.be.equal(true); }); diff --git a/e2e/suites/issues/issues.e2e.js b/e2e/suites/issues/issues.e2e.js index 8eeb93f1..8c840e0f 100644 --- a/e2e/suites/issues/issues.e2e.js +++ b/e2e/suites/issues/issues.e2e.js @@ -307,7 +307,9 @@ describe('issues list', function() { it('remove custom filter', async function() { await issuesHelper.removeCustomFilters(); - expect(issuesHelper.getCustomFilters().count()).to.be.eventually.equal(0); + let customFilterCount = await issuesHelper.getCustomFilters().count(); + + expect(customFilterCount).to.be.equal(0); }); }); }); diff --git a/e2e/suites/project-home.e2e.js b/e2e/suites/project-home.e2e.js index 5afb2343..dfaf8295 100644 --- a/e2e/suites/project-home.e2e.js +++ b/e2e/suites/project-home.e2e.js @@ -138,4 +138,11 @@ describe('project home', function() { expect(watchCounter).to.be.equal(watchCounterOld + 1); }); + it('blocked project', async function() { + browser.get(browser.params.glob.host + 'project/project-6/'); + await utils.common.waitLoader(); + await utils.common.takeScreenshot("project", "blocked-project"); + expect(browser.getCurrentUrl()).to.be.eventually.equal(browser.params.glob.host + 'blocked-project/project-6/'); + }); + }); diff --git a/e2e/suites/public/public.e2e.js b/e2e/suites/public/public.e2e.js index c5f5118c..f0fb86f4 100644 --- a/e2e/suites/public/public.e2e.js +++ b/e2e/suites/public/public.e2e.js @@ -12,7 +12,7 @@ describe('Public', async function(){ await utils.common.waitLoader(); - $$('.privacy-settings input').get(0).click(); + $$('.project-privacy-settings label').get(0).click(); $('button[type="submit"]').click(); diff --git a/e2e/suites/tasks/task-detail.e2e.js b/e2e/suites/tasks/task-detail.e2e.js index f5907c96..850cd3e1 100644 --- a/e2e/suites/tasks/task-detail.e2e.js +++ b/e2e/suites/tasks/task-detail.e2e.js @@ -33,7 +33,7 @@ describe('Task detail', function(){ it('description edition', sharedDetail.descriptionTesting); - it('status edition', sharedDetail.statusTesting); + it('status edition', sharedDetail.statusTesting.bind(this, 'In progress', 'Ready for test')); describe('assigned to edition', sharedDetail.assignedToTesting); diff --git a/e2e/suites/team.e2e.js b/e2e/suites/team.e2e.js index 64e12039..6da84e2e 100644 --- a/e2e/suites/team.e2e.js +++ b/e2e/suites/team.e2e.js @@ -20,6 +20,35 @@ describe('leaving project', function(){ }); }); +describe('leaving project owner', function(){ + before(async function(){ + await utils.common.createProject(); + await utils.nav + .init() + .team() + .go(); + }); + + it('leave project', async function(){ + teamHelper.team().leave(); + + let isLeaveProjectWarningOpen = await teamHelper.isLeaveProjectWarningOpen(); + + await utils.common.takeScreenshot("team", "leave-project-warning"); + + expect(isLeaveProjectWarningOpen).to.be.equal(true); + + let lb = teamHelper.leavingProjectWarningLb(); + + await utils.lightbox.open(lb); + + utils.lightbox.exit(lb); + + let isPresent = await lb.isPresent(); + expect(isPresent).to.be.false; + }); +}); + describe('team', function() { before(async function(){ browser.get(browser.params.glob.host + 'project/project-5/team'); diff --git a/e2e/suites/user-profile/feedback.e2e.js b/e2e/suites/user-profile/feedback.e2e.js index 3e297e6f..5e719729 100644 --- a/e2e/suites/user-profile/feedback.e2e.js +++ b/e2e/suites/user-profile/feedback.e2e.js @@ -16,7 +16,11 @@ describe('feedback', function() { }); it('send feedback', async function() { - await utils.common.topMenuOption(4); + let menu = utils.common.getMenu(); + let menuOption = $('a[translate="PROJECT.NAVIGATION.FEEDBACK"]'); + + browser.actions().mouseMove(menu).perform(); + browser.actions().mouseMove(menuOption).click().perform(); let feedbackLightbox = $('div[tg-lb-feedback]'); diff --git a/e2e/utils/common.js b/e2e/utils/common.js index 2b041457..4c981c2e 100644 --- a/e2e/utils/common.js +++ b/e2e/utils/common.js @@ -26,10 +26,8 @@ common.hasClass = async function (element, cls) { return classes.split(' ').indexOf(cls) !== -1; }; -common.isBrowser = async function(browserName) { - let cap = await browser.getCapabilities(); - - return browserName === cap.caps_.browserName; +common.isBrowser = function(browserName) { + return browserName === browser.browserName; }; common.browserSkip = function(browserName, name, fn) { @@ -76,6 +74,8 @@ common.link = async function(el) { return (href.length > 1 && href !== browser.params.glob.host + "#"); }, 5000); + + await browser .actions() .mouseMove(el) @@ -102,8 +102,7 @@ common.waitLoader = function () { common.takeScreenshot = async function (section, filename) { await common.waitRequestAnimationFrame(); - let cap = await browser.getCapabilities(); - let browserName = cap.caps_.browserName; + let browserName = browser.browserName; let screenshotsFolder = __dirname + "/../screenshots/" + browserName + "/"; let dir = screenshotsFolder + section + "/"; @@ -161,7 +160,7 @@ common.logout = async function() { return browser.driver.wait(async function() { let url = await browser.driver.getCurrentUrl(); - return url === browser.params.glob.host + 'login'; + return url === browser.params.glob.host + 'discover'; }, 10000); }; @@ -368,8 +367,12 @@ common.uploadFile = async function(inputFile, filePath) { await browser.executeScript(toggleInput, inputFile.getWebElement()); }; +common.getMenu = function() { + return $('div[tg-dropdown-user]'); +}; + common.topMenuOption = async function(option) { - let menu = $('div[tg-dropdown-user]'); + let menu = common.getMenu(); let menuOption = menu.$$('li a').get(option); browser.actions().mouseMove(menu).perform(); return browser.actions().mouseMove(menuOption).click().perform(); @@ -421,12 +424,60 @@ common.uploadImagePath = function() { } }; -common.closeJoyride = function() { - browser.waitForAngular(); - $('.introjs-skipbutton').isPresent().then((present) => { - if (present) { - $('.introjs-skipbutton').click(); - browser.sleep(600); - } - }); +common.closeJoyride = async function() { + await browser.waitForAngular(); + + let present = await $('.introjs-skipbutton').isPresent(); + + if (present) { + $('.introjs-skipbutton').click(); + await browser.sleep(600); + } +}; + +common.createProject = async function(members = []) { + var createProject = require('../helpers').createProject; + var notifications = require('./notifications'); + + browser.get(browser.params.glob.host + 'projects/'); + await common.waitLoader(); + + let lb = createProject.createProjectLightbox(); + + createProject.openWizard(); + + await lb.waitOpen(); + + lb.name().sendKeys('aaa'); + + lb.description().sendKeys('bbb'); + + await lb.submit(); + + await notifications.success.open(); + await notifications.success.close(); + + if (members.length) { + var adminMembershipsHelper = require('../helpers').adminMemberships; + + let url = await browser.getCurrentUrl(); + url = url.split('/'); + url = browser.params.glob.host + '/project/' + url[4] + '/admin/memberships'; + + browser.get(url); + await common.waitLoader(); + + let newMemberLightbox = adminMembershipsHelper.getNewMemberLightbox(); + adminMembershipsHelper.openNewMemberLightbox(); + + await newMemberLightbox.waitOpen(); + + for(var i = 0; i < members.length; i++) { + newMemberLightbox.newEmail(members[i]); + } + + newMemberLightbox.submit(); + + await newMemberLightbox.waitClose(); + } }; diff --git a/e2e/utils/lightbox.js b/e2e/utils/lightbox.js index 0108b023..471bb098 100644 --- a/e2e/utils/lightbox.js +++ b/e2e/utils/lightbox.js @@ -3,6 +3,14 @@ var common = require('./common'); var lightbox = module.exports; var transition = 300; +lightbox.exit = function(el) { + if (typeof el === 'string' || el instanceof String) { + el = $(el); + } + + el.$('.close').click(); +}; + lightbox.open = async function(el) { var deferred = protractor.promise.defer(); diff --git a/e2e/utils/nav.js b/e2e/utils/nav.js index 107317d3..b5733c56 100644 --- a/e2e/utils/nav.js +++ b/e2e/utils/nav.js @@ -46,6 +46,11 @@ var actions = { browser.get(browser.params.glob.host); return common.waitLoader(); }, + admin: async function() { + await common.link($('#nav-admin a')); + + return common.waitLoader(); + }, taskboard: async function(index) { let link = $$('.sprints .button-gray').get(index); @@ -58,6 +63,11 @@ var actions = { await common.link(task); + return common.waitLoader(); + }, + team: async function() { + await common.link($('#nav-team a')); + return common.waitLoader(); } }; @@ -87,6 +97,10 @@ var nav = { this.actions.push(actions.home.bind(null)); return this; }, + admin: function() { + this.actions.push(actions.admin.bind(null)); + return this; + }, taskboard: function(index) { this.actions.push(actions.taskboard.bind(null, index)); return this; @@ -95,6 +109,10 @@ var nav = { this.actions.push(actions.task.bind(null, index)); return this; }, + team: function(index) { + this.actions.push(actions.team.bind(null, index)); + return this; + }, go: function() { let promise = this.actions[0](); diff --git a/e2e/utils/notifications.js b/e2e/utils/notifications.js index 07719154..d5d42e10 100644 --- a/e2e/utils/notifications.js +++ b/e2e/utils/notifications.js @@ -77,3 +77,17 @@ notifications.errorLight.open = function() { }); }); }; + +notifications.errorLight.close = function() { + var el = $('.notification-message-light-error'); + + return browser + .wait(function() { + return common.hasClass(el, 'inactive'); + }, 4000) + .then(function(active) { + return browser.sleep(transition).then(function() { + return active; + }); + }); +}; diff --git a/gulpfile.js b/gulpfile.js index bb3d9a71..92d40f2c 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -27,6 +27,9 @@ var gulp = require("gulp"), del = require("del"), livereload = require('gulp-livereload'), gulpFilter = require('gulp-filter'), + addsrc = require('gulp-add-src'); + mergeStream = require('merge-stream'), + path = require('path'), coffeelint = require('gulp-coffeelint'); var argv = require('minimist')(process.argv.slice(2)); @@ -67,13 +70,14 @@ paths.css_vendor = [ paths.vendor + "intro.js/introjs.css" ]; paths.locales = paths.app + "locales/**/*.json"; +paths.modulesLocales = paths.app + "modules/**/locales/*.json"; paths.sass = [ paths.app + "**/*.scss", - "!" + paths.app + "/styles/bourbon/**/*.scss", - "!" + paths.app + "/styles/dependencies/**/*.scss", - "!" + paths.app + "/styles/extras/**/*.scss", - "!" + paths.app + "/themes/**/variables.scss", + "!" + paths.app + "styles/bourbon/**/*.scss", + "!" + paths.app + "styles/dependencies/**/*.scss", + "!" + paths.app + "styles/extras/**/*.scss", + "!" + paths.app + "themes/**/*.scss", ]; paths.sass_watch = paths.sass.concat(themes.current.customScss); @@ -85,7 +89,8 @@ paths.styles_dependencies = [ paths.css = [ paths.tmp + "styles/**/*.css", - paths.tmp + "modules/**/*.css" + paths.tmp + "modules/**/*.css", + paths.tmp + "custom.css" ]; paths.css_order = [ @@ -101,7 +106,7 @@ paths.css_order = [ paths.tmp + "styles/modules/**/*.css", paths.tmp + "modules/**/*.css", paths.tmp + "styles/shame/*.css", - paths.tmp + "themes/**/*.css" + paths.tmp + "custom.css" ]; paths.coffee = [ @@ -110,6 +115,8 @@ paths.coffee = [ ]; paths.coffee_order = [ + paths.app + "modules/compile-modules/**/*.module.coffee", + paths.app + "modules/compile-modules/**/*.coffee", paths.app + "coffee/app.coffee", paths.app + "coffee/*.coffee", paths.app + "coffee/modules/controllerMixins.coffee", @@ -138,9 +145,8 @@ paths.coffee_order = [ paths.libs = [ paths.vendor + "bluebird/js/browser/bluebird.js", paths.vendor + "jquery/dist/jquery.js", - paths.vendor + "lodash/dist/lodash.js", + paths.vendor + "lodash/lodash.js", paths.vendor + "emoticons/lib/emoticons.js", - paths.vendor + "underscore.string/lib/underscore.string.js", paths.vendor + "messageformat/messageformat.js", paths.vendor + "angular/angular.js", paths.vendor + "angular-route/angular-route.js", @@ -259,9 +265,8 @@ gulp.task("clear-sass-cache", function() { }); gulp.task("sass-compile", [], function() { - var sassFiles = paths.sass.concat(themes.current.customScss); - - return gulp.src(sassFiles) + return gulp.src(paths.sass) + .pipe(addsrc.append(themes.current.customScss)) .pipe(plumber()) .pipe(insert.prepend('@import "dependencies";')) .pipe(cached("sass")) @@ -292,9 +297,7 @@ gulp.task("css-lint-app", function() { }); gulp.task("app-css", function() { - var cssFiles = paths.css.concat(themes.current.customCss); - - return gulp.src(cssFiles) + return gulp.src(paths.css) .pipe(order(paths.css_order, {base: '.'})) .pipe(concat("theme-" + themes.current.name + ".css")) .pipe(autoprefixer({ @@ -379,8 +382,22 @@ gulp.task("app-loader", function() { }); gulp.task("locales", function() { - return gulp.src(paths.locales) + var plugins = gulp.src(paths.app + "modules/**/locales/*.json") + .pipe(rename(function (localeFile) { + // rename app/modules/compiles-modules/tg-contrib/locales/locale-en.json + // to tg-contrib/locale-en.json + + var pluginPath = path.join(localeFile.dirname, '..'); + var pluginFolder = pluginPath.split('/').pop(); + + localeFile.dirname = pluginFolder; + })) .pipe(gulp.dest(paths.distVersion + "locales")); + + var core = gulp.src(paths.locales) + .pipe(gulp.dest(paths.distVersion + "locales")); + + return mergeStream(plugins, core); }); gulp.task("coffee-lint", function () { @@ -480,7 +497,7 @@ gulp.task("copy-theme-fonts", function() { }); gulp.task("copy-images", function() { - return gulp.src(paths.app + "/images/**/*") + return gulp.src([paths.app + "/images/**/*", paths.app + '/modules/compile-modules/**/images/*']) .pipe(gulpif(isDeploy, imagemin({progressive: true}))) .pipe(gulp.dest(paths.distVersion + "/images/")); }); @@ -550,7 +567,7 @@ gulp.task("watch", function() { gulp.watch(paths.svg, ["copy-svg"]); gulp.watch(paths.coffee, ["app-watch"]); gulp.watch(paths.libs, ["jslibs-watch"]); - gulp.watch(paths.locales, ["locales"]); + gulp.watch([paths.locales, paths.modulesLocales], ["locales"]); gulp.watch(paths.images, ["copy-images"]); gulp.watch(paths.fonts, ["copy-fonts"]); }); diff --git a/package.json b/package.json index ed924a9d..1232b445 100644 --- a/package.json +++ b/package.json @@ -18,11 +18,14 @@ "scripts": { "scss-lint": "gulp scss-lint --fail", "test": "./node_modules/karma/bin/karma start", - "e2e": "node ./node_modules/babel/bin/babel-node.js --stage=1 ./run-e2e.js" + "e2e": "./node_modules/.bin/babel-node run-e2e.js" }, "devDependencies": { "angular-mocks": "1.4.7", - "babel": "^5.6.5", + "babel-cli": "^6.6.5", + "babel-polyfill": "^6.7.4", + "babel-preset-es2015": "^6.6.0", + "babel-register": "^6.7.2", "bluebird": "^3.0.2", "chai": "^3.3.0", "chai-as-promised": "^5.1.0", @@ -34,6 +37,7 @@ "express": "^4.12.0", "glob": "^5.0.14", "gulp": "^3.8.11", + "gulp-add-src": "^0.2.0", "gulp-angular-templatecache": "^1.5.0", "gulp-autoprefixer": "^3.0.1", "gulp-cache": "^0.3.0", @@ -71,6 +75,7 @@ "karma-coffee-preprocessor": "^0.3.0", "karma-mocha": "^0.2.0", "karma-sourcemap-loader": "^0.3.4", + "merge-stream": "^1.0.0", "minimist": "^1.1.1", "mocha": "^2.2.4", "node-uuid": "^1.4.3", diff --git a/run-e2e.js b/run-e2e.js index 33af48d8..e7f005f7 100644 --- a/run-e2e.js +++ b/run-e2e.js @@ -3,6 +3,8 @@ var child_process = require('child_process'); var inquirer = require("inquirer"); var Promise = require('bluebird'); +// npm run e2e -- -s userStories, auth + var suites = [ 'auth', 'public', diff --git a/test-utils.js b/test-utils.js index 4b33b6ad..751db5a0 100644 --- a/test-utils.js +++ b/test-utils.js @@ -30,4 +30,6 @@ var original = searchOriginal(this); original._rejectfn.apply(this, arguments); }; + + window.addDecorator = function() {}; }());