Merge branch 'master' into stable
|
@ -8,6 +8,7 @@ bower_components
|
|||
app/coffee/modules/locales/locale*.coffee
|
||||
*.swp
|
||||
*.swo
|
||||
.#*
|
||||
tags
|
||||
tmp/
|
||||
app/config/main.coffee
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
before_install:
|
||||
- export CHROME_BIN=chromium-browser
|
||||
- export DISPLAY=:99.0
|
||||
- sh -e /etc/init.d/xvfb start
|
||||
- npm install -g bower
|
||||
- npm install -g gulp
|
||||
install:
|
||||
- npm install
|
||||
- bower install
|
||||
before_script:
|
||||
- gulp deploy
|
||||
language: node_js
|
||||
node_js:
|
||||
- "0.12"
|
|
@ -26,3 +26,4 @@ answer newbie questions, and generally made Taiga that much better:
|
|||
- Daniel Koch
|
||||
- Florian Bezagu
|
||||
- Ryan Swanstrom
|
||||
- Chris Wilson <chris.wilson@aridhia.com>
|
||||
|
|
40
CHANGELOG.md
|
@ -1,7 +1,45 @@
|
|||
# Changelog #
|
||||
|
||||
|
||||
## 1.7.0 Empetrum Nigrum (unreleased)
|
||||
## 1.8.0 Saracenia Purpurea (2015-06-18)
|
||||
|
||||
### Features
|
||||
- Menus
|
||||
- New User menu
|
||||
- New project menu design
|
||||
- Home
|
||||
- Change home page for logged users, show a user dashboard with `working on` and `watching` sections.
|
||||
- Proyects privacity
|
||||
- Enabled public projects
|
||||
- Improve SEO, fix meta tags and added social meta tags
|
||||
- About project detail
|
||||
- New projects list design
|
||||
- New project detail page design
|
||||
- Add project timeline
|
||||
- User profile
|
||||
- Now, access to edit user settings is out of a project
|
||||
- New User profile view
|
||||
- Add activity timeline to user profiles
|
||||
- With the activity of my contacts on mine
|
||||
- With the activity of the user on others
|
||||
- Add user contacts to user profile
|
||||
- Add project list to user profile
|
||||
- Backlog panel
|
||||
- Improve the drag & drop behavior of USs in backlog panel
|
||||
- Select multiple US with `shift` in the backlog panel
|
||||
- Global searches:
|
||||
- Show the reference of entities in search results (thanks to [@artlepool](https://github.com/artlepool))
|
||||
- Autofocus on search modal
|
||||
- i18n.
|
||||
- Add deutsch (de) translation.
|
||||
- Add nederlands (nl) translation.
|
||||
|
||||
### Misc
|
||||
- Improve performance: remove some unnecessary calls to the api.
|
||||
- Lots of small and not so small bugfixes.
|
||||
|
||||
|
||||
## 1.7.0 Empetrum Nigrum (2015-05-21)
|
||||
|
||||
### Features
|
||||
- Make Taiga translatable (i18n support).
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||

|
||||
[](https://taiga.io "Managed with Taiga")
|
||||
[](https://travis-ci.org/taigaio/taiga-front)
|
||||
|
||||
## Get the compiled version ##
|
||||
|
||||
|
|
|
@ -28,129 +28,348 @@ taiga.generateHash = (components=[]) ->
|
|||
components = _.map(components, (x) -> JSON.stringify(x))
|
||||
return hex_sha1(components.join(":"))
|
||||
|
||||
|
||||
taiga.generateUniqueSessionIdentifier = ->
|
||||
date = (new Date()).getTime()
|
||||
randomNumber = Math.floor(Math.random() * 0x9000000)
|
||||
return taiga.generateHash([date, randomNumber])
|
||||
|
||||
|
||||
taiga.sessionId = taiga.generateUniqueSessionIdentifier()
|
||||
|
||||
|
||||
configure = ($routeProvider, $locationProvider, $httpProvider, $provide, $tgEventsProvider, tgLoaderProvider,
|
||||
configure = ($routeProvider, $locationProvider, $httpProvider, $provide, $tgEventsProvider,
|
||||
$compileProvider, $translateProvider) ->
|
||||
|
||||
# wait until the trasnlation is ready to resolve the page
|
||||
originalWhen = $routeProvider.when
|
||||
|
||||
$routeProvider.when = (path, route) ->
|
||||
route.resolve || (route.resolve = {})
|
||||
angular.extend(route.resolve, {
|
||||
languageLoad: ["$q", "$translate", ($q, $translate) ->
|
||||
deferred = $q.defer()
|
||||
|
||||
$translate().then () -> deferred.resolve()
|
||||
|
||||
return deferred.promise
|
||||
]
|
||||
})
|
||||
|
||||
return originalWhen.call($routeProvider, path, route)
|
||||
|
||||
$routeProvider.when("/",
|
||||
{templateUrl: "project/projects.html"})
|
||||
{
|
||||
templateUrl: "home/home.html",
|
||||
access: {
|
||||
requiresLogin: true
|
||||
},
|
||||
title: "HOME.PAGE_TITLE",
|
||||
description: "HOME.PAGE_DESCRIPTION",
|
||||
loader: true
|
||||
}
|
||||
)
|
||||
|
||||
$routeProvider.when("/projects/",
|
||||
{
|
||||
templateUrl: "projects/listing/projects-listing.html",
|
||||
access: {
|
||||
requiresLogin: true
|
||||
},
|
||||
title: "PROJECTS.PAGE_TITLE",
|
||||
description: "PROJECTS.PAGE_DESCRIPTION",
|
||||
loader: true,
|
||||
controller: "ProjectsListing",
|
||||
controllerAs: "vm"
|
||||
}
|
||||
)
|
||||
|
||||
$routeProvider.when("/project/:pslug/",
|
||||
{templateUrl: "project/project.html"})
|
||||
{
|
||||
templateUrl: "projects/project/project.html",
|
||||
loader: true,
|
||||
controller: "Project",
|
||||
controllerAs: "vm"
|
||||
section: "project-timeline"
|
||||
}
|
||||
)
|
||||
|
||||
$routeProvider.when("/project/:pslug/search",
|
||||
{templateUrl: "search/search.html", reloadOnSearch: false})
|
||||
{
|
||||
templateUrl: "search/search.html",
|
||||
reloadOnSearch: false,
|
||||
section: "search"
|
||||
}
|
||||
)
|
||||
|
||||
$routeProvider.when("/project/:pslug/backlog",
|
||||
{templateUrl: "backlog/backlog.html", resolve: {loader: tgLoaderProvider.add()}})
|
||||
{
|
||||
templateUrl: "backlog/backlog.html",
|
||||
loader: true,
|
||||
section: "backlog"
|
||||
}
|
||||
)
|
||||
|
||||
$routeProvider.when("/project/:pslug/kanban",
|
||||
{templateUrl: "kanban/kanban.html", resolve: {loader: tgLoaderProvider.add()}})
|
||||
{
|
||||
templateUrl: "kanban/kanban.html",
|
||||
loader: true,
|
||||
section: "kanban"
|
||||
}
|
||||
)
|
||||
|
||||
# Milestone
|
||||
$routeProvider.when("/project/:pslug/taskboard/:sslug",
|
||||
{templateUrl: "taskboard/taskboard.html", resolve: {loader: tgLoaderProvider.add()}})
|
||||
{
|
||||
templateUrl: "taskboard/taskboard.html",
|
||||
loader: true,
|
||||
section: "backlog"
|
||||
}
|
||||
)
|
||||
|
||||
# User stories
|
||||
$routeProvider.when("/project/:pslug/us/:usref",
|
||||
{templateUrl: "us/us-detail.html", resolve: {loader: tgLoaderProvider.add()}})
|
||||
{
|
||||
templateUrl: "us/us-detail.html",
|
||||
loader: true,
|
||||
section: "backlog-kanban"
|
||||
}
|
||||
)
|
||||
|
||||
# Tasks
|
||||
$routeProvider.when("/project/:pslug/task/:taskref",
|
||||
{templateUrl: "task/task-detail.html", resolve: {loader: tgLoaderProvider.add()}})
|
||||
{
|
||||
templateUrl: "task/task-detail.html",
|
||||
loader: true,
|
||||
section: "backlog-kanban"
|
||||
}
|
||||
)
|
||||
|
||||
# Wiki
|
||||
$routeProvider.when("/project/:pslug/wiki",
|
||||
{redirectTo: (params) -> "/project/#{params.pslug}/wiki/home"}, )
|
||||
$routeProvider.when("/project/:pslug/wiki/:slug",
|
||||
{templateUrl: "wiki/wiki.html", resolve: {loader: tgLoaderProvider.add()}})
|
||||
{
|
||||
templateUrl: "wiki/wiki.html",
|
||||
loader: true,
|
||||
section: "wiki"
|
||||
}
|
||||
)
|
||||
|
||||
# Team
|
||||
$routeProvider.when("/project/:pslug/team",
|
||||
{templateUrl: "team/team.html", resolve: {loader: tgLoaderProvider.add()}})
|
||||
{
|
||||
templateUrl: "team/team.html",
|
||||
loader: true,
|
||||
section: "team"
|
||||
}
|
||||
)
|
||||
|
||||
# Issues
|
||||
$routeProvider.when("/project/:pslug/issues",
|
||||
{templateUrl: "issue/issues.html", resolve: {loader: tgLoaderProvider.add()}})
|
||||
{
|
||||
templateUrl: "issue/issues.html",
|
||||
loader: true,
|
||||
section: "issues"
|
||||
}
|
||||
)
|
||||
$routeProvider.when("/project/:pslug/issue/:issueref",
|
||||
{templateUrl: "issue/issues-detail.html", resolve: {loader: tgLoaderProvider.add()}})
|
||||
{
|
||||
templateUrl: "issue/issues-detail.html",
|
||||
loader: true,
|
||||
section: "issues"
|
||||
}
|
||||
)
|
||||
|
||||
# Admin - Project Profile
|
||||
$routeProvider.when("/project/:pslug/admin/project-profile/details",
|
||||
{templateUrl: "admin/admin-project-profile.html"})
|
||||
{
|
||||
templateUrl: "admin/admin-project-profile.html",
|
||||
section: "admin"
|
||||
}
|
||||
)
|
||||
$routeProvider.when("/project/:pslug/admin/project-profile/default-values",
|
||||
{templateUrl: "admin/admin-project-default-values.html"})
|
||||
{
|
||||
templateUrl: "admin/admin-project-default-values.html",
|
||||
section: "admin"
|
||||
}
|
||||
)
|
||||
$routeProvider.when("/project/:pslug/admin/project-profile/modules",
|
||||
{templateUrl: "admin/admin-project-modules.html"})
|
||||
{
|
||||
templateUrl: "admin/admin-project-modules.html",
|
||||
section: "admin"
|
||||
}
|
||||
)
|
||||
$routeProvider.when("/project/:pslug/admin/project-profile/export",
|
||||
{templateUrl: "admin/admin-project-export.html"})
|
||||
{
|
||||
templateUrl: "admin/admin-project-export.html",
|
||||
section: "admin"
|
||||
}
|
||||
)
|
||||
$routeProvider.when("/project/:pslug/admin/project-profile/reports",
|
||||
{templateUrl: "admin/admin-project-reports.html"})
|
||||
{
|
||||
templateUrl: "admin/admin-project-reports.html",
|
||||
section: "admin"
|
||||
}
|
||||
)
|
||||
|
||||
$routeProvider.when("/project/:pslug/admin/project-values/status",
|
||||
{templateUrl: "admin/admin-project-values-status.html"})
|
||||
{
|
||||
templateUrl: "admin/admin-project-values-status.html",
|
||||
section: "admin"
|
||||
}
|
||||
)
|
||||
$routeProvider.when("/project/:pslug/admin/project-values/points",
|
||||
{templateUrl: "admin/admin-project-values-points.html"})
|
||||
{
|
||||
templateUrl: "admin/admin-project-values-points.html",
|
||||
section: "admin"
|
||||
}
|
||||
)
|
||||
$routeProvider.when("/project/:pslug/admin/project-values/priorities",
|
||||
{templateUrl: "admin/admin-project-values-priorities.html"})
|
||||
{
|
||||
templateUrl: "admin/admin-project-values-priorities.html",
|
||||
section: "admin"
|
||||
}
|
||||
)
|
||||
$routeProvider.when("/project/:pslug/admin/project-values/severities",
|
||||
{templateUrl: "admin/admin-project-values-severities.html"})
|
||||
{
|
||||
templateUrl: "admin/admin-project-values-severities.html",
|
||||
section: "admin"
|
||||
}
|
||||
)
|
||||
$routeProvider.when("/project/:pslug/admin/project-values/types",
|
||||
{templateUrl: "admin/admin-project-values-types.html"})
|
||||
{
|
||||
templateUrl: "admin/admin-project-values-types.html",
|
||||
section: "admin"
|
||||
}
|
||||
)
|
||||
$routeProvider.when("/project/:pslug/admin/project-values/custom-fields",
|
||||
{templateUrl: "admin/admin-project-values-custom-fields.html"})
|
||||
{
|
||||
templateUrl: "admin/admin-project-values-custom-fields.html",
|
||||
section: "admin"
|
||||
}
|
||||
)
|
||||
|
||||
$routeProvider.when("/project/:pslug/admin/memberships",
|
||||
{templateUrl: "admin/admin-memberships.html"})
|
||||
{
|
||||
templateUrl: "admin/admin-memberships.html",
|
||||
section: "admin"
|
||||
}
|
||||
)
|
||||
# Admin - Roles
|
||||
$routeProvider.when("/project/:pslug/admin/roles",
|
||||
{templateUrl: "admin/admin-roles.html"})
|
||||
{
|
||||
templateUrl: "admin/admin-roles.html",
|
||||
section: "admin"
|
||||
}
|
||||
)
|
||||
|
||||
# Admin - Third Parties
|
||||
$routeProvider.when("/project/:pslug/admin/third-parties/webhooks",
|
||||
{templateUrl: "admin/admin-third-parties-webhooks.html"})
|
||||
{
|
||||
templateUrl: "admin/admin-third-parties-webhooks.html",
|
||||
section: "admin"
|
||||
}
|
||||
)
|
||||
$routeProvider.when("/project/:pslug/admin/third-parties/github",
|
||||
{templateUrl: "admin/admin-third-parties-github.html"})
|
||||
{
|
||||
templateUrl: "admin/admin-third-parties-github.html",
|
||||
section: "admin"
|
||||
}
|
||||
)
|
||||
$routeProvider.when("/project/:pslug/admin/third-parties/gitlab",
|
||||
{templateUrl: "admin/admin-third-parties-gitlab.html"})
|
||||
{
|
||||
templateUrl: "admin/admin-third-parties-gitlab.html",
|
||||
section: "admin"
|
||||
}
|
||||
)
|
||||
$routeProvider.when("/project/:pslug/admin/third-parties/bitbucket",
|
||||
{templateUrl: "admin/admin-third-parties-bitbucket.html"})
|
||||
{
|
||||
templateUrl: "admin/admin-third-parties-bitbucket.html",
|
||||
section: "admin"
|
||||
}
|
||||
)
|
||||
# Admin - Contrib Plugins
|
||||
$routeProvider.when("/project/:pslug/admin/contrib/:plugin",
|
||||
{templateUrl: "contrib/main.html"})
|
||||
|
||||
# User settings
|
||||
$routeProvider.when("/project/:pslug/user-settings/user-profile",
|
||||
$routeProvider.when("/user-settings/user-profile",
|
||||
{templateUrl: "user/user-profile.html"})
|
||||
$routeProvider.when("/project/:pslug/user-settings/user-change-password",
|
||||
$routeProvider.when("/user-settings/user-change-password",
|
||||
{templateUrl: "user/user-change-password.html"})
|
||||
$routeProvider.when("/project/:pslug/user-settings/user-avatar",
|
||||
{templateUrl: "user/user-avatar.html"})
|
||||
$routeProvider.when("/project/:pslug/user-settings/mail-notifications",
|
||||
$routeProvider.when("/user-settings/mail-notifications",
|
||||
{templateUrl: "user/mail-notifications.html"})
|
||||
$routeProvider.when("/change-email/:email_token",
|
||||
{templateUrl: "user/change-email.html"})
|
||||
$routeProvider.when("/cancel-account/:cancel_token",
|
||||
{templateUrl: "user/cancel-account.html"})
|
||||
|
||||
# User profile
|
||||
$routeProvider.when("/profile",
|
||||
{
|
||||
templateUrl: "profile/profile.html",
|
||||
loader: true,
|
||||
access: {
|
||||
requiresLogin: true
|
||||
},
|
||||
controller: "Profile",
|
||||
controllerAs: "vm"
|
||||
}
|
||||
)
|
||||
|
||||
$routeProvider.when("/profile/:slug",
|
||||
{
|
||||
templateUrl: "profile/profile.html",
|
||||
loader: true,
|
||||
controller: "Profile",
|
||||
controllerAs: "vm"
|
||||
}
|
||||
)
|
||||
|
||||
# Auth
|
||||
$routeProvider.when("/login",
|
||||
{templateUrl: "auth/login.html"})
|
||||
{
|
||||
templateUrl: "auth/login.html",
|
||||
title: "LOGIN.PAGE_TITLE"
|
||||
description: "LOGIN.PAGE_DESCRIPTION"
|
||||
}
|
||||
)
|
||||
$routeProvider.when("/register",
|
||||
{templateUrl: "auth/register.html"})
|
||||
{
|
||||
templateUrl: "auth/register.html",
|
||||
title: "REGISTER.PAGE_TITLE",
|
||||
description: "REGISTER.PAGE_DESCRIPTION"
|
||||
}
|
||||
)
|
||||
$routeProvider.when("/forgot-password",
|
||||
{templateUrl: "auth/forgot-password.html"})
|
||||
{
|
||||
templateUrl: "auth/forgot-password.html",
|
||||
title: "FORGOT_PASSWORD.PAGE_TITLE",
|
||||
description: "FORGOT_PASSWORD.PAGE_DESCRIPTION"
|
||||
}
|
||||
)
|
||||
$routeProvider.when("/change-password",
|
||||
{templateUrl: "auth/change-password-from-recovery.html"})
|
||||
{
|
||||
templateUrl: "auth/change-password-from-recovery.html",
|
||||
title: "CHANGE_PASSWORD.PAGE_TITLE",
|
||||
description: "CHANGE_PASSWORD.PAGE_TITLE",
|
||||
}
|
||||
)
|
||||
$routeProvider.when("/change-password/:token",
|
||||
{templateUrl: "auth/change-password-from-recovery.html"})
|
||||
{
|
||||
templateUrl: "auth/change-password-from-recovery.html",
|
||||
title: "CHANGE_PASSWORD.PAGE_TITLE",
|
||||
description: "CHANGE_PASSWORD.PAGE_TITLE",
|
||||
}
|
||||
)
|
||||
$routeProvider.when("/invitation/:token",
|
||||
{templateUrl: "auth/invitation.html"})
|
||||
{
|
||||
templateUrl: "auth/invitation.html",
|
||||
title: "INVITATION.PAGE_TITLE",
|
||||
description: "INVITATION.PAGE_DESCRIPTION"
|
||||
}
|
||||
)
|
||||
|
||||
# Errors/Exceptions
|
||||
$routeProvider.when("/error",
|
||||
|
@ -177,6 +396,8 @@ configure = ($routeProvider, $locationProvider, $httpProvider, $provide, $tgEven
|
|||
"X-Session-Id": taiga.sessionId
|
||||
}
|
||||
|
||||
$httpProvider.useApplyAsync(true)
|
||||
|
||||
$tgEventsProvider.setSessionId(taiga.sessionId)
|
||||
|
||||
# Add next param when user try to access to a secction need auth permissions.
|
||||
|
@ -201,6 +422,35 @@ configure = ($routeProvider, $locationProvider, $httpProvider, $provide, $tgEven
|
|||
|
||||
$httpProvider.interceptors.push("authHttpIntercept")
|
||||
|
||||
|
||||
loaderIntercept = ($q, loaderService) ->
|
||||
return {
|
||||
request: (config) ->
|
||||
loaderService.logRequest()
|
||||
|
||||
return config
|
||||
|
||||
requestError: (rejection) ->
|
||||
loaderService.logResponse()
|
||||
|
||||
return $q.reject(rejection)
|
||||
|
||||
responseError: (rejection) ->
|
||||
loaderService.logResponse()
|
||||
|
||||
return $q.reject(rejection)
|
||||
|
||||
response: (response) ->
|
||||
loaderService.logResponse()
|
||||
|
||||
return response
|
||||
}
|
||||
|
||||
|
||||
$provide.factory("loaderIntercept", ["$q", "tgLoader", loaderIntercept])
|
||||
|
||||
$httpProvider.interceptors.push("loaderIntercept")
|
||||
|
||||
# If there is an error in the version throw a notify error.
|
||||
# IMPROVEiMENT: Move this version error handler to USs, issues and tasks repository
|
||||
versionCheckHttpIntercept = ($q) ->
|
||||
|
@ -286,7 +536,7 @@ i18nInit = (lang, $translate) ->
|
|||
checksley.updateMessages('default', messages)
|
||||
|
||||
|
||||
init = ($log, $config, $rootscope, $auth, $events, $analytics, $translate) ->
|
||||
init = ($log, $rootscope, $auth, $events, $analytics, $translate, $location, $navUrls, appMetaService, projectService, loaderService) ->
|
||||
$log.debug("Initialize application")
|
||||
|
||||
# Taiga Plugins
|
||||
|
@ -297,6 +547,10 @@ init = ($log, $config, $rootscope, $auth, $events, $analytics, $translate) ->
|
|||
lang = ctx.language
|
||||
i18nInit(lang, $translate)
|
||||
|
||||
# bluebird
|
||||
Promise.setScheduler (cb) ->
|
||||
$rootscope.$evalAsync(cb)
|
||||
|
||||
# Load user
|
||||
if $auth.isAuthenticated()
|
||||
$events.setupConnection()
|
||||
|
@ -305,16 +559,50 @@ init = ($log, $config, $rootscope, $auth, $events, $analytics, $translate) ->
|
|||
# Analytics
|
||||
$analytics.initialize()
|
||||
|
||||
# On the first page load the loader is painted in `$routeChangeSuccess`
|
||||
# because we need to hide the tg-navigation-bar.
|
||||
# In the other cases the loader is in `$routeChangeSuccess`
|
||||
# because `location.noreload` prevent to execute this event.
|
||||
un = $rootscope.$on '$routeChangeStart', (event, next) ->
|
||||
if next.loader
|
||||
loaderService.start(true)
|
||||
|
||||
un()
|
||||
|
||||
$rootscope.$on '$routeChangeSuccess', (event, next) ->
|
||||
if next.loader
|
||||
loaderService.start(true)
|
||||
|
||||
if next.access && next.access.requiresLogin
|
||||
if !$auth.isAuthenticated()
|
||||
$location.path($navUrls.resolve("login"))
|
||||
|
||||
projectService.setSection(next.section)
|
||||
|
||||
if next.params.pslug
|
||||
projectService.setProject(next.params.pslug)
|
||||
else
|
||||
projectService.cleanProject()
|
||||
|
||||
if next.title or next.description
|
||||
title = $translate.instant(next.title or "")
|
||||
description = $translate.instant(next.description or "")
|
||||
appMetaService.setAll(title, description)
|
||||
|
||||
|
||||
modules = [
|
||||
# Main Global Modules
|
||||
"taigaBase",
|
||||
"taigaCommon",
|
||||
"taigaResources",
|
||||
"taigaResources2",
|
||||
"taigaAuth",
|
||||
"taigaEvents",
|
||||
|
||||
# Specific Modules
|
||||
"taigaHome",
|
||||
"taigaNavigationBar",
|
||||
"taigaProjects",
|
||||
"taigaRelatedTasks",
|
||||
"taigaBacklog",
|
||||
"taigaTaskboard",
|
||||
|
@ -326,13 +614,16 @@ modules = [
|
|||
"taigaWiki",
|
||||
"taigaSearch",
|
||||
"taigaAdmin",
|
||||
"taigaNavMenu",
|
||||
"taigaProject",
|
||||
"taigaUserSettings",
|
||||
"taigaFeedback",
|
||||
"taigaPlugins",
|
||||
"taigaIntegrations",
|
||||
"taigaComponents",
|
||||
# new modules
|
||||
"taigaProfile",
|
||||
"taigaHome",
|
||||
"taigaUserTimeline",
|
||||
|
||||
# template cache
|
||||
"templates",
|
||||
|
@ -340,7 +631,9 @@ modules = [
|
|||
# Vendor modules
|
||||
"ngRoute",
|
||||
"ngAnimate",
|
||||
"pascalprecht.translate"
|
||||
"pascalprecht.translate",
|
||||
"infinite-scroll",
|
||||
"tgRepeat"
|
||||
].concat(_.map(@.taigaContribPlugins, (plugin) -> plugin.module))
|
||||
|
||||
# Main module definition
|
||||
|
@ -352,7 +645,6 @@ module.config([
|
|||
"$httpProvider",
|
||||
"$provide",
|
||||
"$tgEventsProvider",
|
||||
"tgLoaderProvider",
|
||||
"$compileProvider",
|
||||
"$translateProvider",
|
||||
configure
|
||||
|
@ -360,11 +652,15 @@ module.config([
|
|||
|
||||
module.run([
|
||||
"$log",
|
||||
"$tgConfig",
|
||||
"$rootScope",
|
||||
"$tgAuth",
|
||||
"$tgEvents",
|
||||
"$tgAnalytics",
|
||||
"$translate"
|
||||
"$translate",
|
||||
"$tgLocation",
|
||||
"$tgNavUrls",
|
||||
"tgAppMetaService",
|
||||
"tgProjectService",
|
||||
"tgLoader",
|
||||
init
|
||||
])
|
||||
|
|
|
@ -43,11 +43,12 @@ class MembershipsController extends mixOf(taiga.Controller, taiga.PageMixin, tai
|
|||
"$tgLocation",
|
||||
"$tgNavUrls",
|
||||
"$tgAnalytics",
|
||||
"$appTitle"
|
||||
"tgAppMetaService",
|
||||
"$translate"
|
||||
]
|
||||
|
||||
constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q,
|
||||
@location, @navUrls, @analytics, @appTitle) ->
|
||||
constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, @navUrls, @analytics,
|
||||
@appMetaService, @translate) ->
|
||||
bindMethods(@)
|
||||
|
||||
@scope.project = {}
|
||||
|
@ -56,7 +57,9 @@ class MembershipsController extends mixOf(taiga.Controller, taiga.PageMixin, tai
|
|||
promise = @.loadInitialData()
|
||||
|
||||
promise.then =>
|
||||
@appTitle.set("Membership - " + @scope.project.name)
|
||||
title = @translate.instant("ADMIN.MEMBERSHIPS.PAGE_TITLE", {projectName: @scope.project.name})
|
||||
description = @scope.project.description
|
||||
@appMetaService.setAll(title, description)
|
||||
|
||||
promise.then null, @.onInitialDataError.bind(@)
|
||||
|
||||
|
@ -65,10 +68,11 @@ class MembershipsController extends mixOf(taiga.Controller, taiga.PageMixin, tai
|
|||
@analytics.trackEvent("membership", "create", "create memberships on admin", 1)
|
||||
|
||||
loadProject: ->
|
||||
return @rs.projects.get(@scope.projectId).then (project) =>
|
||||
return @rs.projects.getBySlug(@params.pslug).then (project) =>
|
||||
if not project.i_am_owner
|
||||
@location.path(@navUrls.resolve("permission-denied"))
|
||||
|
||||
@scope.projectId = project.id
|
||||
@scope.project = project
|
||||
@scope.$emit('project:loaded', project)
|
||||
return project
|
||||
|
@ -76,20 +80,20 @@ class MembershipsController extends mixOf(taiga.Controller, taiga.PageMixin, tai
|
|||
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)
|
||||
@scope.memberships = _.filter(data.models, (membership) ->
|
||||
membership.user == null or membership.is_user_active)
|
||||
@scope.page = data.current
|
||||
@scope.count = data.count
|
||||
@scope.paginatedBy = data.paginatedBy
|
||||
return data
|
||||
|
||||
loadInitialData: ->
|
||||
promise = @repo.resolve({pslug: @params.pslug}).then (data) =>
|
||||
@scope.projectId = data.project
|
||||
return data
|
||||
promise = @.loadProject()
|
||||
promise.then =>
|
||||
@.loadUsersAndRoles()
|
||||
@.loadMembers()
|
||||
|
||||
return promise.then(=> @.loadProject())
|
||||
.then(=> @.loadUsersAndRoles())
|
||||
.then(=> @.loadMembers())
|
||||
return promise
|
||||
|
||||
getUrlFilters: ->
|
||||
filters = _.pick(@location.search(), "page")
|
||||
|
@ -377,7 +381,9 @@ MembershipsRowActionsDirective = ($log, $repo, $rs, $confirm, $compile, $transla
|
|||
$el.on "click", ".pending", (event) ->
|
||||
event.preventDefault()
|
||||
onSuccess = ->
|
||||
text = $translate.instant("ADMIN.MEMBERSHIP.SUCCESS_SEND_INVITATION", {email: $scope.member.email})
|
||||
text = $translate.instant("ADMIN.MEMBERSHIP.SUCCESS_SEND_INVITATION", {
|
||||
email: $scope.member.email
|
||||
})
|
||||
$confirm.notify("success", text)
|
||||
onError = ->
|
||||
text = $translate.instant("ADMIM.MEMBERSHIP.ERROR_SEND_INVITATION")
|
||||
|
@ -414,4 +420,5 @@ MembershipsRowActionsDirective = ($log, $repo, $rs, $confirm, $compile, $transla
|
|||
return {link: link}
|
||||
|
||||
|
||||
module.directive("tgMembershipsRowActions", ["$log", "$tgRepo", "$tgResources", "$tgConfirm", "$compile", "$translate", MembershipsRowActionsDirective])
|
||||
module.directive("tgMembershipsRowActions", ["$log", "$tgRepo", "$tgResources", "$tgConfirm", "$compile",
|
||||
"$translate", MembershipsRowActionsDirective])
|
||||
|
|
|
@ -47,34 +47,38 @@ class ProjectProfileController extends mixOf(taiga.Controller, taiga.PageMixin)
|
|||
"$q",
|
||||
"$tgLocation",
|
||||
"$tgNavUrls",
|
||||
"$appTitle",
|
||||
"tgAppMetaService",
|
||||
"$translate"
|
||||
]
|
||||
|
||||
constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, @navUrls, @appTitle, @translate) ->
|
||||
constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, @navUrls,
|
||||
@appMetaService, @translate) ->
|
||||
@scope.project = {}
|
||||
|
||||
promise = @.loadInitialData()
|
||||
|
||||
promise.then =>
|
||||
sectionName = @translate.instant( @scope.sectionName)
|
||||
appTitle = @translate.instant("ADMIN.PROJECT_PROFILE.PAGE_TITLE", {
|
||||
title = @translate.instant("ADMIN.PROJECT_PROFILE.PAGE_TITLE", {
|
||||
sectionName: sectionName, projectName: @scope.project.name})
|
||||
@appTitle.set(appTitle)
|
||||
description = @scope.project.description
|
||||
@appMetaService.setAll(title, description)
|
||||
|
||||
promise.then null, @.onInitialDataError.bind(@)
|
||||
|
||||
@scope.$on "project:loaded", =>
|
||||
sectionName = @translate.instant(@scope.sectionName)
|
||||
appTitle = @translate.instant("ADMIN.PROJECT_PROFILE.PAGE_TITLE", {
|
||||
title = @translate.instant("ADMIN.PROJECT_PROFILE.PAGE_TITLE", {
|
||||
sectionName: sectionName, projectName: @scope.project.name})
|
||||
@appTitle.set(appTitle)
|
||||
description = @scope.project.description
|
||||
@appMetaService.setAll(title, description)
|
||||
|
||||
loadProject: ->
|
||||
return @rs.projects.get(@scope.projectId).then (project) =>
|
||||
return @rs.projects.getBySlug(@params.pslug).then (project) =>
|
||||
if not project.i_am_owner
|
||||
@location.path(@navUrls.resolve("permission-denied"))
|
||||
|
||||
@scope.projectId = project.id
|
||||
@scope.project = project
|
||||
@scope.pointsList = _.sortBy(project.points, "order")
|
||||
@scope.usStatusList = _.sortBy(project.us_statuses, "order")
|
||||
|
@ -86,22 +90,9 @@ class ProjectProfileController extends mixOf(taiga.Controller, taiga.PageMixin)
|
|||
@scope.$emit('project:loaded', project)
|
||||
return project
|
||||
|
||||
loadTagsColors: ->
|
||||
return @rs.projects.tagsColors(@scope.projectId).then (tags_colors) =>
|
||||
@scope.project.tags_colors = tags_colors
|
||||
|
||||
loadProjectProfile: ->
|
||||
return @q.all([
|
||||
@.loadProject(),
|
||||
@.loadTagsColors()
|
||||
])
|
||||
|
||||
loadInitialData: ->
|
||||
promise = @repo.resolve({pslug: @params.pslug}).then (data) =>
|
||||
@scope.projectId = data.project
|
||||
return data
|
||||
|
||||
return promise.then(=> @.loadProjectProfile())
|
||||
promise = @.loadProject()
|
||||
return promise
|
||||
|
||||
openDeleteLightbox: ->
|
||||
@rootscope.$broadcast("deletelightbox:new", @scope.project)
|
||||
|
@ -113,8 +104,10 @@ module.controller("ProjectProfileController", ProjectProfileController)
|
|||
## Project Profile Directive
|
||||
#############################################################################
|
||||
|
||||
ProjectProfileDirective = ($repo, $confirm, $loading, $navurls, $location) ->
|
||||
ProjectProfileDirective = ($repo, $confirm, $loading, $navurls, $location, projectService) ->
|
||||
link = ($scope, $el, $attrs) ->
|
||||
$ctrl = $el.controller()
|
||||
|
||||
form = $el.find("form").checksley({"onlyOneErrorElement": true})
|
||||
submit = debounce 2000, (event) =>
|
||||
event.preventDefault()
|
||||
|
@ -127,9 +120,14 @@ ProjectProfileDirective = ($repo, $confirm, $loading, $navurls, $location) ->
|
|||
promise.then ->
|
||||
$loading.finish(submitButton)
|
||||
$confirm.notify("success")
|
||||
newUrl = $navurls.resolve("project-admin-project-profile-details", {project: $scope.project.slug})
|
||||
newUrl = $navurls.resolve("project-admin-project-profile-details", {
|
||||
project: $scope.project.slug
|
||||
})
|
||||
$location.path(newUrl)
|
||||
$scope.$emit("project:loaded", $scope.project)
|
||||
|
||||
$ctrl.loadInitialData()
|
||||
|
||||
projectService.fetchProject()
|
||||
|
||||
promise.then null, (data) ->
|
||||
$loading.finish(submitButton)
|
||||
|
@ -144,7 +142,8 @@ ProjectProfileDirective = ($repo, $confirm, $loading, $navurls, $location) ->
|
|||
return {link:link}
|
||||
|
||||
module.directive("tgProjectProfile", ["$tgRepo", "$tgConfirm", "$tgLoading", "$tgNavUrls", "$tgLocation",
|
||||
ProjectProfileDirective])
|
||||
"tgProjectService", ProjectProfileDirective])
|
||||
|
||||
|
||||
#############################################################################
|
||||
## Project Default Values Directive
|
||||
|
@ -187,7 +186,7 @@ module.directive("tgProjectDefaultValues", ["$tgRepo", "$tgConfirm", "$tgLoading
|
|||
## Project Modules Directive
|
||||
#############################################################################
|
||||
|
||||
ProjectModulesDirective = ($repo, $confirm, $loading) ->
|
||||
ProjectModulesDirective = ($repo, $confirm, $loading, projectService) ->
|
||||
link = ($scope, $el, $attrs) ->
|
||||
form = $el.find("form").checksley()
|
||||
submit = =>
|
||||
|
@ -201,6 +200,8 @@ ProjectModulesDirective = ($repo, $confirm, $loading) ->
|
|||
$confirm.notify("success")
|
||||
$scope.$emit("project:loaded", $scope.project)
|
||||
|
||||
projectService.fetchProject()
|
||||
|
||||
promise.then null, (data) ->
|
||||
$loading.finish(target)
|
||||
$confirm.notify("error", data._error_message)
|
||||
|
@ -229,7 +230,8 @@ ProjectModulesDirective = ($repo, $confirm, $loading) ->
|
|||
|
||||
return {link:link}
|
||||
|
||||
module.directive("tgProjectModules", ["$tgRepo", "$tgConfirm", "$tgLoading", ProjectModulesDirective])
|
||||
module.directive("tgProjectModules", ["$tgRepo", "$tgConfirm", "$tgLoading", "tgProjectService",
|
||||
ProjectModulesDirective])
|
||||
|
||||
|
||||
#############################################################################
|
||||
|
|
|
@ -46,11 +46,12 @@ class ProjectValuesSectionController extends mixOf(taiga.Controller, taiga.PageM
|
|||
"$q",
|
||||
"$tgLocation",
|
||||
"$tgNavUrls",
|
||||
"$appTitle",
|
||||
"tgAppMetaService",
|
||||
"$translate"
|
||||
]
|
||||
|
||||
constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, @navUrls, @appTitle, @translate) ->
|
||||
constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, @navUrls,
|
||||
@appMetaService, @translate) ->
|
||||
@scope.project = {}
|
||||
|
||||
promise = @.loadInitialData()
|
||||
|
@ -58,30 +59,28 @@ class ProjectValuesSectionController extends mixOf(taiga.Controller, taiga.PageM
|
|||
promise.then () =>
|
||||
sectionName = @translate.instant(@scope.sectionName)
|
||||
|
||||
title = @translate.instant("ADMIN.PROJECT_VALUES.APP_TITLE", {
|
||||
title = @translate.instant("ADMIN.PROJECT_VALUES.PAGE_TITLE", {
|
||||
"sectionName": sectionName,
|
||||
"projectName": @scope.project.name
|
||||
})
|
||||
|
||||
@appTitle.set(title)
|
||||
description = @scope.project.description
|
||||
@appMetaService.setAll(title, description)
|
||||
|
||||
promise.then null, @.onInitialDataError.bind(@)
|
||||
|
||||
loadProject: ->
|
||||
return @rs.projects.get(@scope.projectId).then (project) =>
|
||||
return @rs.projects.getBySlug(@params.pslug).then (project) =>
|
||||
if not project.i_am_owner
|
||||
@location.path(@navUrls.resolve("permission-denied"))
|
||||
|
||||
@scope.projectId = project.id
|
||||
@scope.project = project
|
||||
@scope.$emit('project:loaded', project)
|
||||
return project
|
||||
|
||||
loadInitialData: ->
|
||||
promise = @repo.resolve({pslug: @params.pslug}).then (data) =>
|
||||
@scope.projectId = data.project
|
||||
return data
|
||||
|
||||
return promise.then => @.loadProject()
|
||||
promise = @.loadProject()
|
||||
return promise
|
||||
|
||||
|
||||
module.controller("ProjectValuesSectionController", ProjectValuesSectionController)
|
||||
|
@ -126,7 +125,7 @@ module.controller("ProjectValuesController", ProjectValuesController)
|
|||
## Project values directive
|
||||
#############################################################################
|
||||
|
||||
ProjectValuesDirective = ($log, $repo, $confirm, $location, animationFrame, @translate, $rootscope) ->
|
||||
ProjectValuesDirective = ($log, $repo, $confirm, $location, animationFrame, $translate, $rootscope) ->
|
||||
## Drag & Drop Link
|
||||
|
||||
linkDragAndDrop = ($scope, $el, $attrs) ->
|
||||
|
@ -167,7 +166,7 @@ ProjectValuesDirective = ($log, $repo, $confirm, $location, animationFrame, @tra
|
|||
}
|
||||
|
||||
initializeTextTranslations = ->
|
||||
$scope.addNewElementText = @translate.instant("ADMIN.PROJECT_VALUES_#{objName.toUpperCase()}.ACTION_ADD")
|
||||
$scope.addNewElementText = $translate.instant("ADMIN.PROJECT_VALUES_#{objName.toUpperCase()}.ACTION_ADD")
|
||||
|
||||
initializeNewValue()
|
||||
initializeTextTranslations()
|
||||
|
@ -296,7 +295,10 @@ ProjectValuesDirective = ($log, $repo, $confirm, $location, animationFrame, @tra
|
|||
if _.keys(choices).length == 0
|
||||
return $confirm.error("ADMIN.PROJECT_VALUES.ERROR_DELETE_ALL")
|
||||
|
||||
$confirm.askChoice("PROJECT.TITLE_ACTION_DELETE_VALUE", subtitle, choices, "ADMIN.PROJECT_VALUES.REPLACEMENT").then (response) ->
|
||||
title = $translate.instant("ADMIN.COMMON.TITLE_ACTION_DELETE_VALUE")
|
||||
text = $translate.instant("ADMIN.PROJECT_VALUES.REPLACEMENT")
|
||||
|
||||
$confirm.askChoice(title, subtitle, choices, text).then (response) ->
|
||||
onSucces = ->
|
||||
$ctrl.loadValues().finally ->
|
||||
response.finish()
|
||||
|
@ -382,15 +384,24 @@ class ProjectCustomAttributesController extends mixOf(taiga.Controller, taiga.Pa
|
|||
"$q",
|
||||
"$tgLocation",
|
||||
"$tgNavUrls",
|
||||
"$appTitle",
|
||||
"tgAppMetaService",
|
||||
"$translate"
|
||||
]
|
||||
|
||||
constructor: (@scope, @rootscope, @repo, @rs, @params, @q, @location, @navUrls, @appTitle) ->
|
||||
constructor: (@scope, @rootscope, @repo, @rs, @params, @q, @location, @navUrls, @appMetaService,
|
||||
@translate) ->
|
||||
@scope.project = {}
|
||||
|
||||
@rootscope.$on "project:loaded", =>
|
||||
@.loadCustomAttributes()
|
||||
@appTitle.set("Project Custom Attributes - " + @scope.sectionName + " - " + @scope.project.name)
|
||||
|
||||
sectionName = @translate.instant(@scope.sectionName)
|
||||
title = @translate.instant("ADMIN.CUSTOM_ATTRIBUTES.PAGE_TITLE", {
|
||||
"sectionName": sectionName,
|
||||
"projectName": @scope.project.name
|
||||
})
|
||||
description = @scope.project.description
|
||||
@appMetaService.setAll(title, description)
|
||||
|
||||
#########################
|
||||
# Custom Attribute
|
||||
|
@ -430,7 +441,7 @@ module.controller("ProjectCustomAttributesController", ProjectCustomAttributesCo
|
|||
## Custom Attributes Directive
|
||||
#############################################################################
|
||||
|
||||
ProjectCustomAttributesDirective = ($log, $confirm, animationFrame) ->
|
||||
ProjectCustomAttributesDirective = ($log, $confirm, animationFrame, $translate) ->
|
||||
link = ($scope, $el, $attrs) ->
|
||||
$ctrl = $el.controller()
|
||||
|
||||
|
@ -616,7 +627,10 @@ ProjectCustomAttributesDirective = ($log, $confirm, animationFrame) ->
|
|||
attr = formEl.scope().attr
|
||||
message = attr.name
|
||||
|
||||
$confirm.ask("COMMON.CUSTOM_ATTRIBUTES.DELETE", "COMMON.CUSTOM_ATTRIBUTES.CONFIRM_DELETE", message).then (finish) ->
|
||||
title = $translate.instant("COMMON.CUSTOM_ATTRIBUTES.DELETE")
|
||||
text = $translate.instant("COMMON.CUSTOM_ATTRIBUTES.CONFIRM_DELETE")
|
||||
|
||||
$confirm.ask(title, text, message).then (finish) ->
|
||||
onSucces = ->
|
||||
$ctrl.loadCustomAttributes().finally ->
|
||||
finish()
|
||||
|
@ -636,4 +650,5 @@ ProjectCustomAttributesDirective = ($log, $confirm, animationFrame) ->
|
|||
|
||||
return {link: link}
|
||||
|
||||
module.directive("tgProjectCustomAttributes", ["$log", "$tgConfirm", "animationFrame", ProjectCustomAttributesDirective])
|
||||
module.directive("tgProjectCustomAttributes", ["$log", "$tgConfirm", "animationFrame", "$translate",
|
||||
ProjectCustomAttributesDirective])
|
||||
|
|
|
@ -44,12 +44,12 @@ class RolesController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fil
|
|||
"$q",
|
||||
"$tgLocation",
|
||||
"$tgNavUrls",
|
||||
"$appTitle",
|
||||
"tgAppMetaService",
|
||||
"$translate"
|
||||
]
|
||||
|
||||
constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, @navUrls, @appTitle,
|
||||
@translate) ->
|
||||
constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, @navUrls,
|
||||
@appMetaService, @translate) ->
|
||||
bindMethods(@)
|
||||
|
||||
@scope.sectionName = "ADMIN.MENU.PERMISSIONS"
|
||||
|
@ -59,16 +59,18 @@ class RolesController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fil
|
|||
promise = @.loadInitialData()
|
||||
|
||||
promise.then () =>
|
||||
title = @translate.instant("ADMIN.ROLES.SECTION_NAME", {projectName: @scope.project.name})
|
||||
@appTitle.set(title)
|
||||
title = @translate.instant("ADMIN.ROLES.PAGE_TITLE", {projectName: @scope.project.name})
|
||||
description = @scope.project.description
|
||||
@appMetaService.setAll(title, description)
|
||||
|
||||
promise.then null, @.onInitialDataError.bind(@)
|
||||
|
||||
loadProject: ->
|
||||
return @rs.projects.get(@scope.projectId).then (project) =>
|
||||
return @rs.projects.getBySlug(@params.pslug).then (project) =>
|
||||
if not project.i_am_owner
|
||||
@location.path(@navUrls.resolve("permission-denied"))
|
||||
|
||||
@scope.projectId = project.id
|
||||
@scope.project = project
|
||||
|
||||
@scope.$emit('project:loaded', project)
|
||||
|
@ -76,39 +78,29 @@ class RolesController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fil
|
|||
|
||||
return project
|
||||
|
||||
loadExternalUserRole: (roles) ->
|
||||
roles = roles.map (role) ->
|
||||
role.external_user = false
|
||||
|
||||
return role
|
||||
|
||||
public_permission = {
|
||||
"name": @translate.instant("ADMIN.ROLES.EXTERNAL_USER"),
|
||||
"permissions": @scope.project.public_permissions,
|
||||
"external_user": true
|
||||
}
|
||||
|
||||
roles.push(public_permission)
|
||||
|
||||
return roles
|
||||
|
||||
loadRoles: ->
|
||||
return @rs.roles.list(@scope.projectId)
|
||||
.then @loadExternalUserRole
|
||||
.then (roles) =>
|
||||
@scope.roles = roles
|
||||
@scope.role = @scope.roles[0]
|
||||
return @rs.roles.list(@scope.projectId).then (roles) =>
|
||||
roles = roles.map (role) ->
|
||||
role.external_user = false
|
||||
|
||||
return roles
|
||||
return role
|
||||
|
||||
public_permission = {
|
||||
"name": @translate.instant("ADMIN.ROLES.EXTERNAL_USER"),
|
||||
"permissions": @scope.project.public_permissions,
|
||||
"external_user": true
|
||||
}
|
||||
|
||||
roles.push(public_permission)
|
||||
|
||||
@scope.roles = roles
|
||||
@scope.role = @scope.roles[0]
|
||||
return roles
|
||||
|
||||
loadInitialData: ->
|
||||
promise = @repo.resolve({pslug: @params.pslug}).then (data) =>
|
||||
@scope.projectId = data.project
|
||||
return data
|
||||
|
||||
return promise.then(=> @.loadProject())
|
||||
.then(=> @.loadUsersAndRoles())
|
||||
.then(=> @.loadRoles())
|
||||
promise = @.loadProject()
|
||||
promise.then(=> @.loadRoles())
|
||||
return promise
|
||||
|
||||
setRole: (role) ->
|
||||
@scope.role = role
|
||||
|
@ -236,7 +228,8 @@ NewRoleDirective = ($tgrepo, $confirm) ->
|
|||
$el.find(".new").val('')
|
||||
|
||||
onSuccess = (role) ->
|
||||
$scope.roles.push(role)
|
||||
insertPosition = $scope.roles.length - 1
|
||||
$scope.roles.splice(insertPosition, 0, role)
|
||||
$ctrl.setRole(role)
|
||||
$el.find(".add-button").show()
|
||||
$ctrl.loadProject()
|
||||
|
|
|
@ -28,6 +28,7 @@ timeout = @.taiga.timeout
|
|||
|
||||
module = angular.module("taigaAdmin")
|
||||
|
||||
|
||||
#############################################################################
|
||||
## Webhooks
|
||||
#############################################################################
|
||||
|
@ -40,11 +41,11 @@ class WebhooksController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.
|
|||
"$routeParams",
|
||||
"$tgLocation",
|
||||
"$tgNavUrls",
|
||||
"$appTitle",
|
||||
"tgAppMetaService",
|
||||
"$translate"
|
||||
]
|
||||
|
||||
constructor: (@scope, @repo, @rs, @params, @location, @navUrls, @appTitle, @translate) ->
|
||||
constructor: (@scope, @repo, @rs, @params, @location, @navUrls, @appMetaService, @translate) ->
|
||||
bindMethods(@)
|
||||
|
||||
@scope.sectionName = "ADMIN.WEBHOOKS.SECTION_NAME"
|
||||
|
@ -53,8 +54,9 @@ class WebhooksController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.
|
|||
promise = @.loadInitialData()
|
||||
|
||||
promise.then () =>
|
||||
text = @translate.instant("ADMIN.WEBHOOKS.APP_TITLE", {"projectName": @scope.project.name})
|
||||
@appTitle.set(text)
|
||||
title = @translate.instant("ADMIN.WEBHOOKS.PAGE_TITLE", {projectName: @scope.project.name})
|
||||
description = @scope.project.description
|
||||
@appMetaService.setAll(title, description)
|
||||
|
||||
promise.then null, @.onInitialDataError.bind(@)
|
||||
|
||||
|
@ -65,24 +67,25 @@ class WebhooksController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.
|
|||
@scope.webhooks = webhooks
|
||||
|
||||
loadProject: ->
|
||||
return @rs.projects.get(@scope.projectId).then (project) =>
|
||||
return @rs.projects.getBySlug(@params.pslug).then (project) =>
|
||||
if not project.i_am_owner
|
||||
@location.path(@navUrls.resolve("permission-denied"))
|
||||
|
||||
@scope.projectId = project.id
|
||||
@scope.project = project
|
||||
@scope.$emit('project:loaded', project)
|
||||
return project
|
||||
|
||||
loadInitialData: ->
|
||||
promise = @repo.resolve({pslug: @params.pslug}).then (data) =>
|
||||
@scope.projectId = data.project
|
||||
return data
|
||||
promise = @.loadProject()
|
||||
promise.then =>
|
||||
@.loadWebhooks()
|
||||
|
||||
return promise.then(=> @.loadProject())
|
||||
.then(=> @.loadWebhooks())
|
||||
return promise
|
||||
|
||||
module.controller("WebhooksController", WebhooksController)
|
||||
|
||||
|
||||
#############################################################################
|
||||
## Webhook Directive
|
||||
#############################################################################
|
||||
|
@ -213,7 +216,8 @@ WebhookDirective = ($rs, $repo, $confirm, $loading, $translate) ->
|
|||
|
||||
return {link:link}
|
||||
|
||||
module.directive("tgWebhook", ["$tgResources", "$tgRepo", "$tgConfirm", "$tgLoading", "$translate", WebhookDirective])
|
||||
module.directive("tgWebhook", ["$tgResources", "$tgRepo", "$tgConfirm", "$tgLoading", "$translate",
|
||||
WebhookDirective])
|
||||
|
||||
|
||||
#############################################################################
|
||||
|
@ -289,11 +293,11 @@ class GithubController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi
|
|||
"$tgRepo",
|
||||
"$tgResources",
|
||||
"$routeParams",
|
||||
"$appTitle",
|
||||
"tgAppMetaService",
|
||||
"$translate"
|
||||
]
|
||||
|
||||
constructor: (@scope, @repo, @rs, @params, @appTitle, @translate) ->
|
||||
constructor: (@scope, @repo, @rs, @params, @appMetaService, @translate) ->
|
||||
bindMethods(@)
|
||||
|
||||
@scope.sectionName = @translate.instant("ADMIN.GITHUB.SECTION_NAME")
|
||||
|
@ -302,8 +306,9 @@ class GithubController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi
|
|||
promise = @.loadInitialData()
|
||||
|
||||
promise.then () =>
|
||||
title = @translate.instant("ADMIN.GITHUB.APP_TITLE", {projectName: @scope.project.name})
|
||||
@appTitle.set(title)
|
||||
title = @translate.instant("ADMIN.GITHUB.PAGE_TITLE", {projectName: @scope.project.name})
|
||||
description = @scope.project.description
|
||||
@appMetaService.setAll(title, description)
|
||||
|
||||
promise.then null, @.onInitialDataError.bind(@)
|
||||
|
||||
|
@ -312,19 +317,16 @@ class GithubController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi
|
|||
@scope.github = github
|
||||
|
||||
loadProject: ->
|
||||
return @rs.projects.get(@scope.projectId).then (project) =>
|
||||
return @rs.projects.getBySlug(@params.pslug).then (project) =>
|
||||
@scope.projectId = project.id
|
||||
@scope.project = project
|
||||
@scope.$emit('project:loaded', project)
|
||||
return project
|
||||
|
||||
loadInitialData: ->
|
||||
promise = @repo.resolve({pslug: @params.pslug}).then (data) =>
|
||||
@scope.projectId = data.project
|
||||
return data
|
||||
|
||||
return promise.then(=> @.loadProject())
|
||||
.then(=> @.loadModules())
|
||||
|
||||
promise = @.loadProject()
|
||||
promise.then(=> @.loadModules())
|
||||
return promise
|
||||
|
||||
module.controller("GithubController", GithubController)
|
||||
|
||||
|
@ -339,11 +341,11 @@ class GitlabController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi
|
|||
"$tgRepo",
|
||||
"$tgResources",
|
||||
"$routeParams",
|
||||
"$appTitle",
|
||||
"tgAppMetaService",
|
||||
"$translate"
|
||||
]
|
||||
|
||||
constructor: (@scope, @repo, @rs, @params, @appTitle, @translate) ->
|
||||
constructor: (@scope, @repo, @rs, @params, @appMetaService, @translate) ->
|
||||
bindMethods(@)
|
||||
|
||||
@scope.sectionName = @translate.instant("ADMIN.GITLAB.SECTION_NAME")
|
||||
|
@ -351,8 +353,9 @@ class GitlabController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi
|
|||
promise = @.loadInitialData()
|
||||
|
||||
promise.then () =>
|
||||
title = @translate.instant("ADMIN.GITLAB.APP_TITLE", {projectName: @scope.project.name})
|
||||
@appTitle.set(title)
|
||||
title = @translate.instant("ADMIN.GITLAB.PAGE_TITLE", {projectName: @scope.project.name})
|
||||
description = @scope.project.description
|
||||
@appMetaService.setAll(title, description)
|
||||
|
||||
promise.then null, @.onInitialDataError.bind(@)
|
||||
|
||||
|
@ -364,19 +367,16 @@ class GitlabController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi
|
|||
@scope.gitlab = gitlab
|
||||
|
||||
loadProject: ->
|
||||
return @rs.projects.get(@scope.projectId).then (project) =>
|
||||
return @rs.projects.getBySlug(@params.pslug).then (project) =>
|
||||
@scope.projectId = project.id
|
||||
@scope.project = project
|
||||
@scope.$emit('project:loaded', project)
|
||||
return project
|
||||
|
||||
loadInitialData: ->
|
||||
promise = @repo.resolve({pslug: @params.pslug}).then (data) =>
|
||||
@scope.projectId = data.project
|
||||
return data
|
||||
|
||||
return promise.then(=> @.loadProject())
|
||||
.then(=> @.loadModules())
|
||||
|
||||
promise = @.loadProject()
|
||||
promise.then(=> @.loadModules())
|
||||
return promise
|
||||
|
||||
module.controller("GitlabController", GitlabController)
|
||||
|
||||
|
@ -391,11 +391,11 @@ class BitbucketController extends mixOf(taiga.Controller, taiga.PageMixin, taiga
|
|||
"$tgRepo",
|
||||
"$tgResources",
|
||||
"$routeParams",
|
||||
"$appTitle",
|
||||
"tgAppMetaService",
|
||||
"$translate"
|
||||
]
|
||||
|
||||
constructor: (@scope, @repo, @rs, @params, @appTitle, @translate) ->
|
||||
constructor: (@scope, @repo, @rs, @params, @appMetaService, @translate) ->
|
||||
bindMethods(@)
|
||||
|
||||
@scope.sectionName = @translate.instant("ADMIN.BITBUCKET.SECTION_NAME")
|
||||
|
@ -403,8 +403,9 @@ class BitbucketController extends mixOf(taiga.Controller, taiga.PageMixin, taiga
|
|||
promise = @.loadInitialData()
|
||||
|
||||
promise.then () =>
|
||||
title = @translate.instant("ADMIN.BITBUCKET.APP_TITLE", {projectName: @scope.project.name})
|
||||
@appTitle.set(title)
|
||||
title = @translate.instant("ADMIN.BITBUCKET.PAGE_TITLE", {projectName: @scope.project.name})
|
||||
description = @scope.project.description
|
||||
@appMetaService.setAll(title, description)
|
||||
|
||||
promise.then null, @.onInitialDataError.bind(@)
|
||||
|
||||
|
@ -416,18 +417,16 @@ class BitbucketController extends mixOf(taiga.Controller, taiga.PageMixin, taiga
|
|||
@scope.bitbucket = bitbucket
|
||||
|
||||
loadProject: ->
|
||||
return @rs.projects.get(@scope.projectId).then (project) =>
|
||||
return @rs.projects.getBySlug(@params.pslug).then (project) =>
|
||||
@scope.projectId = project.id
|
||||
@scope.project = project
|
||||
@scope.$emit('project:loaded', project)
|
||||
return project
|
||||
|
||||
loadInitialData: ->
|
||||
promise = @repo.resolve({pslug: @params.pslug}).then (data) =>
|
||||
@scope.projectId = data.project
|
||||
return data
|
||||
|
||||
return promise.then(=> @.loadProject())
|
||||
.then(=> @.loadModules())
|
||||
promise = @.loadProject()
|
||||
promise.then(=> @.loadModules())
|
||||
return promise
|
||||
|
||||
module.controller("BitbucketController", BitbucketController)
|
||||
|
||||
|
@ -552,12 +551,12 @@ module.directive("tgBitbucketWebhooks", ["$tgRepo", "$tgConfirm", "$tgLoading",
|
|||
#############################################################################
|
||||
ValidOriginIpsDirective = ->
|
||||
link = ($scope, $el, $attrs, $ngModel) ->
|
||||
$ngModel.$parsers.push (value) ->
|
||||
value = $.trim(value)
|
||||
if value == ""
|
||||
return []
|
||||
$ngModel.$parsers.push (value) ->
|
||||
value = $.trim(value)
|
||||
if value == ""
|
||||
return []
|
||||
|
||||
return value.split(",")
|
||||
return value.split(",")
|
||||
|
||||
return {
|
||||
link: link
|
||||
|
|
|
@ -36,14 +36,26 @@ class AuthService extends taiga.Service
|
|||
"$tgHttp",
|
||||
"$tgUrls",
|
||||
"$tgConfig",
|
||||
"$translate"]
|
||||
"$translate",
|
||||
"tgCurrentUserService"]
|
||||
|
||||
constructor: (@rootscope, @storage, @model, @rs, @http, @urls, @config, @translate) ->
|
||||
constructor: (@rootscope, @storage, @model, @rs, @http, @urls, @config, @translate, @currentUserService) ->
|
||||
super()
|
||||
userModel = @.getUser()
|
||||
@.setUserdata(userModel)
|
||||
|
||||
setUserdata: (userModel) ->
|
||||
if userModel
|
||||
@.userData = Immutable.fromJS(userModel.getAttrs())
|
||||
@currentUserService.setUser(@.userData)
|
||||
else
|
||||
@.userData = null
|
||||
|
||||
|
||||
_setLocales: ->
|
||||
lang = @rootscope.user.lang || @config.get("defaultLanguage") || "en"
|
||||
@translate.use(lang)
|
||||
@translate.preferredLanguage(lang) # Needed for calls to the api in the correct language
|
||||
@translate.use(lang) # Needed for change the interface in runtime
|
||||
|
||||
getUser: ->
|
||||
if @rootscope.user
|
||||
|
@ -63,6 +75,8 @@ class AuthService extends taiga.Service
|
|||
@storage.set("userInfo", user.getAttrs())
|
||||
@rootscope.user = user
|
||||
|
||||
@.setUserdata(user)
|
||||
|
||||
@._setLocales()
|
||||
|
||||
clear: ->
|
||||
|
@ -104,6 +118,8 @@ class AuthService extends taiga.Service
|
|||
@.removeToken()
|
||||
@.clear()
|
||||
|
||||
@currentUserService.removeUser()
|
||||
|
||||
register: (data, type, existing) ->
|
||||
url = @urls.resolve("auth-register")
|
||||
|
||||
|
@ -176,7 +192,8 @@ PublicRegisterMessageDirective = ($config, $navUrls, templates) ->
|
|||
template: templateFn
|
||||
}
|
||||
|
||||
module.directive("tgPublicRegisterMessage", ["$tgConfig", "$tgNavUrls", "$tgTemplate", PublicRegisterMessageDirective])
|
||||
module.directive("tgPublicRegisterMessage", ["$tgConfig", "$tgNavUrls", "$tgTemplate",
|
||||
PublicRegisterMessageDirective])
|
||||
|
||||
|
||||
LoginDirective = ($auth, $confirm, $location, $config, $routeParams, $navUrls, $events, $translate) ->
|
||||
|
@ -212,11 +229,17 @@ LoginDirective = ($auth, $confirm, $location, $config, $routeParams, $navUrls, $
|
|||
|
||||
$el.on "submit", "form", submit
|
||||
|
||||
window.prerenderReady = true
|
||||
|
||||
$scope.$on "$destroy", ->
|
||||
$el.off()
|
||||
|
||||
return {link:link}
|
||||
|
||||
module.directive("tgLogin", ["$tgAuth", "$tgConfirm", "$tgLocation", "$tgConfig", "$routeParams",
|
||||
"$tgNavUrls", "$tgEvents", "$translate", LoginDirective])
|
||||
|
||||
|
||||
#############################################################################
|
||||
## Register Directive
|
||||
#############################################################################
|
||||
|
@ -238,9 +261,9 @@ RegisterDirective = ($auth, $confirm, $location, $navUrls, $config, $analytics,
|
|||
$location.path($navUrls.resolve("home"))
|
||||
|
||||
onErrorSubmit = (response) ->
|
||||
if response.data._error_message?
|
||||
text = $translate.instant("LOGIN_FORM.ERROR_GENERIC") + " " + response.data._error_message
|
||||
$confirm.notify("light-error", text + " " + response.data._error_message)
|
||||
if response.data._error_message
|
||||
text = $translate.instant("COMMON.GENERIC_ERROR", {error: response.data._error_message})
|
||||
$confirm.notify("light-error", text)
|
||||
|
||||
form.setErrors(response.data)
|
||||
|
||||
|
@ -255,11 +278,17 @@ RegisterDirective = ($auth, $confirm, $location, $navUrls, $config, $analytics,
|
|||
|
||||
$el.on "submit", "form", submit
|
||||
|
||||
$scope.$on "$destroy", ->
|
||||
$el.off()
|
||||
|
||||
window.prerenderReady = true
|
||||
|
||||
return {link:link}
|
||||
|
||||
module.directive("tgRegister", ["$tgAuth", "$tgConfirm", "$tgLocation", "$tgNavUrls", "$tgConfig",
|
||||
"$tgAnalytics", "$translate", RegisterDirective])
|
||||
|
||||
|
||||
#############################################################################
|
||||
## Forgot Password Directive
|
||||
#############################################################################
|
||||
|
@ -291,11 +320,17 @@ ForgotPasswordDirective = ($auth, $confirm, $location, $navUrls, $translate) ->
|
|||
|
||||
$el.on "submit", "form", submit
|
||||
|
||||
$scope.$on "$destroy", ->
|
||||
$el.off()
|
||||
|
||||
window.prerenderReady = true
|
||||
|
||||
return {link:link}
|
||||
|
||||
module.directive("tgForgotPassword", ["$tgAuth", "$tgConfirm", "$tgLocation", "$tgNavUrls", "$translate",
|
||||
ForgotPasswordDirective])
|
||||
|
||||
|
||||
#############################################################################
|
||||
## Change Password from Recovery Directive
|
||||
#############################################################################
|
||||
|
@ -316,12 +351,10 @@ ChangePasswordFromRecoveryDirective = ($auth, $confirm, $location, $params, $nav
|
|||
$location.path($navUrls.resolve("login"))
|
||||
|
||||
text = $translate.instant("CHANGE_PASSWORD_RECOVERY_FORM.SUCCESS")
|
||||
|
||||
$confirm.success(text)
|
||||
|
||||
onErrorSubmit = (response) ->
|
||||
text = $translate.instant("COMMON.GENERIC_ERROR", {error: response.data._error_message})
|
||||
|
||||
$confirm.notify("light-error", text)
|
||||
|
||||
submit = debounce 2000, (event) =>
|
||||
|
@ -335,10 +368,15 @@ ChangePasswordFromRecoveryDirective = ($auth, $confirm, $location, $params, $nav
|
|||
|
||||
$el.on "submit", "form", submit
|
||||
|
||||
$scope.$on "$destroy", ->
|
||||
$el.off()
|
||||
|
||||
return {link:link}
|
||||
|
||||
module.directive("tgChangePasswordFromRecovery", ["$tgAuth", "$tgConfirm", "$tgLocation", "$routeParams",
|
||||
"$tgNavUrls", "$translate", ChangePasswordFromRecoveryDirective])
|
||||
"$tgNavUrls", "$translate",
|
||||
ChangePasswordFromRecoveryDirective])
|
||||
|
||||
|
||||
#############################################################################
|
||||
## Invitation
|
||||
|
@ -365,7 +403,9 @@ InvitationDirective = ($auth, $confirm, $location, $params, $navUrls, $analytics
|
|||
onSuccessSubmitLogin = (response) ->
|
||||
$analytics.trackEvent("auth", "invitationAccept", "invitation accept with existing user", 1)
|
||||
$location.path($navUrls.resolve("project", {project: $scope.invitation.project_slug}))
|
||||
text = $translate.instant("INVITATION_LOGIN_FORM.SUCCESS", {"project_name": $scope.invitation.project_name})
|
||||
text = $translate.instant("INVITATION_LOGIN_FORM.SUCCESS", {
|
||||
"project_name": $scope.invitation.project_name
|
||||
})
|
||||
|
||||
$confirm.notify("success", text)
|
||||
|
||||
|
@ -388,7 +428,7 @@ InvitationDirective = ($auth, $confirm, $location, $params, $navUrls, $analytics
|
|||
|
||||
# Register form
|
||||
$scope.dataRegister = {token: token}
|
||||
registerForm = $el.find("form.register-form").checksley()
|
||||
registerForm = $el.find("form.register-form").checksley({onlyOneErrorElement: true})
|
||||
|
||||
onSuccessSubmitRegister = (response) ->
|
||||
$analytics.trackEvent("auth", "invitationAccept", "invitation accept with new user", 1)
|
||||
|
@ -397,9 +437,11 @@ InvitationDirective = ($auth, $confirm, $location, $params, $navUrls, $analytics
|
|||
"Welcome to #{_.escape($scope.invitation.project_name)}")
|
||||
|
||||
onErrorSubmitRegister = (response) ->
|
||||
text = $translate.instant("LOGIN_FORM.ERROR_AUTH_INCORRECT")
|
||||
if response.data._error_message
|
||||
text = $translate.instant("COMMON.GENERIC_ERROR", {error: response.data._error_message})
|
||||
$confirm.notify("light-error", text)
|
||||
|
||||
$confirm.notify("light-error", text)
|
||||
registerForm.setErrors(response.data)
|
||||
|
||||
submitRegister = debounce 2000, (event) =>
|
||||
event.preventDefault()
|
||||
|
@ -413,11 +455,15 @@ InvitationDirective = ($auth, $confirm, $location, $params, $navUrls, $analytics
|
|||
$el.on "submit", "form.register-form", submitRegister
|
||||
$el.on "click", ".button-register", submitRegister
|
||||
|
||||
$scope.$on "$destroy", ->
|
||||
$el.off()
|
||||
|
||||
return {link:link}
|
||||
|
||||
module.directive("tgInvitation", ["$tgAuth", "$tgConfirm", "$tgLocation", "$routeParams",
|
||||
"$tgNavUrls", "$tgAnalytics", "$translate", InvitationDirective])
|
||||
|
||||
|
||||
#############################################################################
|
||||
## Change Email
|
||||
#############################################################################
|
||||
|
@ -429,12 +475,15 @@ ChangeEmailDirective = ($repo, $model, $auth, $confirm, $location, $params, $nav
|
|||
form = $el.find("form").checksley()
|
||||
|
||||
onSuccessSubmit = (response) ->
|
||||
$repo.queryOne("users", $auth.getUser().id).then (data) =>
|
||||
$auth.setUser(data)
|
||||
$location.path($navUrls.resolve("home"))
|
||||
if $auth.isAuthenticated()
|
||||
$repo.queryOne("users", $auth.getUser().id).then (data) =>
|
||||
$auth.setUser(data)
|
||||
$location.path($navUrls.resolve("home"))
|
||||
else
|
||||
$location.path($navUrls.resolve("login"))
|
||||
|
||||
text = $translate.instant("CHANGE_EMAIL_FORM.SUCCESS")
|
||||
$confirm.success(text)
|
||||
text = $translate.instant("CHANGE_EMAIL_FORM.SUCCESS")
|
||||
$confirm.success(text)
|
||||
|
||||
onErrorSubmit = (response) ->
|
||||
text = $translate.instant("COMMON.GENERIC_ERROR", {error: response.data._error_message})
|
||||
|
@ -456,10 +505,14 @@ ChangeEmailDirective = ($repo, $model, $auth, $confirm, $location, $params, $nav
|
|||
event.preventDefault()
|
||||
submit()
|
||||
|
||||
$scope.$on "$destroy", ->
|
||||
$el.off()
|
||||
|
||||
return {link:link}
|
||||
|
||||
module.directive("tgChangeEmail", ["$tgRepo", "$tgModel", "$tgAuth", "$tgConfirm", "$tgLocation", "$routeParams",
|
||||
"$tgNavUrls", "$translate", ChangeEmailDirective])
|
||||
module.directive("tgChangeEmail", ["$tgRepo", "$tgModel", "$tgAuth", "$tgConfirm", "$tgLocation",
|
||||
"$routeParams", "$tgNavUrls", "$translate", ChangeEmailDirective])
|
||||
|
||||
|
||||
#############################################################################
|
||||
## Cancel account
|
||||
|
@ -495,7 +548,10 @@ CancelAccountDirective = ($repo, $model, $auth, $confirm, $location, $params, $n
|
|||
|
||||
$el.on "submit", "form", submit
|
||||
|
||||
$scope.$on "$destroy", ->
|
||||
$el.off()
|
||||
|
||||
return {link:link}
|
||||
|
||||
module.directive("tgCancelAccount", ["$tgRepo", "$tgModel", "$tgAuth", "$tgConfirm", "$tgLocation", "$routeParams",
|
||||
"$tgNavUrls", CancelAccountDirective])
|
||||
module.directive("tgCancelAccount", ["$tgRepo", "$tgModel", "$tgAuth", "$tgConfirm", "$tgLocation",
|
||||
"$routeParams","$tgNavUrls", CancelAccountDirective])
|
||||
|
|
|
@ -45,16 +45,15 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F
|
|||
"$routeParams",
|
||||
"$q",
|
||||
"$tgLocation",
|
||||
"$appTitle",
|
||||
"tgAppMetaService",
|
||||
"$tgNavUrls",
|
||||
"$tgEvents",
|
||||
"$tgAnalytics",
|
||||
"tgLoader",
|
||||
"$translate"
|
||||
]
|
||||
|
||||
constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q,
|
||||
@location, @appTitle, @navUrls, @events, @analytics, tgLoader, @translate) ->
|
||||
@location, @appMetaService, @navUrls, @events, @analytics, @translate) ->
|
||||
bindMethods(@)
|
||||
|
||||
@scope.sectionName = @translate.instant("BACKLOG.SECTION_NAME")
|
||||
|
@ -67,7 +66,12 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F
|
|||
|
||||
# On Success
|
||||
promise.then =>
|
||||
@appTitle.set("Backlog - " + @scope.project.name)
|
||||
title = @translate.instant("BACKLOG.PAGE_TITLE", {projectName: @scope.project.name})
|
||||
description = @translate.instant("BACKLOG.PAGE_DESCRIPTION", {
|
||||
projectName: @scope.project.name,
|
||||
projectDescription: @scope.project.description
|
||||
})
|
||||
@appMetaService.setAll(title, description)
|
||||
|
||||
if @rs.userstories.getShowTags(@scope.projectId)
|
||||
@showTags = true
|
||||
|
@ -77,9 +81,6 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F
|
|||
# On Error
|
||||
promise.then null, @.onInitialDataError.bind(@)
|
||||
|
||||
# Finally
|
||||
promise.finally tgLoader.pageLoaded
|
||||
|
||||
initializeEventHandlers: ->
|
||||
@scope.$on "usform:bulk:success", =>
|
||||
@.loadUserstories()
|
||||
|
@ -607,9 +608,11 @@ BacklogDirective = ($repo, $rootscope, $translate) ->
|
|||
$ctrl.loadProjectStats()
|
||||
|
||||
|
||||
# Enable move to current sprint only when there are selected us's
|
||||
$el.on "change", ".backlog-table-body .user-stories input:checkbox", (event) ->
|
||||
target = angular.element(event.currentTarget)
|
||||
shiftPressed = false
|
||||
lastChecked = null
|
||||
|
||||
checkSelected = (target) ->
|
||||
lastChecked = target.closest(".us-item-row")
|
||||
moveToCurrentSprintDom = $el.find("#move-to-current-sprint")
|
||||
selectedUsDom = $el.find(".backlog-table-body .user-stories input:checkbox:checked")
|
||||
|
||||
|
@ -620,6 +623,33 @@ BacklogDirective = ($repo, $rootscope, $translate) ->
|
|||
|
||||
target.closest('.us-item-row').toggleClass('ui-multisortable-multiple')
|
||||
|
||||
$(window).on "keydown.shift-pressed keyup.shift-pressed", (event) ->
|
||||
shiftPressed = !!event.shiftKey
|
||||
|
||||
return true
|
||||
|
||||
# Enable move to current sprint only when there are selected us's
|
||||
$el.on "change", ".backlog-table-body .user-stories input:checkbox", (event) ->
|
||||
# check elements between the last two if shift is pressed
|
||||
if lastChecked && shiftPressed
|
||||
elements = []
|
||||
current = $(event.currentTarget).closest(".us-item-row")
|
||||
nextAll = lastChecked.nextAll()
|
||||
prevAll = lastChecked.prevAll()
|
||||
|
||||
if _.some(nextAll, (next) -> next == current[0])
|
||||
elements = lastChecked.nextUntil(current)
|
||||
else if _.some(prevAll, (prev) -> prev == current[0])
|
||||
elements = lastChecked.prevUntil(current)
|
||||
|
||||
_.map elements, (elm) ->
|
||||
input = $(elm).find("input:checkbox")
|
||||
input.prop('checked', true);
|
||||
checkSelected(input)
|
||||
|
||||
target = angular.element(event.currentTarget)
|
||||
checkSelected(target)
|
||||
|
||||
$el.on "click", "#move-to-current-sprint", (event) =>
|
||||
# Calculating the us's to be modified
|
||||
ussDom = $el.find(".backlog-table-body .user-stories input:checkbox:checked")
|
||||
|
@ -705,6 +735,7 @@ BacklogDirective = ($repo, $rootscope, $translate) ->
|
|||
|
||||
$scope.$on "$destroy", ->
|
||||
$el.off()
|
||||
$(window).off(".shift-pressed")
|
||||
|
||||
return {link: link}
|
||||
|
||||
|
|
|
@ -61,10 +61,10 @@ BacklogSortableDirective = ($repo, $rs, $rootscope, $tgConfirm, $translate) ->
|
|||
items: ".us-item-row",
|
||||
cancel: ".popover"
|
||||
connectWith: ".sprint"
|
||||
containment: ".wrapper"
|
||||
dropOnEmpty: true
|
||||
placeholder: "row us-item-row us-item-drag sortable-placeholder"
|
||||
scroll: true
|
||||
disableHorizontalScroll: true
|
||||
# A consequence of length of backlog user story item
|
||||
# the default tolerance ("intersection") not works properly.
|
||||
tolerance: "pointer"
|
||||
|
@ -73,8 +73,11 @@ BacklogSortableDirective = ($repo, $rs, $rootscope, $tgConfirm, $translate) ->
|
|||
# works unexpectly (in some circumstances calculates wrong
|
||||
# position for revert).
|
||||
revert: false
|
||||
cursorAt: {right: 15}
|
||||
start: () ->
|
||||
$(document.body).addClass("drag-active")
|
||||
stop: () ->
|
||||
$(document.body).removeClass("drag-active")
|
||||
|
||||
if $el.hasClass("active-filters")
|
||||
$el.sortable("cancel")
|
||||
filterError()
|
||||
|
@ -167,8 +170,11 @@ SprintSortableDirective = ($repo, $rs, $rootscope) ->
|
|||
$el.sortable({
|
||||
scroll: true
|
||||
dropOnEmpty: true
|
||||
items: ".sprint-table .milestone-us-item-row",
|
||||
items: ".sprint-table .milestone-us-item-row"
|
||||
disableHorizontalScroll: true
|
||||
connectWith: ".sprint,.backlog-table-body,.empty-backlog"
|
||||
placeholder: "row us-item-row sortable-placeholder"
|
||||
forcePlaceholderSize:true
|
||||
})
|
||||
|
||||
$el.on "multiplesortreceive", (event, ui) ->
|
||||
|
|
|
@ -44,6 +44,7 @@ module.directive("tgMain", ["$rootScope", "$window", TaigaMainDirective])
|
|||
|
||||
urls = {
|
||||
"home": "/"
|
||||
"projects": "/projects"
|
||||
"error": "/error"
|
||||
"not-found": "/not-found"
|
||||
"permission-denied": "/permission-denied"
|
||||
|
@ -57,7 +58,8 @@ urls = {
|
|||
"invitation": "/invitation/:token"
|
||||
"create-project": "/create-project"
|
||||
|
||||
"profile": "/:user"
|
||||
"profile": "/profile"
|
||||
"user-profile": "/profile/:username"
|
||||
|
||||
"project": "/project/:project"
|
||||
"project-backlog": "/project/:project/backlog"
|
||||
|
@ -67,9 +69,7 @@ urls = {
|
|||
"project-search": "/project/:project/search"
|
||||
|
||||
"project-userstories-detail": "/project/:project/us/:ref"
|
||||
|
||||
"project-tasks-detail": "/project/:project/task/:ref"
|
||||
|
||||
"project-issues-detail": "/project/:project/issue/:ref"
|
||||
|
||||
"project-wiki": "/project/:project/wiki"
|
||||
|
@ -102,10 +102,10 @@ urls = {
|
|||
"project-admin-contrib": "/project/:project/admin/contrib/:plugin"
|
||||
|
||||
# User settings
|
||||
"user-settings-user-profile": "/project/:project/user-settings/user-profile"
|
||||
"user-settings-user-change-password": "/project/:project/user-settings/user-change-password"
|
||||
"user-settings-user-avatar": "/project/:project/user-settings/user-avatar"
|
||||
"user-settings-mail-notifications": "/project/:project/user-settings/mail-notifications"
|
||||
"user-settings-user-profile": "/user-settings/user-profile"
|
||||
"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"
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -22,9 +22,16 @@
|
|||
taigaContribPlugins = @.taigaContribPlugins = @.taigaContribPlugins or []
|
||||
|
||||
class ContribController extends taiga.Controller
|
||||
@.$inject = ["$rootScope", "$scope", "$routeParams", "$tgRepo", "$tgResources", "$tgConfirm", "$appTitle"]
|
||||
@.$inject = [
|
||||
"$rootScope",
|
||||
"$scope",
|
||||
"$routeParams",
|
||||
"$tgRepo",
|
||||
"$tgResources",
|
||||
"$tgConfirm"
|
||||
]
|
||||
|
||||
constructor: (@rootScope, @scope, @params, @repo, @rs, @confirm, @appTitle) ->
|
||||
constructor: (@rootScope, @scope, @params, @repo, @rs, @confirm) ->
|
||||
@scope.adminPlugins = _.where(@rootScope.contribPlugins, {"type": "admin"})
|
||||
@scope.currentPlugin = _.first(_.where(@scope.adminPlugins, {"slug": @params.plugin}))
|
||||
@scope.pluginTemplate = "contrib/#{@scope.currentPlugin.slug}"
|
||||
|
@ -32,25 +39,19 @@ class ContribController extends taiga.Controller
|
|||
|
||||
promise = @.loadInitialData()
|
||||
|
||||
promise.then () =>
|
||||
@appTitle.set(@scope.project.name)
|
||||
|
||||
promise.then null, =>
|
||||
@confirm.notify("error")
|
||||
|
||||
loadProject: ->
|
||||
return @rs.projects.get(@scope.projectId).then (project) =>
|
||||
return @rs.projects.getBySlug(@params.pslug).then (project) =>
|
||||
@scope.projectId = project.id
|
||||
@scope.project = project
|
||||
@scope.$emit('project:loaded', project)
|
||||
@scope.$broadcast('project:loaded', project)
|
||||
return project
|
||||
|
||||
loadInitialData: ->
|
||||
promise = @repo.resolve({pslug: @params.pslug}).then (data) =>
|
||||
@scope.projectId = data.project
|
||||
return data
|
||||
|
||||
return promise.then(=> @.loadProject())
|
||||
return @.loadProject()
|
||||
|
||||
module = angular.module("taigaBase")
|
||||
module.controller("ContribController", ContribController)
|
||||
|
|
|
@ -22,9 +22,9 @@
|
|||
taiga = @.taiga
|
||||
|
||||
class HttpService extends taiga.Service
|
||||
@.$inject = ["$http", "$q", "$tgStorage", "$rootScope", "$cacheFactory"]
|
||||
@.$inject = ["$http", "$q", "$tgStorage", "$rootScope", "$cacheFactory", "$translate"]
|
||||
|
||||
constructor: (@http, @q, @storage, @rootScope, @cacheFactory) ->
|
||||
constructor: (@http, @q, @storage, @rootScope, @cacheFactory, @translate) ->
|
||||
super()
|
||||
|
||||
@.cache = @cacheFactory("httpget");
|
||||
|
@ -37,7 +37,7 @@ class HttpService extends taiga.Service
|
|||
headers["Authorization"] = "Bearer #{token}"
|
||||
|
||||
# Accept-Language
|
||||
lang = @rootScope.user?.lang
|
||||
lang = @translate.preferredLanguage()
|
||||
if lang
|
||||
headers["Accept-Language"] = lang
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ locationFactory = ($location, $route, $rootscope) ->
|
|||
return $location
|
||||
|
||||
$location.isInCurrentRouteParams = (name, value) ->
|
||||
params = _.merge($route.current.params, $location.search())
|
||||
params = $location.search() || {}
|
||||
|
||||
return params[name] == value
|
||||
|
||||
|
|
|
@ -111,6 +111,9 @@ NavigationUrlsDirective = ($navurls, $auth, $q, $location) ->
|
|||
target.attr("href", fullUrl)
|
||||
|
||||
$el.on "click", (event) ->
|
||||
if event.metaKey || event.ctrlKey
|
||||
return
|
||||
|
||||
event.preventDefault()
|
||||
target = $(event.currentTarget)
|
||||
|
||||
|
|
|
@ -194,6 +194,21 @@ class RepositoryService extends taiga.Service
|
|||
result.paginatedBy = parseInt(headers["x-paginated-by"], 10)
|
||||
return result
|
||||
|
||||
queryOnePaginatedRaw: (name, id, params, options={}) ->
|
||||
url = @urls.resolve(name)
|
||||
url = "#{url}/#{id}" if id
|
||||
httpOptions = _.merge({headers: {}}, options)
|
||||
|
||||
return @http.get(url, params, httpOptions).then (data) =>
|
||||
headers = data.headers()
|
||||
result = {}
|
||||
result.data = data.data
|
||||
result.count = parseInt(headers["x-pagination-count"], 10)
|
||||
result.current = parseInt(headers["x-pagination-current"] or 1, 10)
|
||||
result.paginatedBy = parseInt(headers["x-paginated-by"], 10)
|
||||
|
||||
return result
|
||||
|
||||
resolve: (options) ->
|
||||
params = {}
|
||||
params.project = options.pslug if options.pslug?
|
||||
|
|
|
@ -138,17 +138,6 @@ ToggleCommentDirective = () ->
|
|||
|
||||
module.directive("tgToggleComment", ToggleCommentDirective)
|
||||
|
||||
#############################################################################
|
||||
## Set the page title
|
||||
#############################################################################
|
||||
|
||||
AppTitle = () ->
|
||||
set = (text) ->
|
||||
$("title").text(text)
|
||||
|
||||
return {set: set}
|
||||
|
||||
module.factory("$appTitle", AppTitle)
|
||||
|
||||
#############################################################################
|
||||
## Get the appropiate section url for a project
|
||||
|
|
|
@ -47,7 +47,7 @@ class AnalyticsService extends taiga.Service
|
|||
@win.ga("require", "displayfeatures")
|
||||
|
||||
if @.trackRoutes and (not @.ignoreFirstPageLoad)
|
||||
@win.ga("send", "pageview", @.getUrl());
|
||||
@win.ga("send", "pageview", @.getUrl())
|
||||
|
||||
# activates page tracking
|
||||
if @.trackRoutes
|
||||
|
|
|
@ -277,6 +277,8 @@ AttachmentDirective = ($template, $compile, $translate) ->
|
|||
if attachment.is_deprecated
|
||||
$el.addClass("deprecated")
|
||||
$el.find("input:checkbox").prop('checked', true)
|
||||
else
|
||||
$el.removeClass("deprecated")
|
||||
|
||||
saveAttachment = ->
|
||||
attachment.description = $el.find("input[name='description']").val()
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
CompileHtmlDirective = ($compile) ->
|
||||
link = (scope, element, attrs) ->
|
||||
scope.$watch attrs.tgCompileHtml, (newValue, oldValue) ->
|
||||
element.html(newValue)
|
||||
$compile(element.contents())(scope)
|
||||
|
||||
return {
|
||||
link: link
|
||||
}
|
||||
|
||||
CompileHtmlDirective.$inject = ["$compile"]
|
||||
|
||||
angular.module("taigaCommon").directive("tgCompileHtml", CompileHtmlDirective)
|
|
@ -220,7 +220,7 @@ WatchersDirective = ($rootscope, $confirm, $repo, $qqueue, $template, $compile,
|
|||
$confirm.notify("success")
|
||||
watchers = _.map(watchers, (watcherId) -> $scope.usersById[watcherId])
|
||||
renderWatchers(watchers)
|
||||
$rootscope.$broadcast("history:reload")
|
||||
$rootscope.$broadcast("object:updated")
|
||||
|
||||
promise.then null, ->
|
||||
$model.$modelValue.revert()
|
||||
|
@ -235,7 +235,7 @@ WatchersDirective = ($rootscope, $confirm, $repo, $qqueue, $template, $compile,
|
|||
$confirm.notify("success")
|
||||
watchers = _.map(item.watchers, (watcherId) -> $scope.usersById[watcherId])
|
||||
renderWatchers(watchers)
|
||||
$rootscope.$broadcast("history:reload")
|
||||
$rootscope.$broadcast("object:updated")
|
||||
promise.then null, ->
|
||||
item.revert()
|
||||
$confirm.notify("error")
|
||||
|
@ -321,7 +321,7 @@ AssignedToDirective = ($rootscope, $confirm, $repo, $loading, $qqueue, $template
|
|||
$loading.finish($el)
|
||||
$confirm.notify("success")
|
||||
renderAssignedTo($model.$modelValue)
|
||||
$rootscope.$broadcast("history:reload")
|
||||
$rootscope.$broadcast("object:updated")
|
||||
promise.then null, ->
|
||||
$model.$modelValue.revert()
|
||||
$confirm.notify("error")
|
||||
|
@ -474,6 +474,10 @@ EditableSubjectDirective = ($rootscope, $repo, $confirm, $loading, $qqueue, $tem
|
|||
|
||||
link = ($scope, $el, $attrs, $model) ->
|
||||
|
||||
$scope.$on "object:updated", () ->
|
||||
$el.find('.edit-subject').hide()
|
||||
$el.find('.view-subject').show()
|
||||
|
||||
isEditable = ->
|
||||
return $scope.project.my_permissions.indexOf($attrs.requiredPerm) != -1
|
||||
|
||||
|
@ -485,7 +489,7 @@ EditableSubjectDirective = ($rootscope, $repo, $confirm, $loading, $qqueue, $tem
|
|||
promise = $repo.save($model.$modelValue)
|
||||
promise.then ->
|
||||
$confirm.notify("success")
|
||||
$rootscope.$broadcast("history:reload")
|
||||
$rootscope.$broadcast("object:updated")
|
||||
$el.find('.edit-subject').hide()
|
||||
$el.find('.view-subject').show()
|
||||
promise.then null, ->
|
||||
|
@ -501,7 +505,9 @@ EditableSubjectDirective = ($rootscope, $repo, $confirm, $loading, $qqueue, $tem
|
|||
$el.find('.view-subject').hide()
|
||||
$el.find('input').focus()
|
||||
|
||||
$el.on "click", ".save", ->
|
||||
$el.on "click", ".save", (e) ->
|
||||
e.preventDefault()
|
||||
|
||||
subject = $scope.item.subject
|
||||
save(subject)
|
||||
|
||||
|
@ -553,6 +559,10 @@ EditableDescriptionDirective = ($rootscope, $repo, $confirm, $compile, $loading,
|
|||
$el.find('.edit-description').hide()
|
||||
$el.find('.view-description .edit').hide()
|
||||
|
||||
$scope.$on "object:updated", () ->
|
||||
$el.find('.edit-description').hide()
|
||||
$el.find('.view-description').show()
|
||||
|
||||
isEditable = ->
|
||||
return $scope.project.my_permissions.indexOf($attrs.requiredPerm) != -1
|
||||
|
||||
|
@ -563,7 +573,7 @@ EditableDescriptionDirective = ($rootscope, $repo, $confirm, $compile, $loading,
|
|||
promise = $repo.save($model.$modelValue)
|
||||
promise.then ->
|
||||
$confirm.notify("success")
|
||||
$rootscope.$broadcast("history:reload")
|
||||
$rootscope.$broadcast("object:updated")
|
||||
$el.find('.edit-description').hide()
|
||||
$el.find('.view-description').show()
|
||||
promise.then null, ->
|
||||
|
@ -782,9 +792,7 @@ module.directive("tgProgressBar", ["$tgTemplate", TgProgressBarDirective])
|
|||
TgMainTitleDirective = ($translate) ->
|
||||
link = ($scope, $el, $attrs) ->
|
||||
$attrs.$observe "i18nSectionName", (i18nSectionName) ->
|
||||
trans = $translate(i18nSectionName)
|
||||
trans.then (sectionName) -> $scope.sectionName = sectionName
|
||||
trans.catch (sectionName) -> $scope.sectionName = sectionName
|
||||
$scope.sectionName = $translate.instant(i18nSectionName)
|
||||
|
||||
$scope.$on "$destroy", ->
|
||||
$el.off()
|
||||
|
|
|
@ -92,7 +92,7 @@ UsEstimationDirective = ($tgEstimationsService, $rootScope, $repo, $confirm, $qq
|
|||
estimationProcess = $tgEstimationsService.create($el, us, $scope.project)
|
||||
estimationProcess.onSelectedPointForRole = (roleId, pointId) ->
|
||||
@save(roleId, pointId).then ->
|
||||
$rootScope.$broadcast("history:reload")
|
||||
$rootScope.$broadcast("object:updated")
|
||||
|
||||
estimationProcess.render = () ->
|
||||
ctx = {
|
||||
|
|
|
@ -276,8 +276,9 @@ HistoryDirective = ($log, $loading, $qqueue, $template, $confirm, $translate, $c
|
|||
deleteCommentUser: comment.delete_comment_user.name
|
||||
deleteComment: comment.comment_html
|
||||
activityId: comment.id
|
||||
canRestoreComment: (comment.delete_comment_user.pk == $scope.user.id or
|
||||
$scope.project.my_permissions.indexOf("modify_project") > -1)
|
||||
canRestoreComment: ($scope.user and
|
||||
(comment.delete_comment_user.pk == $scope.user.id or
|
||||
$scope.project.my_permissions.indexOf("modify_project") > -1))
|
||||
})
|
||||
|
||||
html = $compile(html)($scope)
|
||||
|
@ -371,15 +372,14 @@ HistoryDirective = ($log, $loading, $qqueue, $template, $confirm, $translate, $c
|
|||
$scope.$watch("comments", renderComments)
|
||||
$scope.$watch("history", renderActivity)
|
||||
|
||||
$scope.$on("history:reload", -> $ctrl.loadHistory(type, objectId))
|
||||
$scope.$on("object:updated", -> $ctrl.loadHistory(type, objectId))
|
||||
|
||||
# Events
|
||||
|
||||
$el.on "click", ".add-comment a.button-green", debounce 2000, (event) ->
|
||||
$el.on "click", ".add-comment input.button-green", debounce 2000, (event) ->
|
||||
event.preventDefault()
|
||||
|
||||
target = angular.element(event.currentTarget)
|
||||
|
||||
save(target)
|
||||
|
||||
$el.on "click", ".show-more", (event) ->
|
||||
|
|
|
@ -41,11 +41,12 @@ class LightboxService extends taiga.Service
|
|||
|
||||
$el.css('display', 'flex')
|
||||
|
||||
$el.find('input,textarea').first().focus()
|
||||
|
||||
@animationFrame.add =>
|
||||
$el.addClass("open")
|
||||
|
||||
@animationFrame.add ->
|
||||
$el.find('input,textarea').first().focus()
|
||||
|
||||
@animationFrame.add =>
|
||||
lightboxContent.show()
|
||||
defered.resolve()
|
||||
|
@ -67,6 +68,11 @@ class LightboxService extends taiga.Service
|
|||
|
||||
$el.addClass('close')
|
||||
|
||||
if $el.hasClass("remove-on-close")
|
||||
scope = $el.data("scope")
|
||||
scope.$destroy()
|
||||
$el.remove()
|
||||
|
||||
closeAll: ->
|
||||
docEl = angular.element(document)
|
||||
for lightboxEl in docEl.find(".lightbox.open")
|
||||
|
@ -148,14 +154,14 @@ module.directive("lightbox", ["lightboxService", LightboxDirective])
|
|||
|
||||
BlockLightboxDirective = ($rootscope, $tgrepo, $confirm, lightboxService, $loading, $qqueue, $translate) ->
|
||||
link = ($scope, $el, $attrs, $model) ->
|
||||
$translate($attrs.title).then (title) ->
|
||||
$el.find("h2.title").text(title)
|
||||
title = $translate.instant($attrs.title)
|
||||
$el.find("h2.title").text(title)
|
||||
|
||||
unblock = $qqueue.bindAdd (item, finishCallback) =>
|
||||
promise = $tgrepo.save(item)
|
||||
promise.then ->
|
||||
$confirm.notify("success")
|
||||
$rootscope.$broadcast("history:reload")
|
||||
$rootscope.$broadcast("object:updated")
|
||||
$model.$setViewValue(item)
|
||||
finishCallback()
|
||||
|
||||
|
@ -177,7 +183,7 @@ BlockLightboxDirective = ($rootscope, $tgrepo, $confirm, lightboxService, $loadi
|
|||
promise = $tgrepo.save($model.$modelValue)
|
||||
promise.then ->
|
||||
$confirm.notify("success")
|
||||
$rootscope.$broadcast("history:reload")
|
||||
$rootscope.$broadcast("object:updated")
|
||||
|
||||
promise.then null, ->
|
||||
$confirm.notify("error")
|
||||
|
@ -467,7 +473,6 @@ AssignedToLightboxDirective = (lightboxService, lightboxKeyboardNavigationServic
|
|||
html = $compile(html)($scope)
|
||||
|
||||
$el.find("div.watchers").html(html)
|
||||
lightboxKeyboardNavigationService.init($el)
|
||||
|
||||
closeLightbox = () ->
|
||||
lightboxKeyboardNavigationService.stop()
|
||||
|
@ -481,7 +486,7 @@ AssignedToLightboxDirective = (lightboxService, lightboxKeyboardNavigationServic
|
|||
render(selectedUser)
|
||||
lightboxService.open($el).then ->
|
||||
$el.find('input').focus()
|
||||
|
||||
lightboxKeyboardNavigationService.init($el)
|
||||
|
||||
$scope.$watch "usersSearch", (searchingText) ->
|
||||
if searchingText?
|
||||
|
@ -562,7 +567,6 @@ WatchersLightboxDirective = ($repo, lightboxService, lightboxKeyboardNavigationS
|
|||
|
||||
html = usersTemplate(ctx)
|
||||
$el.find("div.watchers").html(html)
|
||||
lightboxKeyboardNavigationService.init($el)
|
||||
|
||||
closeLightbox = () ->
|
||||
lightboxKeyboardNavigationService.stop()
|
||||
|
@ -576,7 +580,7 @@ WatchersLightboxDirective = ($repo, lightboxService, lightboxKeyboardNavigationS
|
|||
|
||||
lightboxService.open($el).then ->
|
||||
$el.find("input").focus()
|
||||
lightboxKeyboardNavigationService.init($el)
|
||||
lightboxKeyboardNavigationService.init($el)
|
||||
|
||||
$scope.$watch "usersSearch", (searchingText) ->
|
||||
if not searchingText?
|
||||
|
|
|
@ -40,78 +40,84 @@ LoaderDirective = (tgLoader, $rootscope) ->
|
|||
$(document.body).removeClass("loader-active")
|
||||
$el.removeClass("active")
|
||||
|
||||
$rootscope.$on "$routeChangeSuccess", (e) ->
|
||||
tgLoader.startCurrentPageLoader()
|
||||
|
||||
$rootscope.$on "$locationChangeSuccess", (e) ->
|
||||
tgLoader.reset()
|
||||
|
||||
return {
|
||||
link: link
|
||||
}
|
||||
|
||||
module.directive("tgLoader", ["tgLoader", "$rootScope", LoaderDirective])
|
||||
|
||||
Loader = () ->
|
||||
forceDisabled = false
|
||||
|
||||
defaultConfig = {
|
||||
enabled: false,
|
||||
Loader = ($rootscope) ->
|
||||
config = {
|
||||
minTime: 300
|
||||
}
|
||||
|
||||
config = _.merge({}, defaultConfig)
|
||||
open = false
|
||||
startLoadTime = 0
|
||||
requestCount = 0
|
||||
lastResponseDate = 0
|
||||
|
||||
@.add = () ->
|
||||
return () ->
|
||||
if !forceDisabled
|
||||
config.enabled = true
|
||||
pageLoaded = (force = false) ->
|
||||
if startLoadTime
|
||||
timeoutValue = 0
|
||||
|
||||
if !force
|
||||
endTime = new Date().getTime()
|
||||
diff = endTime - startLoadTime
|
||||
|
||||
if diff < config.minTime
|
||||
timeoutValue = config.minTime - diff
|
||||
|
||||
timeout timeoutValue, ->
|
||||
$rootscope.$broadcast("loader:end")
|
||||
open = false
|
||||
window.prerenderReady = true # Needed by Prerender Server
|
||||
|
||||
@.$get = ["$rootScope", ($rootscope) ->
|
||||
startLoadTime = 0
|
||||
requestCount = 0
|
||||
lastResponseDate = 0
|
||||
|
||||
reset = () ->
|
||||
config = _.merge({}, defaultConfig)
|
||||
autoClose = () ->
|
||||
maxAuto = 5000
|
||||
timeoutAuto = setTimeout (() ->
|
||||
pageLoaded()
|
||||
|
||||
pageLoaded = (force = false) ->
|
||||
if startLoadTime
|
||||
timeoutValue = 0
|
||||
clearInterval(intervalAuto)
|
||||
), maxAuto
|
||||
|
||||
if !force
|
||||
endTime = new Date().getTime()
|
||||
diff = endTime - startLoadTime
|
||||
intervalAuto = setInterval (() ->
|
||||
if lastResponseDate && requestCount == 0
|
||||
pageLoaded()
|
||||
|
||||
if diff < config.minTime
|
||||
timeoutValue = config.minTime - diff
|
||||
clearInterval(intervalAuto)
|
||||
clearTimeout(timeoutAuto)
|
||||
), 50
|
||||
|
||||
timeout(timeoutValue, -> $rootscope.$broadcast("loader:end"))
|
||||
start = () ->
|
||||
startLoadTime = new Date().getTime()
|
||||
$rootscope.$broadcast("loader:start")
|
||||
open = true
|
||||
|
||||
start = () ->
|
||||
startLoadTime = new Date().getTime()
|
||||
$rootscope.$broadcast("loader:start")
|
||||
return {
|
||||
pageLoaded: pageLoaded
|
||||
start: (auto=false) ->
|
||||
if !open
|
||||
start()
|
||||
autoClose() if auto
|
||||
onStart: (fn) ->
|
||||
$rootscope.$on("loader:start", fn)
|
||||
|
||||
return {
|
||||
reset: reset
|
||||
pageLoaded: pageLoaded
|
||||
start: start
|
||||
startCurrentPageLoader: () ->
|
||||
if config.enabled
|
||||
start()
|
||||
onEnd: (fn) ->
|
||||
$rootscope.$on("loader:end", fn)
|
||||
|
||||
onStart: (fn) ->
|
||||
$rootscope.$on("loader:start", fn)
|
||||
logRequest: () ->
|
||||
requestCount++
|
||||
|
||||
onEnd: (fn) ->
|
||||
$rootscope.$on("loader:end", fn)
|
||||
logResponse: () ->
|
||||
requestCount--
|
||||
lastResponseDate = new Date().getTime()
|
||||
}
|
||||
|
||||
preventLoading: () ->
|
||||
forceDisabled = true
|
||||
|
||||
disablePreventLoading: () ->
|
||||
forceDisabled = false
|
||||
}
|
||||
]
|
||||
Loader.$inject = ["$rootScope"]
|
||||
|
||||
return
|
||||
|
||||
module.provider("tgLoader", [Loader])
|
||||
module.factory("tgLoader", Loader)
|
||||
|
|
|
@ -285,7 +285,7 @@ TagLineDirective = ($rootScope, $repo, $rs, $confirm, $qqueue, $template, $compi
|
|||
$model.$setViewValue(model)
|
||||
|
||||
onSuccess = ->
|
||||
$rootScope.$broadcast("history:reload")
|
||||
$rootScope.$broadcast("object:updated")
|
||||
onError = ->
|
||||
$confirm.notify("error")
|
||||
model.revert()
|
||||
|
@ -306,7 +306,7 @@ TagLineDirective = ($rootScope, $repo, $rs, $confirm, $qqueue, $template, $compi
|
|||
$model.$setViewValue(model)
|
||||
|
||||
onSuccess = ->
|
||||
$rootScope.$broadcast("history:reload")
|
||||
$rootScope.$broadcast("object:updated")
|
||||
onError = ->
|
||||
$confirm.notify("error")
|
||||
model.revert()
|
||||
|
|
|
@ -29,7 +29,7 @@ trim = @.taiga.trim
|
|||
|
||||
module = angular.module("taigaFeedback", [])
|
||||
|
||||
FeedbackDirective = ($lightboxService, $repo, $confirm, $loading)->
|
||||
FeedbackDirective = ($lightboxService, $repo, $confirm, $loading, feedbackService)->
|
||||
link = ($scope, $el, $attrs) ->
|
||||
form = $el.find("form").checksley()
|
||||
|
||||
|
@ -56,16 +56,23 @@ FeedbackDirective = ($lightboxService, $repo, $confirm, $loading)->
|
|||
|
||||
$el.on "submit", "form", submit
|
||||
|
||||
$scope.$on "feedback:show", ->
|
||||
$scope.$apply ->
|
||||
$scope.feedback = {}
|
||||
|
||||
openLightbox = ->
|
||||
$scope.feedback = {}
|
||||
$lightboxService.open($el)
|
||||
$el.find("textarea").focus()
|
||||
|
||||
$scope.$on "$destroy", ->
|
||||
$el.off()
|
||||
|
||||
return {link:link}
|
||||
openLightbox()
|
||||
|
||||
module.directive("tgLbFeedback", ["lightboxService", "$tgRepo", "$tgConfirm", "$tgLoading", FeedbackDirective])
|
||||
directive = {
|
||||
link: link,
|
||||
templateUrl: "common/lightbox-feedback.html"
|
||||
scope: {}
|
||||
}
|
||||
|
||||
return directive
|
||||
|
||||
module.directive("tgLbFeedback", ["lightboxService", "$tgRepo", "$tgConfirm",
|
||||
"$tgLoading", "tgFeedbackService", FeedbackDirective])
|
||||
|
|
|
@ -44,15 +44,14 @@ class IssueDetailController extends mixOf(taiga.Controller, taiga.PageMixin)
|
|||
"$q",
|
||||
"$tgLocation",
|
||||
"$log",
|
||||
"$appTitle",
|
||||
"tgAppMetaService",
|
||||
"$tgAnalytics",
|
||||
"$tgNavUrls",
|
||||
"$translate",
|
||||
"tgLoader"
|
||||
"$translate"
|
||||
]
|
||||
|
||||
constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location,
|
||||
@log, @appTitle, @analytics, @navUrls, @translate, tgLoader) ->
|
||||
@log, @appMetaService, @analytics, @navUrls, @translate) ->
|
||||
@scope.issueRef = @params.issueref
|
||||
@scope.sectionName = @translate.instant("ISSUES.SECTION_NAME")
|
||||
@.initializeEventHandlers()
|
||||
|
@ -61,33 +60,45 @@ class IssueDetailController extends mixOf(taiga.Controller, taiga.PageMixin)
|
|||
|
||||
# On Success
|
||||
promise.then =>
|
||||
@appTitle.set(@scope.issue.subject + " - " + @scope.project.name)
|
||||
@._setMeta()
|
||||
@.initializeOnDeleteGoToUrl()
|
||||
|
||||
# On Error
|
||||
promise.then null, @.onInitialDataError.bind(@)
|
||||
|
||||
# Finally
|
||||
promise.finally tgLoader.pageLoaded
|
||||
_setMeta: ->
|
||||
title = @translate.instant("ISSUE.PAGE_TITLE", {
|
||||
issueRef: "##{@scope.issue.ref}"
|
||||
issueSubject: @scope.issue.subject
|
||||
projectName: @scope.project.name
|
||||
})
|
||||
description = @translate.instant("ISSUE.PAGE_DESCRIPTION", {
|
||||
issueStatus: @scope.statusById[@scope.issue.status]?.name or "--"
|
||||
issueType: @scope.typeById[@scope.issue.type]?.name or "--"
|
||||
issueSeverity: @scope.severityById[@scope.issue.severity]?.name or "--"
|
||||
issuePriority: @scope.priorityById[@scope.issue.priority]?.name or "--"
|
||||
issueDescription: angular.element(@scope.issue.description_html or "").text()
|
||||
})
|
||||
@appMetaService.setAll(title, description)
|
||||
|
||||
initializeEventHandlers: ->
|
||||
@scope.$on "attachment:create", =>
|
||||
@rootscope.$broadcast("history:reload")
|
||||
@rootscope.$broadcast("object:updated")
|
||||
@analytics.trackEvent("attachment", "create", "create attachment on issue", 1)
|
||||
|
||||
@scope.$on "attachment:edit", =>
|
||||
@rootscope.$broadcast("history:reload")
|
||||
@rootscope.$broadcast("object:updated")
|
||||
|
||||
@scope.$on "attachment:delete", =>
|
||||
@rootscope.$broadcast("history:reload")
|
||||
@rootscope.$broadcast("object:updated")
|
||||
|
||||
@scope.$on "promote-issue-to-us:success", =>
|
||||
@analytics.trackEvent("issue", "promoteToUserstory", "promote issue to userstory", 1)
|
||||
@rootscope.$broadcast("history:reload")
|
||||
@rootscope.$broadcast("object:updated")
|
||||
@.loadIssue()
|
||||
|
||||
@scope.$on "custom-attributes-values:edit", =>
|
||||
@rootscope.$broadcast("history:reload")
|
||||
@rootscope.$broadcast("object:updated")
|
||||
|
||||
initializeOnDeleteGoToUrl: ->
|
||||
ctx = {project: @scope.project.slug}
|
||||
|
@ -229,7 +240,7 @@ IssueStatusButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue, $t
|
|||
onSuccess = ->
|
||||
$confirm.notify("success")
|
||||
$model.$setViewValue(issue)
|
||||
$rootScope.$broadcast("history:reload")
|
||||
$rootScope.$broadcast("object:updated")
|
||||
$loading.finish($el.find(".level-name"))
|
||||
onError = ->
|
||||
$confirm.notify("error")
|
||||
|
@ -313,7 +324,7 @@ IssueTypeButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue, $tem
|
|||
onSuccess = ->
|
||||
$confirm.notify("success")
|
||||
$model.$setViewValue(issue)
|
||||
$rootScope.$broadcast("history:reload")
|
||||
$rootScope.$broadcast("object:updated")
|
||||
$loading.finish($el.find(".level-name"))
|
||||
|
||||
onError = ->
|
||||
|
@ -399,7 +410,7 @@ IssueSeverityButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue,
|
|||
onSuccess = ->
|
||||
$confirm.notify("success")
|
||||
$model.$setViewValue(issue)
|
||||
$rootScope.$broadcast("history:reload")
|
||||
$rootScope.$broadcast("object:updated")
|
||||
$loading.finish($el.find(".level-name"))
|
||||
onError = ->
|
||||
$confirm.notify("error")
|
||||
|
@ -486,7 +497,7 @@ IssuePriorityButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue,
|
|||
onSuccess = ->
|
||||
$confirm.notify("success")
|
||||
$model.$setViewValue(issue)
|
||||
$rootScope.$broadcast("history:reload")
|
||||
$rootScope.$broadcast("object:updated")
|
||||
$loading.finish($el.find(".level-name"))
|
||||
onError = ->
|
||||
$confirm.notify("error")
|
||||
|
|
|
@ -47,18 +47,16 @@ class IssuesController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi
|
|||
"$routeParams",
|
||||
"$q",
|
||||
"$tgLocation",
|
||||
"$appTitle",
|
||||
"tgAppMetaService",
|
||||
"$tgNavUrls",
|
||||
"$tgEvents",
|
||||
"$tgAnalytics",
|
||||
"tgLoader",
|
||||
"$translate"
|
||||
]
|
||||
|
||||
constructor: (@scope, @rootscope, @repo, @confirm, @rs, @urls, @params, @q, @location, @appTitle,
|
||||
@navUrls, @events, @analytics, tgLoader, @translate) ->
|
||||
|
||||
@scope.sectionName = @translate.instant("ISSUES.LIST_SECTION_NAME")
|
||||
constructor: (@scope, @rootscope, @repo, @confirm, @rs, @urls, @params, @q, @location, @appMetaService,
|
||||
@navUrls, @events, @analytics, @translate) ->
|
||||
@scope.sectionName = "Issues"
|
||||
@scope.filters = {}
|
||||
|
||||
if _.isEmpty(@location.search())
|
||||
|
@ -72,14 +70,16 @@ class IssuesController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi
|
|||
|
||||
# On Success
|
||||
promise.then =>
|
||||
@appTitle.set("Issues - " + @scope.project.name)
|
||||
title = @translate.instant("ISSUES.PAGE_TITLE", {projectName: @scope.project.name})
|
||||
description = @translate.instant("ISSUES.PAGE_DESCRIPTION", {
|
||||
projectName: @scope.project.name,
|
||||
projectDescription: @scope.project.description
|
||||
})
|
||||
@appMetaService.setAll(title, description)
|
||||
|
||||
# On Error
|
||||
promise.then null, @.onInitialDataError.bind(@)
|
||||
|
||||
# Finally
|
||||
promise.finally tgLoader.pageLoaded
|
||||
|
||||
@scope.$on "issueform:new:success", =>
|
||||
@analytics.trackEvent("issue", "create", "create issue on issues list", 1)
|
||||
@.loadIssues()
|
||||
|
@ -440,7 +440,7 @@ module.directive("tgIssues", ["$log", "$tgLocation", "$tgTemplate", "$compile",
|
|||
## Issues Filters Directive
|
||||
#############################################################################
|
||||
|
||||
IssuesFiltersDirective = ($log, $location, $rs, $confirm, $loading, $template, $translate, $compile) ->
|
||||
IssuesFiltersDirective = ($log, $location, $rs, $confirm, $loading, $template, $translate, $compile, $auth) ->
|
||||
template = $template.get("issue/issues-filters.html", true)
|
||||
templateSelected = $template.get("issue/issues-filters-selected.html", true)
|
||||
|
||||
|
@ -477,7 +477,7 @@ IssuesFiltersDirective = ($log, $location, $rs, $confirm, $loading, $template, $
|
|||
html = $compile(html)($scope)
|
||||
$el.find(".filters-applied").html(html)
|
||||
|
||||
if selectedFilters.length > 0
|
||||
if $auth.isAuthenticated() && selectedFilters.length > 0
|
||||
$el.find(".save-filters").show()
|
||||
else
|
||||
$el.find(".save-filters").hide()
|
||||
|
@ -663,7 +663,7 @@ IssuesFiltersDirective = ($log, $location, $rs, $confirm, $loading, $template, $
|
|||
return {link:link}
|
||||
|
||||
module.directive("tgIssuesFilters", ["$log", "$tgLocation", "$tgResources", "$tgConfirm", "$tgLoading",
|
||||
"$tgTemplate", "$translate", "$compile", IssuesFiltersDirective])
|
||||
"$tgTemplate", "$translate", "$compile", "$tgAuth", IssuesFiltersDirective])
|
||||
|
||||
|
||||
#############################################################################
|
||||
|
@ -719,6 +719,7 @@ IssueStatusInlineEditionDirective = ($repo, $template, $rootscope) ->
|
|||
|
||||
$scope.$apply () ->
|
||||
$repo.save(issue).then ->
|
||||
$ctrl.loadIssues()
|
||||
|
||||
for filter in $scope.filters.statuses
|
||||
if filter.id == issue.status
|
||||
|
@ -726,21 +727,6 @@ IssueStatusInlineEditionDirective = ($repo, $template, $rootscope) ->
|
|||
|
||||
$rootscope.$broadcast("filters:issueupdate", $scope.filters)
|
||||
|
||||
filtering = false
|
||||
|
||||
for filter in $scope.filters.statuses
|
||||
if filter.selected == true
|
||||
filtering = true
|
||||
if filter.id == issue.status
|
||||
return
|
||||
|
||||
if not filtering
|
||||
return
|
||||
|
||||
for el, i in $scope.issues
|
||||
if el and el.id == issue.id
|
||||
$scope.issues.splice(i, 1)
|
||||
|
||||
for filter in $scope.filters.statuses
|
||||
if filter.id == issue.status
|
||||
filter.count++
|
||||
|
|
|
@ -58,16 +58,15 @@ class KanbanController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi
|
|||
"$routeParams",
|
||||
"$q",
|
||||
"$tgLocation",
|
||||
"$appTitle",
|
||||
"tgAppMetaService",
|
||||
"$tgNavUrls",
|
||||
"$tgEvents",
|
||||
"$tgAnalytics",
|
||||
"tgLoader",
|
||||
"$translate"
|
||||
]
|
||||
|
||||
constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location,
|
||||
@appTitle, @navUrls, @events, @analytics, tgLoader, @translate) ->
|
||||
@appMetaService, @navUrls, @events, @analytics, @translate) ->
|
||||
|
||||
bindMethods(@)
|
||||
|
||||
|
@ -79,14 +78,16 @@ class KanbanController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi
|
|||
|
||||
# On Success
|
||||
promise.then =>
|
||||
@appTitle.set("Kanban - " + @scope.project.name)
|
||||
title = @translate.instant("KANBAN.PAGE_TITLE", {projectName: @scope.project.name})
|
||||
description = @translate.instant("KANBAN.PAGE_DESCRIPTION", {
|
||||
projectName: @scope.project.name,
|
||||
projectDescription: @scope.project.description
|
||||
})
|
||||
@appMetaService.setAll(title, description)
|
||||
|
||||
# On Error
|
||||
promise.then null, @.onInitialDataError.bind(@)
|
||||
|
||||
# Finally
|
||||
promise.finally tgLoader.pageLoaded
|
||||
|
||||
initializeEventHandlers: ->
|
||||
@scope.$on "usform:new:success", =>
|
||||
@.loadUserstories()
|
||||
|
|
|
@ -1,316 +0,0 @@
|
|||
###
|
||||
# Copyright (C) 2014 Andrey Antukh <niwi@niwi.be>
|
||||
# Copyright (C) 2014 Jesús Espino Garcia <jespinog@gmail.com>
|
||||
# Copyright (C) 2014 David Barragán Merino <bameda@dbarragan.com>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# File: modules/nav.coffee
|
||||
###
|
||||
|
||||
taiga = @.taiga
|
||||
groupBy = @.taiga.groupBy
|
||||
bindOnce = @.taiga.bindOnce
|
||||
timeout = @.taiga.timeout
|
||||
|
||||
module = angular.module("taigaNavMenu", [])
|
||||
|
||||
|
||||
#############################################################################
|
||||
## Projects Navigation
|
||||
#############################################################################
|
||||
|
||||
class ProjectsNavigationController extends taiga.Controller
|
||||
@.$inject = ["$scope", "$rootScope", "$tgResources", "$tgNavUrls", "$projectUrl"]
|
||||
|
||||
constructor: (@scope, @rootscope, @rs, @navurls, @projectUrl) ->
|
||||
promise = @.loadInitialData()
|
||||
promise.then null, ->
|
||||
console.log "FAIL"
|
||||
# TODO
|
||||
|
||||
# Listen when someone wants to reload all the projects
|
||||
@scope.$on "projects:reload", =>
|
||||
@.loadInitialData()
|
||||
|
||||
# Listen when someone has reloaded a project
|
||||
@scope.$on "project:loaded", (ctx, project) =>
|
||||
@.loadInitialData()
|
||||
|
||||
loadInitialData: ->
|
||||
return @rs.projects.listByMember(@rootscope.user?.id).then (projects) =>
|
||||
for project in projects
|
||||
project.url = @projectUrl.get(project)
|
||||
@scope.projects = projects
|
||||
@scope.filteredProjects = projects
|
||||
@scope.filterText = ""
|
||||
return projects
|
||||
|
||||
newProject: ->
|
||||
@scope.$apply () =>
|
||||
@rootscope.$broadcast("projects:create")
|
||||
|
||||
filterProjects: (text) ->
|
||||
@scope.filteredProjects = _.filter @scope.projects, (project) ->
|
||||
project.name.toLowerCase().indexOf(text) > -1
|
||||
|
||||
@scope.filterText = text
|
||||
@rootscope.$broadcast("projects:filtered")
|
||||
|
||||
module.controller("ProjectsNavigationController", ProjectsNavigationController)
|
||||
|
||||
|
||||
ProjectsNavigationDirective = ($rootscope, animationFrame, $timeout, tgLoader, $location, $compile, $template) ->
|
||||
baseTemplate = $template.get("project/project-navigation-base.html", true)
|
||||
projectsTemplate = $template.get("project/project-navigation-list.html", true)
|
||||
|
||||
overlay = $(".projects-nav-overlay")
|
||||
loadingStart = 0
|
||||
|
||||
hideMenu = () ->
|
||||
if overlay.is(':visible')
|
||||
difftime = new Date().getTime() - loadingStart
|
||||
timeoutValue = 0
|
||||
|
||||
if (difftime < 1000)
|
||||
timeoutValue = 1000 - timeoutValue
|
||||
|
||||
timeout timeoutValue, ->
|
||||
overlay.one 'transitionend', () ->
|
||||
$(document.body)
|
||||
.removeClass("loading-project open-projects-nav closed-projects-nav")
|
||||
.css("overflow-x", "visible")
|
||||
|
||||
overlay.hide()
|
||||
|
||||
$(document.body).addClass("closed-projects-nav")
|
||||
|
||||
tgLoader.disablePreventLoading()
|
||||
|
||||
|
||||
link = ($scope, $el, $attrs, $ctrls) ->
|
||||
$ctrl = $ctrls[0]
|
||||
$rootscope.$on("project:loaded", hideMenu)
|
||||
|
||||
renderProjects = (projects) ->
|
||||
html = projectsTemplate({projects: projects})
|
||||
$el.find(".projects-list").html(html)
|
||||
|
||||
$scope.$emit("regenerate:project-pagination")
|
||||
|
||||
render = (projects) ->
|
||||
$el.html($compile(baseTemplate())($scope))
|
||||
renderProjects(projects)
|
||||
|
||||
overlay.on 'click', () ->
|
||||
hideMenu()
|
||||
|
||||
$(document).on 'keydown', (e) =>
|
||||
code = if e.keyCode then e.keyCode else e.which
|
||||
if code == 27
|
||||
hideMenu()
|
||||
|
||||
$scope.$on "nav:projects-list:open", ->
|
||||
if !$(document.body).hasClass("open-projects-nav")
|
||||
animationFrame.add () => overlay.show()
|
||||
|
||||
animationFrame.add(
|
||||
() => $(document.body).css("overflow-x", "hidden")
|
||||
() => $(document.body).toggleClass("open-projects-nav")
|
||||
)
|
||||
|
||||
$el.on "click", ".projects-list > li > a", (event) ->
|
||||
# HACK: to solve a problem with the loader when the next url
|
||||
# is equal to the current one
|
||||
target = angular.element(event.currentTarget)
|
||||
nextUrl = target.prop("href")
|
||||
currentUrl = $location.absUrl()
|
||||
if nextUrl == currentUrl
|
||||
hideMenu()
|
||||
return
|
||||
# END HACK
|
||||
|
||||
$(document.body).addClass('loading-project')
|
||||
|
||||
tgLoader.preventLoading()
|
||||
|
||||
loadingStart = new Date().getTime()
|
||||
|
||||
$el.on "click", ".create-project-button", (event) ->
|
||||
event.preventDefault()
|
||||
$ctrl.newProject()
|
||||
|
||||
$el.on "keyup", ".search-project", (event) ->
|
||||
target = angular.element(event.currentTarget)
|
||||
$ctrl.filterProjects(target.val())
|
||||
|
||||
$scope.$on "projects:filtered", ->
|
||||
renderProjects($scope.filteredProjects)
|
||||
|
||||
$scope.$watch "projects", (projects) ->
|
||||
render(projects) if projects?
|
||||
|
||||
return {
|
||||
require: ["tgProjectsNav"]
|
||||
controller: ProjectsNavigationController
|
||||
link: link
|
||||
}
|
||||
|
||||
|
||||
module.directive("tgProjectsNav", ["$rootScope", "animationFrame", "$timeout", "tgLoader", "$tgLocation", "$compile",
|
||||
"$tgTemplate", ProjectsNavigationDirective])
|
||||
|
||||
|
||||
#############################################################################
|
||||
## Project
|
||||
#############################################################################
|
||||
|
||||
ProjectMenuDirective = ($log, $compile, $auth, $rootscope, $tgAuth, $location, $navUrls, $config, $template) ->
|
||||
menuEntriesTemplate = $template.get("project/project-menu.html", true)
|
||||
|
||||
mainTemplate = _.template("""
|
||||
<div class="logo-container logo">
|
||||
<svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 134.2 134.3" version="1.1" preserveAspectRatio="xMidYMid meet">
|
||||
<style>
|
||||
path {
|
||||
fill:#f5f5f5;
|
||||
opacity:0.7;
|
||||
}
|
||||
</style>
|
||||
<g transform="translate(-307.87667,-465.22863)">
|
||||
<g class="bottom">
|
||||
<path transform="matrix(-0.14066483,0.99005727,-0.99005727,0.14066483,0,0)" d="m561.8-506.6 42 0 0 42-42 0z" />
|
||||
<path transform="matrix(0.14066483,-0.99005727,0.99005727,-0.14066483,0,0)" d="m-645.7 422.6 42 0 0 42-42 0z" />
|
||||
<path transform="matrix(0.99005727,0.14066483,0.14066483,0.99005727,0,0)" d="m266.6 451.9 42 0 0 42-42 0z" />
|
||||
<path transform="matrix(-0.99005727,-0.14066483,-0.14066483,-0.99005727,0,0)" d="m-350.6-535.9 42 0 0 42-42 0z" />
|
||||
</g>
|
||||
<g class="top">
|
||||
<path transform="matrix(-0.60061118,-0.79954125,0.60061118,-0.79954125,0,0)" d="m-687.1-62.7 42 0 0 42-42 0z" />
|
||||
<path transform="matrix(-0.79954125,0.60061118,-0.79954125,-0.60061118,0,0)" d="m166.6-719.6 42 0 0 42-42 0z" />
|
||||
<path transform="matrix(0.60061118,0.79954125,-0.60061118,0.79954125,0,0)" d="m603.1-21.3 42 0 0 42-42 0z" />
|
||||
<path transform="matrix(0.79954125,-0.60061118,0.79954125,0.60061118,0,0)" d="m-250.7 635.8 42 0 0 42-42 0z" />
|
||||
<path transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,0,0)" d="m630.3 100 22.6 0 0 22.6-22.6 0z" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<span class="item">taiga<sup>[beta]</sup></span>
|
||||
</div>
|
||||
<div class="menu-container"></div>
|
||||
""")
|
||||
|
||||
# If the last page was kanban or backlog and
|
||||
# the new one is the task detail or the us details
|
||||
# this method preserve the last section name.
|
||||
getSectionName = ($el, sectionName, project) ->
|
||||
oldSectionName = $el.find("a.active").parent().attr("id")?.replace("nav-", "")
|
||||
|
||||
if sectionName == "backlog-kanban"
|
||||
if oldSectionName in ["backlog", "kanban"]
|
||||
sectionName = oldSectionName
|
||||
else if project.is_backlog_activated && !project.is_kanban_activated
|
||||
sectionName = "backlog"
|
||||
else if !project.is_backlog_activated && project.is_kanban_activated
|
||||
sectionName = "kanban"
|
||||
|
||||
return sectionName
|
||||
|
||||
renderMainMenu = ($el) ->
|
||||
html = mainTemplate({})
|
||||
$el.html(html)
|
||||
|
||||
# WARNING: this code has traces of slighty hacky parts
|
||||
# This rerenders and compiles the navigation when ng-view
|
||||
# content loaded signal is raised using inner scope.
|
||||
renderMenuEntries = ($el, targetScope, project={}) ->
|
||||
container = $el.find(".menu-container")
|
||||
sectionName = getSectionName($el, targetScope.section, project)
|
||||
|
||||
ctx = {
|
||||
user: $auth.getUser(),
|
||||
project: project,
|
||||
feedbackEnabled: $config.get("feedbackEnabled")
|
||||
}
|
||||
dom = $compile(menuEntriesTemplate(ctx))(targetScope)
|
||||
|
||||
dom.find("a.active").removeClass("active")
|
||||
dom.find("#nav-#{sectionName} > a").addClass("active")
|
||||
|
||||
container.replaceWith(dom)
|
||||
|
||||
videoConferenceUrl = (project) ->
|
||||
urlFixer = (url) -> return url
|
||||
|
||||
if project.videoconferences == "appear-in"
|
||||
baseUrl = "https://appear.in/"
|
||||
else if project.videoconferences == "talky"
|
||||
baseUrl = "https://talky.io/"
|
||||
else if project.videoconferences == "jitsi"
|
||||
baseUrl = "https://meet.jit.si/"
|
||||
urlFixer = (url) -> return url.replace(/ /g, "").replace(/-/g, "")
|
||||
else
|
||||
return ""
|
||||
|
||||
if project.videoconferences_salt
|
||||
url = "#{project.slug}-#{project.videoconferences_salt}"
|
||||
else
|
||||
url = "#{project.slug}"
|
||||
|
||||
url = urlFixer(url)
|
||||
|
||||
return baseUrl + url
|
||||
|
||||
|
||||
link = ($scope, $el, $attrs, $ctrl) ->
|
||||
renderMainMenu($el)
|
||||
project = null
|
||||
|
||||
$el.on "click", ".logo", (event) ->
|
||||
event.preventDefault()
|
||||
target = angular.element(event.currentTarget)
|
||||
$rootscope.$broadcast("nav:projects-list:open")
|
||||
|
||||
$el.on "click", ".user-settings .avatar", (event) ->
|
||||
event.preventDefault()
|
||||
$el.find(".user-settings .popover").popover().open()
|
||||
|
||||
$el.on "click", ".logout", (event) ->
|
||||
event.preventDefault()
|
||||
$auth.logout()
|
||||
$scope.$apply ->
|
||||
$location.path($navUrls.resolve("login"))
|
||||
|
||||
$el.on "click", "#nav-search > a", (event) ->
|
||||
event.preventDefault()
|
||||
$rootscope.$broadcast("search-box:show", project)
|
||||
|
||||
$el.on "click", ".feedback", (event) ->
|
||||
event.preventDefault()
|
||||
$rootscope.$broadcast("feedback:show")
|
||||
|
||||
$scope.$on "projects:loaded", (listener) ->
|
||||
$el.addClass("hidden")
|
||||
listener.stopPropagation()
|
||||
|
||||
$scope.$on "project:loaded", (ctx, newProject) ->
|
||||
project = newProject
|
||||
if $el.hasClass("hidden")
|
||||
$el.removeClass("hidden")
|
||||
|
||||
project.videoconferenceUrl = videoConferenceUrl(project)
|
||||
renderMenuEntries($el, ctx.targetScope, project)
|
||||
|
||||
return {link: link}
|
||||
|
||||
module.directive("tgProjectMenu", ["$log", "$compile", "$tgAuth", "$rootScope", "$tgAuth", "$tgLocation",
|
||||
"$tgNavUrls", "$tgConfig", "$tgTemplate", ProjectMenuDirective])
|
|
@ -26,7 +26,7 @@ debounce = @.taiga.debounce
|
|||
|
||||
module = angular.module("taigaProject")
|
||||
|
||||
CreateProject = ($rootscope, $repo, $confirm, $location, $navurls, $rs, $projectUrl, $loading, lightboxService, $cacheFactory, $translate) ->
|
||||
CreateProject = ($rootscope, $repo, $confirm, $location, $navurls, $rs, $projectUrl, $loading, lightboxService, $cacheFactory, $translate, currentUserService) ->
|
||||
link = ($scope, $el, attrs) ->
|
||||
$scope.data = {}
|
||||
$scope.templates = []
|
||||
|
@ -46,6 +46,7 @@ CreateProject = ($rootscope, $repo, $confirm, $location, $navurls, $rs, $project
|
|||
|
||||
$location.url($projectUrl.get(response))
|
||||
lightboxService.close($el)
|
||||
currentUserService._loadProjects()
|
||||
|
||||
onErrorSubmit = (response) ->
|
||||
$loading.finish(submitButton)
|
||||
|
@ -69,7 +70,7 @@ CreateProject = ($rootscope, $repo, $confirm, $location, $navurls, $rs, $project
|
|||
promise = $repo.create("projects", $scope.data)
|
||||
promise.then(onSuccessSubmit, onErrorSubmit)
|
||||
|
||||
$scope.$on "projects:create", ->
|
||||
openLightbox = ->
|
||||
$scope.data = {
|
||||
total_story_points: 100
|
||||
total_milestones: 5
|
||||
|
@ -125,17 +126,30 @@ CreateProject = ($rootscope, $repo, $confirm, $location, $navurls, $rs, $project
|
|||
event.preventDefault()
|
||||
lightboxService.close($el)
|
||||
|
||||
return {link:link}
|
||||
$scope.$on "$destroy", ->
|
||||
$el.off()
|
||||
|
||||
module.directive("tgLbCreateProject", ["$rootScope", "$tgRepo", "$tgConfirm", "$location", "$tgNavUrls",
|
||||
"$tgResources", "$projectUrl", "$tgLoading", "lightboxService", "$cacheFactory", "$translate", CreateProject])
|
||||
openLightbox()
|
||||
|
||||
directive = {
|
||||
link: link,
|
||||
templateUrl: "project/wizard-create-project.html"
|
||||
scope: {}
|
||||
}
|
||||
|
||||
return directive
|
||||
|
||||
|
||||
module.directive("tgLbCreateProject", ["$rootScope", "$tgRepo", "$tgConfirm",
|
||||
"$location", "$tgNavUrls", "$tgResources", "$projectUrl", "$tgLoading",
|
||||
"lightboxService", "$cacheFactory", "$translate", "tgCurrentUserService", CreateProject])
|
||||
|
||||
|
||||
#############################################################################
|
||||
## Delete Project Lightbox Directive
|
||||
#############################################################################
|
||||
|
||||
DeleteProjectDirective = ($repo, $rootscope, $auth, $location, $navUrls, $confirm, lightboxService, tgLoader) ->
|
||||
DeleteProjectDirective = ($repo, $rootscope, $auth, $location, $navUrls, $confirm, lightboxService, tgLoader, currentUserService) ->
|
||||
link = ($scope, $el, $attrs) ->
|
||||
projectToDelete = null
|
||||
$scope.$on "deletelightbox:new", (ctx, project)->
|
||||
|
@ -156,6 +170,7 @@ DeleteProjectDirective = ($repo, $rootscope, $auth, $location, $navUrls, $confir
|
|||
$rootscope.$broadcast("projects:reload")
|
||||
$location.path($navUrls.resolve("home"))
|
||||
$confirm.notify("success")
|
||||
currentUserService._loadProjects()
|
||||
|
||||
# FIXME: error handling?
|
||||
promise.then null, ->
|
||||
|
@ -173,4 +188,4 @@ DeleteProjectDirective = ($repo, $rootscope, $auth, $location, $navUrls, $confir
|
|||
return {link:link}
|
||||
|
||||
module.directive("tgLbDeleteProject", ["$tgRepo", "$rootScope", "$tgAuth", "$tgLocation", "$tgNavUrls",
|
||||
"$tgConfirm", "lightboxService", "tgLoader", DeleteProjectDirective])
|
||||
"$tgConfirm", "lightboxService", "tgLoader", "tgCurrentUserService", DeleteProjectDirective])
|
||||
|
|
|
@ -1,269 +0,0 @@
|
|||
###
|
||||
# Copyright (C) 2014 Andrey Antukh <niwi@niwi.be>
|
||||
# Copyright (C) 2014 Jesús Espino Garcia <jespinog@gmail.com>
|
||||
# Copyright (C) 2014 David Barragán Merino <bameda@dbarragan.com>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# File: modules/common/attachments.coffee
|
||||
###
|
||||
|
||||
taiga = @.taiga
|
||||
module = angular.module("taigaProject")
|
||||
bindOnce = @.taiga.bindOnce
|
||||
|
||||
class ProjectsController extends taiga.Controller
|
||||
@.$inject = [
|
||||
"$scope",
|
||||
"$q",
|
||||
"$tgResources",
|
||||
"$rootScope",
|
||||
"$tgNavUrls",
|
||||
"$tgAuth",
|
||||
"$tgLocation",
|
||||
"$appTitle",
|
||||
"$projectUrl",
|
||||
"tgLoader"
|
||||
]
|
||||
|
||||
constructor: (@scope, @q, @rs, @rootscope, @navUrls, @auth, @location, @appTitle, @projectUrl,
|
||||
tgLoader) ->
|
||||
@appTitle.set("Projects")
|
||||
|
||||
if !@auth.isAuthenticated()
|
||||
@location.path(@navUrls.resolve("login"))
|
||||
else
|
||||
tgLoader.start()
|
||||
|
||||
@.user = @auth.getUser()
|
||||
|
||||
@.projects = []
|
||||
promise = @.loadInitialData()
|
||||
|
||||
promise.then () =>
|
||||
@scope.$emit("projects:loaded", @.projects)
|
||||
|
||||
promise.then null, @.onInitialDataError.bind(@)
|
||||
|
||||
# Finally
|
||||
promise.finally tgLoader.pageLoaded
|
||||
|
||||
loadInitialData: ->
|
||||
return @rs.projects.listByMember(@rootscope.user?.id).then (projects) =>
|
||||
@.projects = {'recents': projects.slice(0, 8), 'all': projects}
|
||||
for project in projects
|
||||
project.url = @projectUrl.get(project)
|
||||
|
||||
return projects
|
||||
|
||||
newProject: ->
|
||||
@rootscope.$broadcast("projects:create")
|
||||
|
||||
logout: ->
|
||||
@auth.logout()
|
||||
@location.path(@navUrls.resolve("login"))
|
||||
|
||||
module.controller("ProjectsController", ProjectsController)
|
||||
|
||||
|
||||
class ProjectController extends taiga.Controller
|
||||
@.$inject = [
|
||||
"$scope",
|
||||
"$tgResources",
|
||||
"$tgRepo",
|
||||
"$routeParams",
|
||||
"$q",
|
||||
"$rootScope",
|
||||
"$appTitle",
|
||||
"$tgLocation",
|
||||
"$tgNavUrls"
|
||||
]
|
||||
|
||||
constructor: (@scope, @rs, @repo, @params, @q, @rootscope, @appTitle, @location, @navUrls) ->
|
||||
promise = @.loadInitialData()
|
||||
|
||||
promise.then () =>
|
||||
@appTitle.set(@scope.project.name)
|
||||
@scope.$emit("regenerate:project-pagination")
|
||||
|
||||
promise.then null, @.onInitialDataError.bind(@)
|
||||
|
||||
loadInitialData: ->
|
||||
# Resolve project slug
|
||||
promise = @repo.resolve({pslug: @params.pslug}).then (data) =>
|
||||
@scope.projectId = data.project
|
||||
return data
|
||||
|
||||
return promise.then(=> @.loadPageData())
|
||||
.then(=> @scope.$emit("project:loaded", @scope.project))
|
||||
|
||||
loadPageData: ->
|
||||
return @q.all([
|
||||
@.loadProjectStats(),
|
||||
@.loadProject()])
|
||||
|
||||
loadProject: ->
|
||||
return @rs.projects.get(@scope.projectId).then (project) =>
|
||||
@scope.project = project
|
||||
return project
|
||||
|
||||
loadProjectStats: ->
|
||||
return @rs.projects.stats(@scope.projectId).then (stats) =>
|
||||
@scope.stats = stats
|
||||
return stats
|
||||
|
||||
module.controller("ProjectController", ProjectController)
|
||||
|
||||
|
||||
ProjectsPaginationDirective = ($timeout) ->
|
||||
link = ($scope, $el, $attrs) ->
|
||||
prevBtn = $el.find(".v-pagination-previous")
|
||||
nextBtn = $el.find(".v-pagination-next")
|
||||
container = $el.find("ul")
|
||||
|
||||
pageSize = 0
|
||||
containerSize = 0
|
||||
|
||||
render = ->
|
||||
pageSize = $el.find(".v-pagination-list").height()
|
||||
|
||||
if container.find("li").length
|
||||
if hasPagination()
|
||||
if hasNextPage()
|
||||
visible(nextBtn)
|
||||
else
|
||||
hide(nextBtn)
|
||||
|
||||
if hasPrevPage()
|
||||
visible(prevBtn)
|
||||
else
|
||||
hide(prevBtn)
|
||||
else
|
||||
remove()
|
||||
else
|
||||
remove()
|
||||
|
||||
hasPagination = ->
|
||||
containerSize = container.height()
|
||||
|
||||
return containerSize > pageSize
|
||||
|
||||
hasPrevPage = (top) ->
|
||||
if !top?
|
||||
top = -parseInt(container.css('top'), 10) || 0
|
||||
|
||||
return top != 0
|
||||
|
||||
hasNextPage = (top) ->
|
||||
containerSize = container.height()
|
||||
|
||||
if !top
|
||||
top = -parseInt(container.css('top'), 10) || 0
|
||||
|
||||
return containerSize > pageSize && top + pageSize < containerSize
|
||||
|
||||
nextPage = (callback) ->
|
||||
top = parseInt(container.css('top'), 10)
|
||||
newTop = top - pageSize
|
||||
|
||||
lastLi = $el.find(".v-pagination-list li:last-child")
|
||||
maxTop = -((lastLi.position().top + lastLi.outerHeight()) - pageSize)
|
||||
|
||||
newTop = maxTop if newTop < maxTop
|
||||
|
||||
container.animate({"top": newTop}, callback)
|
||||
|
||||
return newTop
|
||||
|
||||
prevPage = (callback) ->
|
||||
top = parseInt(container.css('top'), 10)
|
||||
|
||||
newTop = top + pageSize
|
||||
|
||||
newTop = 0 if newTop > 0
|
||||
|
||||
container.animate({"top": newTop}, callback)
|
||||
|
||||
return newTop
|
||||
|
||||
visible = (element) ->
|
||||
element.css('visibility', 'visible')
|
||||
|
||||
hide = (element) ->
|
||||
element.css('visibility', 'hidden')
|
||||
|
||||
checkButtonVisibility = () ->
|
||||
|
||||
remove = () ->
|
||||
container.css('top', 0)
|
||||
hide(prevBtn)
|
||||
hide(nextBtn)
|
||||
|
||||
$el.on "click", ".v-pagination-previous", (event) ->
|
||||
event.preventDefault()
|
||||
|
||||
if container.is(':animated')
|
||||
return
|
||||
|
||||
visible(nextBtn)
|
||||
|
||||
newTop = prevPage()
|
||||
|
||||
if !hasPrevPage(newTop)
|
||||
hide(prevBtn)
|
||||
|
||||
$el.on "click", ".v-pagination-next", (event) ->
|
||||
event.preventDefault()
|
||||
|
||||
if container.is(':animated')
|
||||
return
|
||||
|
||||
visible(prevBtn)
|
||||
|
||||
newTop = -nextPage()
|
||||
|
||||
if !hasNextPage(newTop)
|
||||
hide(nextBtn)
|
||||
|
||||
$scope.$on "regenerate:project-pagination", ->
|
||||
remove()
|
||||
render()
|
||||
|
||||
$(window).on "resize.projects-pagination", render
|
||||
|
||||
$scope.$on "$destroy", ->
|
||||
$(window).off "resize.projects-pagination"
|
||||
|
||||
return {
|
||||
link: link
|
||||
}
|
||||
|
||||
module.directive("tgProjectsPagination", ['$timeout', ProjectsPaginationDirective])
|
||||
|
||||
ProjectsListDirective = ($compile, $template) ->
|
||||
template = $template.get('project/project-list.html', true)
|
||||
|
||||
link = ($scope, $el, $attrs, $ctrls) ->
|
||||
render = (projects) ->
|
||||
$el.html($compile(template({projects: projects}))($scope))
|
||||
$scope.$emit("regenerate:project-pagination")
|
||||
|
||||
$scope.$on "projects:loaded", (ctx, projects) ->
|
||||
render(projects.all) if projects.all?
|
||||
|
||||
return {
|
||||
link: link
|
||||
}
|
||||
|
||||
module.directive("tgProjectsList", ["$compile", "$tgTemplate", ProjectsListDirective])
|
|
@ -31,13 +31,17 @@ urls = {
|
|||
|
||||
# User
|
||||
"users": "/users"
|
||||
"by_username": "/users/by_username"
|
||||
"users-password-recovery": "/users/password_recovery"
|
||||
"users-change-password-from-recovery": "/users/change_password_from_recovery"
|
||||
"users-change-password": "/users/change_password"
|
||||
"users-change-email": "/users/change_email"
|
||||
"users-cancel-account": "/users/cancel"
|
||||
"contacts": "/users/%s/contacts"
|
||||
"stats": "/users/%s/stats"
|
||||
|
||||
# User - Notification
|
||||
"permissions": "/permissions"
|
||||
"notify-policies": "/notify-policies"
|
||||
|
||||
# User - Storage
|
||||
|
@ -58,6 +62,7 @@ urls = {
|
|||
"projects": "/projects"
|
||||
"project-templates": "/project-templates"
|
||||
"project-modules": "/projects/%s/modules"
|
||||
"bulk-update-projects-order": "/projects/bulk_update_order"
|
||||
|
||||
# Project Values - Choises
|
||||
"userstory-statuses": "/userstory-statuses"
|
||||
|
@ -125,6 +130,11 @@ urls = {
|
|||
"tasks-csv": "/tasks/csv?uuid=%s"
|
||||
"issues-csv": "/issues/csv?uuid=%s"
|
||||
|
||||
# Timeline
|
||||
"timeline-profile": "/timeline/profile"
|
||||
"timeline-user": "/timeline/user"
|
||||
"timeline-project": "/timeline/project"
|
||||
|
||||
# Search
|
||||
"search": "/search"
|
||||
|
||||
|
@ -183,5 +193,6 @@ module.run([
|
|||
"$tgWebhooksResourcesProvider",
|
||||
"$tgWebhookLogsResourcesProvider",
|
||||
"$tgLocalesResourcesProvider",
|
||||
"$tgUsersResourcesProvider",
|
||||
initResources
|
||||
])
|
||||
|
|
|
@ -41,6 +41,9 @@ resourceProvider = ($repo, $http, $urls, $storage, $q) ->
|
|||
params.ref = ref
|
||||
return $repo.queryOne("issues", "by_ref", params)
|
||||
|
||||
service.listInAllProjects = (filters) ->
|
||||
return $repo.queryMany("issues", filters)
|
||||
|
||||
service.list = (projectId, filters, options) ->
|
||||
params = {project: projectId}
|
||||
params = _.extend({}, params, filters or {})
|
||||
|
|
|
@ -37,7 +37,7 @@ resourceProvider = ($config, $repo, $http, $urls, $auth, $q, $translate) ->
|
|||
return $repo.queryMany("projects")
|
||||
|
||||
service.listByMember = (memberId) ->
|
||||
params = {"member": memberId}
|
||||
params = {"member": memberId, "order_by": "memberships__user_order"}
|
||||
return $repo.queryMany("projects", params)
|
||||
|
||||
service.templates = ->
|
||||
|
@ -54,6 +54,10 @@ resourceProvider = ($config, $repo, $http, $urls, $auth, $q, $translate) ->
|
|||
service.stats = (projectId) ->
|
||||
return $repo.queryOneRaw("projects", "#{projectId}/stats")
|
||||
|
||||
service.bulkUpdateOrder = (bulkData) ->
|
||||
url = $urls.resolve("bulk-update-projects-order")
|
||||
return $http.post(url, bulkData)
|
||||
|
||||
service.regenerate_userstories_csv_uuid = (projectId) ->
|
||||
url = "#{$urls.resolve("projects")}/#{projectId}/regenerate_userstories_csv_uuid"
|
||||
return $http.post(url)
|
||||
|
|
|
@ -41,6 +41,9 @@ resourceProvider = ($repo, $http, $urls, $storage) ->
|
|||
params.ref = ref
|
||||
return $repo.queryOne("tasks", "by_ref", params)
|
||||
|
||||
service.listInAllProjects = (filters) ->
|
||||
return $repo.queryMany("tasks", filters)
|
||||
|
||||
service.list = (projectId, sprintId=null, userStoryId=null) ->
|
||||
params = {project: projectId}
|
||||
params.milestone = sprintId if sprintId
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
###
|
||||
# Copyright (C) 2014 Andrey Antukh <niwi@niwi.be>
|
||||
# Copyright (C) 2014 Jesús Espino Garcia <jespinog@gmail.com>
|
||||
# Copyright (C) 2014 David Barragán Merino <bameda@dbarragan.com>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# File: modules/resources/user.coffee
|
||||
###
|
||||
|
||||
|
||||
taiga = @.taiga
|
||||
sizeFormat = @.taiga.sizeFormat
|
||||
|
||||
|
||||
resourceProvider = ($http, $urls) ->
|
||||
service = {}
|
||||
|
||||
service.contacts = (userId, options={}) ->
|
||||
url = $urls.resolve("contacts", userId)
|
||||
httpOptions = {headers: {}}
|
||||
|
||||
if not options.enablePagination
|
||||
httpOptions.headers["x-disable-pagination"] = "1"
|
||||
|
||||
return $http.get(url, {}, httpOptions)
|
||||
.then (result) ->
|
||||
return result.data
|
||||
|
||||
return (instance) ->
|
||||
instance.users = service
|
||||
|
||||
|
||||
module = angular.module("taigaResources")
|
||||
module.factory("$tgUsersResourcesProvider", ["$tgHttp", "$tgUrls", "$q",
|
||||
resourceProvider])
|
|
@ -38,6 +38,9 @@ resourceProvider = ($repo, $http, $urls, $storage) ->
|
|||
params.ref = ref
|
||||
return $repo.queryOne("userstories", "by_ref", params)
|
||||
|
||||
service.listInAllProjects = (filters) ->
|
||||
return $repo.queryMany("userstories", filters)
|
||||
|
||||
service.listUnassigned = (projectId, filters) ->
|
||||
params = {"project": projectId, "milestone": "null"}
|
||||
params = _.extend({}, params, filters or {})
|
||||
|
|
|
@ -43,18 +43,23 @@ class SearchController extends mixOf(taiga.Controller, taiga.PageMixin)
|
|||
"$routeParams",
|
||||
"$q",
|
||||
"$tgLocation",
|
||||
"$appTitle",
|
||||
"tgAppMetaService",
|
||||
"$tgNavUrls",
|
||||
"tgLoader"
|
||||
"$translate"
|
||||
]
|
||||
|
||||
constructor: (@scope, @repo, @rs, @params, @q, @location, @appTitle, @navUrls, @tgLoader) ->
|
||||
constructor: (@scope, @repo, @rs, @params, @q, @location, @appMetaService, @navUrls, @translate) ->
|
||||
@scope.sectionName = "Search"
|
||||
|
||||
promise = @.loadInitialData()
|
||||
|
||||
promise.then () =>
|
||||
@appTitle.set("Search")
|
||||
title = @translate.instant("SEARCH.PAGE_TITLE", {projectName: @scope.project.name})
|
||||
description = @translate.instant("SEARCH.PAGE_DESCRIPTION", {
|
||||
projectName: @scope.project.name,
|
||||
projectDescription: @scope.project.description
|
||||
})
|
||||
@appMetaService.setAll(title, description)
|
||||
|
||||
promise.then null, @.onInitialDataError.bind(@)
|
||||
|
||||
|
@ -63,9 +68,7 @@ class SearchController extends mixOf(taiga.Controller, taiga.PageMixin)
|
|||
loadSearchData = debounceLeading(100, (t) => @.loadSearchData(t))
|
||||
|
||||
@scope.$watch "searchTerm", (term) =>
|
||||
if not term
|
||||
@tgLoader.pageLoaded()
|
||||
else
|
||||
if term
|
||||
loadSearchData(term)
|
||||
|
||||
loadFilters: ->
|
||||
|
@ -90,9 +93,6 @@ class SearchController extends mixOf(taiga.Controller, taiga.PageMixin)
|
|||
@scope.searchResults = data
|
||||
return data
|
||||
|
||||
promise.finally =>
|
||||
@tgLoader.pageLoaded()
|
||||
|
||||
return promise
|
||||
|
||||
loadInitialData: ->
|
||||
|
@ -107,7 +107,7 @@ module.controller("SearchController", SearchController)
|
|||
## Search box directive
|
||||
#############################################################################
|
||||
|
||||
SearchBoxDirective = ($lightboxService, $navurls, $location, $route)->
|
||||
SearchBoxDirective = (projectService, $lightboxService, $navurls, $location, $route)->
|
||||
link = ($scope, $el, $attrs) ->
|
||||
project = null
|
||||
|
||||
|
@ -120,24 +120,40 @@ SearchBoxDirective = ($lightboxService, $navurls, $location, $route)->
|
|||
|
||||
text = $el.find("#search-text").val()
|
||||
|
||||
url = $navurls.resolve("project-search", {project: project.slug})
|
||||
url = $navurls.resolve("project-search", {project: project.get("slug")})
|
||||
|
||||
$lightboxService.close($el)
|
||||
$scope.$apply ->
|
||||
$lightboxService.close($el)
|
||||
|
||||
$location.path(url)
|
||||
$location.search("text", text).path(url)
|
||||
$route.reload()
|
||||
|
||||
$scope.$on "search-box:show", (ctx, newProject)->
|
||||
project = newProject
|
||||
$lightboxService.open($el)
|
||||
$el.find("#search-text").val("")
|
||||
|
||||
openLightbox = () ->
|
||||
project = projectService.project
|
||||
|
||||
$lightboxService.open($el).then () ->
|
||||
$el.find("#search-text").focus()
|
||||
|
||||
$el.on "submit", "form", submit
|
||||
|
||||
return {link:link}
|
||||
openLightbox()
|
||||
|
||||
module.directive("tgSearchBox", ["lightboxService", "$tgNavUrls", "$tgLocation", "$route", SearchBoxDirective])
|
||||
return {
|
||||
templateUrl: "search/lightbox-search.html",
|
||||
link:link
|
||||
}
|
||||
|
||||
SearchBoxDirective.$inject = [
|
||||
"tgProjectService",
|
||||
"lightboxService",
|
||||
"$tgNavUrls",
|
||||
"$tgLocation",
|
||||
"$route"
|
||||
]
|
||||
|
||||
module.directive("tgSearchBox", SearchBoxDirective)
|
||||
|
||||
|
||||
#############################################################################
|
||||
|
@ -154,12 +170,15 @@ SearchDirective = ($log, $compile, $templatecache, $routeparams, $location) ->
|
|||
selectedSectionName = null
|
||||
selectedSectionData = null
|
||||
|
||||
for name, value of data
|
||||
continue if name == "count"
|
||||
if value.length > maxVal
|
||||
maxVal = value.length
|
||||
selectedSectionName = name
|
||||
selectedSectionData = value
|
||||
if data
|
||||
for name in ["userstories", "issues", "tasks", "wikipages"]
|
||||
value = data[name]
|
||||
|
||||
if value.length > maxVal
|
||||
maxVal = value.length
|
||||
selectedSectionName = name
|
||||
selectedSectionData = value
|
||||
break;
|
||||
|
||||
if maxVal == 0
|
||||
return {name: "userstories", value: []}
|
||||
|
|
|
@ -44,17 +44,16 @@ class TaskboardController extends mixOf(taiga.Controller, taiga.PageMixin)
|
|||
"$tgResources",
|
||||
"$routeParams",
|
||||
"$q",
|
||||
"$appTitle",
|
||||
"tgAppMetaService",
|
||||
"$tgLocation",
|
||||
"$tgNavUrls"
|
||||
"$tgEvents"
|
||||
"$tgAnalytics",
|
||||
"tgLoader"
|
||||
"$translate"
|
||||
]
|
||||
|
||||
constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @appTitle, @location, @navUrls,
|
||||
@events, @analytics, tgLoader, @translate) ->
|
||||
constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @appMetaService, @location, @navUrls,
|
||||
@events, @analytics, @translate) ->
|
||||
bindMethods(@)
|
||||
|
||||
@scope.sectionName = @translate.instant("TASKBOARD.SECTION_NAME")
|
||||
|
@ -63,14 +62,30 @@ class TaskboardController extends mixOf(taiga.Controller, taiga.PageMixin)
|
|||
promise = @.loadInitialData()
|
||||
|
||||
# On Success
|
||||
promise.then =>
|
||||
@appTitle.set("Taskboard - " + @scope.project.name)
|
||||
|
||||
promise.then => @._setMeta()
|
||||
# On Error
|
||||
promise.then null, @.onInitialDataError.bind(@)
|
||||
|
||||
# Finally
|
||||
promise.finally tgLoader.pageLoaded
|
||||
_setMeta: ->
|
||||
prettyDate = @translate.instant("BACKLOG.SPRINTS.DATE")
|
||||
|
||||
title = @translate.instant("TASKBOARD.PAGE_TITLE", {
|
||||
projectName: @scope.project.name
|
||||
sprintName: @scope.sprint.name
|
||||
})
|
||||
description = @translate.instant("TASKBOARD.PAGE_DESCRIPTION", {
|
||||
projectName: @scope.project.name
|
||||
sprintName: @scope.sprint.name
|
||||
startDate: moment(@scope.sprint.estimated_start).format(prettyDate)
|
||||
endDate: moment(@scope.sprint.estimated_finish).format(prettyDate)
|
||||
completedPercentage: @scope.stats.completedPercentage or "0"
|
||||
completedPoints: @scope.stats.completedPointsSum or "--"
|
||||
totalPoints: @scope.stats.totalPointsSum or "--"
|
||||
openTasks: @scope.stats.openTasks or "--"
|
||||
totalTasks: @scope.stats.total_tasks or "--"
|
||||
})
|
||||
|
||||
@appMetaService.setAll(title, description)
|
||||
|
||||
initializeEventHandlers: ->
|
||||
# TODO: Reload entire taskboard after create/edit tasks seems
|
||||
|
@ -136,7 +151,7 @@ class TaskboardController extends mixOf(taiga.Controller, taiga.PageMixin)
|
|||
@scope.stats.remainingPointsSum = remainingPointsSum
|
||||
@scope.stats.remainingTasks = remainingTasks
|
||||
if stats.totalPointsSum
|
||||
@scope.stats.completedPercentage = Math.round(100 * stats.completedPointsSum / stats.totalPointsSum)
|
||||
@scope.stats.completedPercentage = Math.round(100*stats.completedPointsSum/stats.totalPointsSum)
|
||||
else
|
||||
@scope.stats.completedPercentage = 0
|
||||
|
||||
|
@ -259,7 +274,7 @@ TaskboardDirective = ($rootscope) ->
|
|||
$el.on "click", ".toggle-analytics-visibility", (event) ->
|
||||
event.preventDefault()
|
||||
target = angular.element(event.currentTarget)
|
||||
target.toggleClass('active');
|
||||
target.toggleClass('active')
|
||||
$rootscope.$broadcast("taskboard:graph:toggle-visibility")
|
||||
|
||||
tableBodyDom = $el.find(".taskboard-table-body")
|
||||
|
|
|
@ -42,15 +42,14 @@ class TaskDetailController extends mixOf(taiga.Controller, taiga.PageMixin)
|
|||
"$q",
|
||||
"$tgLocation",
|
||||
"$log",
|
||||
"$appTitle",
|
||||
"tgAppMetaService",
|
||||
"$tgNavUrls",
|
||||
"$tgAnalytics",
|
||||
"$translate",
|
||||
"tgLoader"
|
||||
"$translate"
|
||||
]
|
||||
|
||||
constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location,
|
||||
@log, @appTitle, @navUrls, @analytics, @translate, tgLoader) ->
|
||||
@log, @appMetaService, @navUrls, @analytics, @translate) ->
|
||||
@scope.taskRef = @params.taskref
|
||||
@scope.sectionName = @translate.instant("TASK.SECTION_NAME")
|
||||
@.initializeEventHandlers()
|
||||
|
@ -58,23 +57,33 @@ class TaskDetailController extends mixOf(taiga.Controller, taiga.PageMixin)
|
|||
promise = @.loadInitialData()
|
||||
|
||||
promise.then () =>
|
||||
@appTitle.set(@scope.task.subject + " - " + @scope.project.name)
|
||||
@._setMeta()
|
||||
@.initializeOnDeleteGoToUrl()
|
||||
|
||||
promise.then null, @.onInitialDataError.bind(@)
|
||||
|
||||
promise.finally tgLoader.pageLoaded
|
||||
_setMeta: ->
|
||||
title = @translate.instant("TASK.PAGE_TITLE", {
|
||||
taskRef: "##{@scope.task.ref}"
|
||||
taskSubject: @scope.task.subject
|
||||
projectName: @scope.project.name
|
||||
})
|
||||
description = @translate.instant("TASK.PAGE_DESCRIPTION", {
|
||||
taskStatus: @scope.statusById[@scope.task.status]?.name or "--"
|
||||
taskDescription: angular.element(@scope.task.description_html or "").text()
|
||||
})
|
||||
@appMetaService.setAll(title, description)
|
||||
|
||||
initializeEventHandlers: ->
|
||||
@scope.$on "attachment:create", =>
|
||||
@analytics.trackEvent("attachment", "create", "create attachment on task", 1)
|
||||
@rootscope.$broadcast("history:reload")
|
||||
@rootscope.$broadcast("object:updated")
|
||||
@scope.$on "attachment:edit", =>
|
||||
@rootscope.$broadcast("history:reload")
|
||||
@rootscope.$broadcast("object:updated")
|
||||
@scope.$on "attachment:delete", =>
|
||||
@rootscope.$broadcast("history:reload")
|
||||
@rootscope.$broadcast("object:updated")
|
||||
@scope.$on "custom-attributes-values:edit", =>
|
||||
@rootscope.$broadcast("history:reload")
|
||||
@rootscope.$broadcast("object:updated")
|
||||
|
||||
initializeOnDeleteGoToUrl: ->
|
||||
ctx = {project: @scope.project.slug}
|
||||
|
@ -169,7 +178,6 @@ TaskStatusDisplayDirective = ($template, $compile) ->
|
|||
})
|
||||
|
||||
html = $compile(html)($scope)
|
||||
|
||||
$el.html(html)
|
||||
|
||||
$scope.$watch $attrs.ngModel, (task) ->
|
||||
|
@ -241,7 +249,7 @@ TaskStatusButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue, $co
|
|||
|
||||
onSuccess = ->
|
||||
$confirm.notify("success")
|
||||
$rootScope.$broadcast("history:reload")
|
||||
$rootScope.$broadcast("object:updated")
|
||||
$loading.finish($el.find(".level-name"))
|
||||
|
||||
onError = ->
|
||||
|
@ -326,7 +334,7 @@ TaskIsIocaineButtonDirective = ($rootscope, $tgrepo, $confirm, $loading, $qqueue
|
|||
|
||||
promise.then ->
|
||||
$confirm.notify("success")
|
||||
$rootscope.$broadcast("history:reload")
|
||||
$rootscope.$broadcast("object:updated")
|
||||
|
||||
promise.then null, ->
|
||||
task.revert()
|
||||
|
|
|
@ -39,29 +39,30 @@ class TeamController extends mixOf(taiga.Controller, taiga.PageMixin)
|
|||
"$q",
|
||||
"$location",
|
||||
"$tgNavUrls",
|
||||
"$appTitle",
|
||||
"tgAppMetaService",
|
||||
"$tgAuth",
|
||||
"tgLoader",
|
||||
"$translate"
|
||||
"$translate",
|
||||
"tgProjectService"
|
||||
]
|
||||
|
||||
constructor: (@scope, @rootscope, @repo, @rs, @params, @q, @location, @navUrls, @appTitle, @auth, tgLoader,
|
||||
@translate) ->
|
||||
constructor: (@scope, @rootscope, @repo, @rs, @params, @q, @location, @navUrls, @appMetaService, @auth,
|
||||
@translate, @projectService) ->
|
||||
@scope.sectionName = "TEAM.SECTION_NAME"
|
||||
|
||||
promise = @.loadInitialData()
|
||||
|
||||
# On Success
|
||||
promise.then =>
|
||||
text = @translate.instant("TEAM.APP_TITLE", {"projectName": @scope.project.name})
|
||||
@appTitle.set(text)
|
||||
title = @translate.instant("TEAM.PAGE_TITLE", {projectName: @scope.project.name})
|
||||
description = @translate.instant("TEAM.PAGE_DESCRIPTION", {
|
||||
projectName: @scope.project.name,
|
||||
projectDescription: @scope.project.description
|
||||
})
|
||||
@appMetaService.setAll(title, description)
|
||||
|
||||
# On Error
|
||||
promise.then null, @.onInitialDataError.bind(@)
|
||||
|
||||
# Finally
|
||||
promise.finally tgLoader.pageLoaded
|
||||
|
||||
setRole: (role) ->
|
||||
if role
|
||||
@scope.filtersRole = role
|
||||
|
@ -69,27 +70,30 @@ class TeamController extends mixOf(taiga.Controller, taiga.PageMixin)
|
|||
@scope.filtersRole = null
|
||||
|
||||
loadMembers: ->
|
||||
return @rs.memberships.list(@scope.projectId, {}, false).then (data) =>
|
||||
currentUser = @auth.getUser()
|
||||
if currentUser? and not currentUser.photo?
|
||||
currentUser.photo = "/images/unnamed.png"
|
||||
currentUser = @auth.getUser()
|
||||
|
||||
@scope.currentUser = _.find data, (membership) =>
|
||||
return currentUser? and membership.user == currentUser.id
|
||||
if currentUser? and not currentUser.photo?
|
||||
currentUser.photo = "/images/unnamed.png"
|
||||
|
||||
@scope.totals = {}
|
||||
_.forEach data, (membership) =>
|
||||
@scope.totals[membership.user] = 0
|
||||
memberships = @projectService.project.toJS().memberships
|
||||
|
||||
@scope.memberships = _.filter data, (membership) =>
|
||||
if membership.user && (not currentUser? or membership.user != currentUser.id) && membership.is_user_active
|
||||
return membership
|
||||
@scope.currentUser = _.find memberships, (membership) =>
|
||||
return currentUser? and membership.user == currentUser.id
|
||||
|
||||
for membership in @scope.memberships
|
||||
if not membership.photo?
|
||||
membership.photo = "/images/unnamed.png"
|
||||
@scope.totals = {}
|
||||
|
||||
return data
|
||||
_.forEach memberships, (membership) =>
|
||||
@scope.totals[membership.user] = 0
|
||||
|
||||
@scope.memberships = _.filter memberships, (membership) =>
|
||||
if membership.user && (not currentUser? or membership.user != currentUser.id)
|
||||
return membership
|
||||
|
||||
@scope.memberships = _.filter memberships, (membership) => return membership.is_active
|
||||
|
||||
for membership in @scope.memberships
|
||||
if not membership.photo?
|
||||
membership.photo = "/images/unnamed.png"
|
||||
|
||||
loadProject: ->
|
||||
return @rs.projects.getBySlug(@params.pslug).then (project) =>
|
||||
|
@ -135,7 +139,9 @@ class TeamController extends mixOf(taiga.Controller, taiga.PageMixin)
|
|||
promise = @.loadProject()
|
||||
return promise.then (project) =>
|
||||
@.fillUsersAndRoles(project.users, project.roles)
|
||||
return @.loadMembers().then(=> @.loadMemberStats())
|
||||
@.loadMembers()
|
||||
|
||||
return @.loadMemberStats()
|
||||
|
||||
module.controller("TeamController", TeamController)
|
||||
|
||||
|
|
|
@ -46,28 +46,11 @@ class UserChangePasswordController extends mixOf(taiga.Controller, taiga.PageMix
|
|||
"$translate"
|
||||
]
|
||||
|
||||
constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, @navUrls, @auth, @translate) ->
|
||||
constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, @navUrls,
|
||||
@auth, @translate) ->
|
||||
@scope.sectionName = @translate.instant("CHANGE_PASSWORD.SECTION_NAME")
|
||||
@scope.project = {}
|
||||
@scope.user = @auth.getUser()
|
||||
|
||||
promise = @.loadInitialData()
|
||||
|
||||
promise.then null, @.onInitialDataError.bind(@)
|
||||
|
||||
loadProject: ->
|
||||
return @rs.projects.get(@scope.projectId).then (project) =>
|
||||
@scope.project = project
|
||||
@scope.$emit('project:loaded', project)
|
||||
return project
|
||||
|
||||
loadInitialData: ->
|
||||
promise = @repo.resolve({pslug: @params.pslug}).then (data) =>
|
||||
@scope.projectId = data.project
|
||||
return data
|
||||
|
||||
return promise.then(=> @.loadProject())
|
||||
|
||||
module.controller("UserChangePasswordController", UserChangePasswordController)
|
||||
|
||||
|
||||
|
|
|
@ -45,41 +45,33 @@ class UserSettingsController extends mixOf(taiga.Controller, taiga.PageMixin)
|
|||
"$translate"
|
||||
]
|
||||
|
||||
constructor: (@scope, @rootscope, @config, @repo, @confirm, @rs, @params, @q, @location, @navUrls, @auth, @translate) ->
|
||||
constructor: (@scope, @rootscope, @config, @repo, @confirm, @rs, @params, @q, @location, @navUrls,
|
||||
@auth, @translate) ->
|
||||
@scope.sectionName = "USER_SETTINGS.MENU.SECTION_TITLE"
|
||||
|
||||
@scope.project = {}
|
||||
@scope.user = @auth.getUser()
|
||||
|
||||
if !@scope.user
|
||||
@location.path(@navUrls.resolve("permission-denied"))
|
||||
@location.replace()
|
||||
|
||||
@scope.lang = @getLan()
|
||||
|
||||
maxFileSize = @config.get("maxUploadFileSize", null)
|
||||
if maxFileSize
|
||||
@translate("USER_SETTINGS.AVATAR_MAX_SIZE", {"maxFileSize": sizeFormat(maxFileSize)}).then (text) =>
|
||||
@scope.maxFileSizeMsg = text
|
||||
text = @translate.instant("USER_SETTINGS.AVATAR_MAX_SIZE", {"maxFileSize": sizeFormat(maxFileSize)})
|
||||
@scope.maxFileSizeMsg = text
|
||||
|
||||
promise = @.loadInitialData()
|
||||
|
||||
promise.then null, @.onInitialDataError.bind(@)
|
||||
|
||||
loadProject: ->
|
||||
return @rs.projects.get(@scope.projectId).then (project) =>
|
||||
@scope.project = project
|
||||
@scope.$emit('project:loaded', project)
|
||||
return project
|
||||
|
||||
loadLocales: ->
|
||||
loadInitialData: ->
|
||||
return @rs.locales.list().then (locales) =>
|
||||
@scope.locales = locales
|
||||
return locales
|
||||
|
||||
loadInitialData: ->
|
||||
promise = @repo.resolve({pslug: @params.pslug}).then (data) =>
|
||||
@scope.projectId = data.project
|
||||
return data
|
||||
|
||||
return @q.all([promise.then(=> @.loadProject()),
|
||||
@.loadLocales()])
|
||||
|
||||
openDeleteLightbox: ->
|
||||
@rootscope.$broadcast("deletelightbox:new", @scope.user)
|
||||
|
||||
|
|
|
@ -46,33 +46,15 @@ class UserNotificationsController extends mixOf(taiga.Controller, taiga.PageMixi
|
|||
|
||||
constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, @navUrls, @auth) ->
|
||||
@scope.sectionName = "USER_SETTINGS.NOTIFICATIONS.SECTION_NAME"
|
||||
@scope.project = {}
|
||||
@scope.user = @auth.getUser()
|
||||
|
||||
promise = @.loadInitialData()
|
||||
|
||||
promise.then null, @.onInitialDataError.bind(@)
|
||||
|
||||
loadProject: ->
|
||||
return @rs.projects.get(@scope.projectId).then (project) =>
|
||||
@scope.project = project
|
||||
@scope.$emit('project:loaded', project)
|
||||
return project
|
||||
|
||||
loadNotifyPolicies: ->
|
||||
loadInitialData: ->
|
||||
return @rs.notifyPolicies.list().then (notifyPolicies) =>
|
||||
@scope.notifyPolicies = notifyPolicies
|
||||
return notifyPolicies
|
||||
|
||||
loadInitialData: ->
|
||||
promise = @repo.resolve({pslug: @params.pslug}).then (data) =>
|
||||
@scope.projectId = data.project
|
||||
return data
|
||||
|
||||
return promise.then(=> @.loadProject())
|
||||
.then(=> @.loadNotifyPolicies())
|
||||
|
||||
|
||||
module.controller("UserNotificationsController", UserNotificationsController)
|
||||
|
||||
|
||||
|
|
|
@ -42,15 +42,14 @@ class UserStoryDetailController extends mixOf(taiga.Controller, taiga.PageMixin)
|
|||
"$q",
|
||||
"$tgLocation",
|
||||
"$log",
|
||||
"$appTitle",
|
||||
"tgAppMetaService",
|
||||
"$tgNavUrls",
|
||||
"$tgAnalytics",
|
||||
"$translate",
|
||||
"tgLoader"
|
||||
"$translate"
|
||||
]
|
||||
|
||||
constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location,
|
||||
@log, @appTitle, @navUrls, @analytics, @translate, tgLoader) ->
|
||||
@log, @appMetaService, @navUrls, @analytics, @translate) ->
|
||||
@scope.usRef = @params.usref
|
||||
@scope.sectionName = @translate.instant("US.SECTION_NAME")
|
||||
@.initializeEventHandlers()
|
||||
|
@ -59,12 +58,32 @@ class UserStoryDetailController extends mixOf(taiga.Controller, taiga.PageMixin)
|
|||
|
||||
# On Success
|
||||
promise.then =>
|
||||
@appTitle.set(@scope.us.subject + " - " + @scope.project.name)
|
||||
@._setMeta()
|
||||
@.initializeOnDeleteGoToUrl()
|
||||
|
||||
# On Error
|
||||
promise.then null, @.onInitialDataError.bind(@)
|
||||
promise.finally tgLoader.pageLoaded
|
||||
|
||||
_setMeta: ->
|
||||
totalTasks = @scope.tasks.length
|
||||
closedTasks = _.filter(@scope.tasks, (t) => @scope.taskStatusById[t.status].is_closed).length
|
||||
progressPercentage = if totalTasks > 0 then Math.round(100 * closedTasks / totalTasks) else 0
|
||||
|
||||
title = @translate.instant("US.PAGE_TITLE", {
|
||||
userStoryRef: "##{@scope.us.ref}"
|
||||
userStorySubject: @scope.us.subject
|
||||
projectName: @scope.project.name
|
||||
})
|
||||
description = @translate.instant("US.PAGE_DESCRIPTION", {
|
||||
userStoryStatus: @scope.statusById[@scope.us.status]?.name or "--"
|
||||
userStoryPoints: @scope.us.total_points
|
||||
userStoryDescription: angular.element(@scope.us.description_html or "").text()
|
||||
userStoryClosedTasks: closedTasks
|
||||
userStoryTotalTasks: totalTasks
|
||||
userStoryProgressPercentage: progressPercentage
|
||||
})
|
||||
|
||||
@appMetaService.setAll(title, description)
|
||||
|
||||
initializeEventHandlers: ->
|
||||
@scope.$on "related-tasks:update", =>
|
||||
|
@ -73,16 +92,16 @@ class UserStoryDetailController extends mixOf(taiga.Controller, taiga.PageMixin)
|
|||
|
||||
@scope.$on "attachment:create", =>
|
||||
@analytics.trackEvent("attachment", "create", "create attachment on userstory", 1)
|
||||
@rootscope.$broadcast("history:reload")
|
||||
@rootscope.$broadcast("object:updated")
|
||||
|
||||
@scope.$on "attachment:edit", =>
|
||||
@rootscope.$broadcast("history:reload")
|
||||
@rootscope.$broadcast("object:updated")
|
||||
|
||||
@scope.$on "attachment:delete", =>
|
||||
@rootscope.$broadcast("history:reload")
|
||||
@rootscope.$broadcast("object:updated")
|
||||
|
||||
@scope.$on "custom-attributes-values:edit", =>
|
||||
@rootscope.$broadcast("history:reload")
|
||||
@rootscope.$broadcast("object:updated")
|
||||
|
||||
initializeOnDeleteGoToUrl: ->
|
||||
ctx = {project: @scope.project.slug}
|
||||
|
@ -299,6 +318,7 @@ UsStatusButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue, $temp
|
|||
|
||||
save = $qqueue.bindAdd (status) =>
|
||||
us = $model.$modelValue.clone()
|
||||
|
||||
us.status = status
|
||||
|
||||
$.fn.popover().closeAll()
|
||||
|
@ -307,7 +327,7 @@ UsStatusButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue, $temp
|
|||
|
||||
onSuccess = ->
|
||||
$confirm.notify("success")
|
||||
$rootScope.$broadcast("history:reload")
|
||||
$rootScope.$broadcast("object:updated")
|
||||
$loading.finish($el.find(".level-name"))
|
||||
|
||||
onError = ->
|
||||
|
@ -389,7 +409,7 @@ UsTeamRequirementButtonDirective = ($rootscope, $tgrepo, $confirm, $loading, $qq
|
|||
promise = $tgrepo.save($model.$modelValue)
|
||||
promise.then =>
|
||||
$loading.finish($el.find("label"))
|
||||
$rootscope.$broadcast("history:reload")
|
||||
$rootscope.$broadcast("object:updated")
|
||||
|
||||
promise.then null, ->
|
||||
$loading.finish($el.find("label"))
|
||||
|
@ -451,7 +471,7 @@ UsClientRequirementButtonDirective = ($rootscope, $tgrepo, $confirm, $loading, $
|
|||
promise = $tgrepo.save($model.$modelValue)
|
||||
promise.then =>
|
||||
$loading.finish($el.find("label"))
|
||||
$rootscope.$broadcast("history:reload")
|
||||
$rootscope.$broadcast("object:updated")
|
||||
promise.then null, ->
|
||||
$loading.finish($el.find("label"))
|
||||
$confirm.notify("error")
|
||||
|
|
|
@ -46,15 +46,14 @@ class WikiDetailController extends mixOf(taiga.Controller, taiga.PageMixin)
|
|||
"$tgLocation",
|
||||
"$filter",
|
||||
"$log",
|
||||
"$appTitle",
|
||||
"tgAppMetaService",
|
||||
"$tgNavUrls",
|
||||
"$tgAnalytics",
|
||||
"tgLoader",
|
||||
"$translate"
|
||||
]
|
||||
|
||||
constructor: (@scope, @rootscope, @repo, @model, @confirm, @rs, @params, @q, @location,
|
||||
@filter, @log, @appTitle, @navUrls, @analytics, tgLoader, @translate) ->
|
||||
@filter, @log, @appMetaService, @navUrls, @analytics, @translate) ->
|
||||
@scope.projectSlug = @params.pslug
|
||||
@scope.wikiSlug = @params.slug
|
||||
@scope.sectionName = "Wiki"
|
||||
|
@ -62,12 +61,22 @@ class WikiDetailController extends mixOf(taiga.Controller, taiga.PageMixin)
|
|||
promise = @.loadInitialData()
|
||||
|
||||
# On Success
|
||||
promise.then () =>
|
||||
@appTitle.set("Wiki - " + @scope.project.name)
|
||||
promise.then () => @._setMeta()
|
||||
|
||||
# On Error
|
||||
promise.then null, @.onInitialDataError.bind(@)
|
||||
promise.finally tgLoader.pageLoaded
|
||||
|
||||
_setMeta: ->
|
||||
title = @translate.instant("WIKI.PAGE_TITLE", {
|
||||
wikiPageName: @scope.wiki.slug
|
||||
projectName: unslugify(@scope.wiki.slug)
|
||||
})
|
||||
description = @translate.instant("WIKI.PAGE_DESCRIPTION", {
|
||||
wikiPageContent: angular.element(@scope.wiki.html or "").text()
|
||||
totalEditions: @scope.wiki.editions or 0
|
||||
lastModifiedDate: moment(@scope.wiki.modified_date).format(@translate.instant("WIKI.DATETIME"))
|
||||
})
|
||||
@appMetaService.setAll(title, description)
|
||||
|
||||
loadProject: ->
|
||||
return @rs.projects.getBySlug(@params.pslug).then (project) =>
|
||||
|
@ -109,7 +118,8 @@ class WikiDetailController extends mixOf(taiga.Controller, taiga.PageMixin)
|
|||
promise = @.loadProject()
|
||||
return promise.then (project) =>
|
||||
@.fillUsersAndRoles(project.users, project.roles)
|
||||
@q.all([@.loadWikiLinks(), @.loadWiki()])
|
||||
@q.all([@.loadWikiLinks(), @.loadWiki()]).then () =>
|
||||
|
||||
|
||||
delete: ->
|
||||
title = @translate.instant("WIKI.DELETE_LIGHTBOX_TITLE")
|
||||
|
|
|
@ -126,6 +126,19 @@ startswith = (str1, str2) ->
|
|||
return _.str.startsWith(str1, str2)
|
||||
|
||||
|
||||
truncate = (str, maxLength, suffix="...") ->
|
||||
return str if (typeof str != "string") and not (str instanceof String)
|
||||
|
||||
out = str.slice(0)
|
||||
|
||||
if out.length > maxLength
|
||||
out = out.substring(0, maxLength + 1)
|
||||
out = out.substring(0, Math.min(out.length, out.lastIndexOf(" ")))
|
||||
out = out + suffix
|
||||
|
||||
return out
|
||||
|
||||
|
||||
sizeFormat = (input, precision=1) ->
|
||||
if isNaN(parseFloat(input)) or not isFinite(input)
|
||||
return "-"
|
||||
|
@ -140,6 +153,37 @@ sizeFormat = (input, precision=1) ->
|
|||
size = (input / Math.pow(1024, number)).toFixed(precision)
|
||||
return "#{size} #{units[number]}"
|
||||
|
||||
stripTags = (str, exception) ->
|
||||
if exception
|
||||
pattern = new RegExp('<(?!' + exception + '\s*\/?)[^>]+>', 'gi')
|
||||
return String(str).replace(pattern, '')
|
||||
else
|
||||
return String(str).replace(/<\/?[^>]+>/g, '')
|
||||
|
||||
replaceTags = (str, tags, replace) ->
|
||||
# open tag
|
||||
pattern = new RegExp('<(' + tags + ')>', 'gi')
|
||||
str = str.replace(pattern, '<' + replace + '>')
|
||||
|
||||
# close tag
|
||||
pattern = new RegExp('<\/(' + tags + ')>', 'gi')
|
||||
str = str.replace(pattern, '</' + replace + '>')
|
||||
|
||||
return str
|
||||
|
||||
defineImmutableProperty = (obj, name, fn) =>
|
||||
Object.defineProperty obj, name, {
|
||||
get: () =>
|
||||
if !_.isFunction(fn)
|
||||
throw "defineImmutableProperty third param must be a function"
|
||||
|
||||
fn_result = fn()
|
||||
if fn_result && _.isObject(fn_result)
|
||||
if fn_result.size == undefined
|
||||
throw "defineImmutableProperty must return immutable data"
|
||||
|
||||
return fn_result
|
||||
}
|
||||
|
||||
taiga = @.taiga
|
||||
taiga.nl2br = nl2br
|
||||
|
@ -156,7 +200,11 @@ taiga.cancelTimeout = cancelTimeout
|
|||
taiga.scopeDefer = scopeDefer
|
||||
taiga.toString = toString
|
||||
taiga.joinStr = joinStr
|
||||
taiga.truncate = truncate
|
||||
taiga.debounce = debounce
|
||||
taiga.debounceLeading = debounceLeading
|
||||
taiga.startswith = startswith
|
||||
taiga.sizeFormat = sizeFormat
|
||||
taiga.stripTags = stripTags
|
||||
taiga.replaceTags = replaceTags
|
||||
taiga.defineImmutableProperty = defineImmutableProperty
|
||||
|
|
|
@ -0,0 +1,581 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
||||
<svg>
|
||||
<metadata>
|
||||
Created by FontForge 20110222 at Thu May 12 12:49:24 2011
|
||||
By www-data
|
||||
Digitized data copyright (c) 2010-2011, Google Corporation.
|
||||
</metadata>
|
||||
<defs>
|
||||
<font id="OpenSans-Light" horiz-adv-x="1169" >
|
||||
<font-face
|
||||
font-family="Open Sans Light"
|
||||
font-weight="300"
|
||||
font-stretch="normal"
|
||||
units-per-em="2048"
|
||||
panose-1="2 11 3 6 3 5 4 2 2 4"
|
||||
ascent="1638"
|
||||
descent="-410"
|
||||
x-height="1087"
|
||||
cap-height="1462"
|
||||
bbox="-907 -512 2218 1907"
|
||||
underline-thickness="102"
|
||||
underline-position="-103"
|
||||
unicode-range="U+0020-2122"
|
||||
/>
|
||||
<missing-glyph />
|
||||
<glyph glyph-name="space" unicode=" " horiz-adv-x="532"
|
||||
/>
|
||||
<glyph glyph-name="exclam" unicode="!" horiz-adv-x="492"
|
||||
d="M276 377h-61l-29 1085h119zM164 78q0 98 80 98q82 0 82 -98t-82 -98q-80 0 -80 98z" />
|
||||
<glyph glyph-name="quotedbl" unicode=""" horiz-adv-x="723"
|
||||
d="M260 1462l-33 -528h-61l-33 528h127zM590 1462l-33 -528h-61l-33 528h127z" />
|
||||
<glyph glyph-name="numbersign" unicode="#" horiz-adv-x="1323"
|
||||
d="M967 928l-76 -398h303v-79h-320l-86 -451h-90l88 451h-360l-86 -451h-88l86 451h-283v79h299l76 398h-297v80h311l86 454h91l-89 -454h365l88 454h86l-88 -454h285v-80h-301zM440 530h363l78 398h-363z" />
|
||||
<glyph glyph-name="dollar" unicode="$"
|
||||
d="M991 440q0 -133 -99 -217t-274 -106v-236h-81v232q-92 2 -200.5 22.5t-172.5 50.5v103q75 -36 179.5 -61t193.5 -25v508q-145 44 -215 88t-102 104t-32 146q0 124 94.5 208.5t254.5 104.5v192h81v-190q197 -9 351 -72l-33 -90q-141 62 -318 72v-486q213 -66 293 -144
|
||||
t80 -204zM881 444q0 85 -63 140.5t-200 95.5v-471q122 13 192.5 75t70.5 160zM297 1049q0 -86 57 -141t183 -93v453q-119 -16 -179.5 -76t-60.5 -143z" />
|
||||
<glyph glyph-name="percent" unicode="%" horiz-adv-x="1653"
|
||||
d="M211 1026q0 -186 45 -279.5t141 -93.5q193 0 193 373q0 184 -49.5 276.5t-143.5 92.5q-96 0 -141 -92.5t-45 -276.5zM688 1026q0 -226 -75 -343.5t-216 -117.5q-133 0 -208.5 120.5t-75.5 340.5q0 223 72 340t212 117q139 0 215 -120.5t76 -336.5zM1063 438
|
||||
q0 -185 45 -277.5t141 -92.5q193 0 193 370q0 369 -193 369q-96 0 -141 -91.5t-45 -277.5zM1540 438q0 -226 -74 -343.5t-215 -117.5q-136 0 -211 121.5t-75 339.5q0 225 73.5 341t212.5 116q137 0 213 -120t76 -337zM1280 1462l-811 -1462h-96l811 1462h96z" />
|
||||
<glyph glyph-name="ampersand" unicode="&" horiz-adv-x="1460"
|
||||
d="M123 371q0 138 73.5 235t274.5 205l-75 82q-66 71 -98 139t-32 142q0 143 95.5 227t256.5 84q155 0 245.5 -81t90.5 -224q0 -105 -70 -192.5t-253 -194.5l452 -457q61 72 104 157t75 201h96q-63 -246 -209 -426l266 -268h-135l-193 197q-92 -90 -164 -131.5t-157.5 -63.5
|
||||
t-194.5 -22q-209 0 -328.5 103t-119.5 288zM578 70q128 0 234.5 43.5t209.5 146.5l-483 485q-136 -72 -196.5 -122.5t-88 -109.5t-27.5 -138q0 -143 93 -224t258 -81zM373 1176q0 -79 40 -146t152 -174q159 85 221 159t62 169q0 94 -62 152.5t-168 58.5q-114 0 -179.5 -58
|
||||
t-65.5 -161z" />
|
||||
<glyph glyph-name="quotesingle" unicode="'" horiz-adv-x="393"
|
||||
d="M260 1462l-33 -528h-61l-33 528h127z" />
|
||||
<glyph glyph-name="parenleft" unicode="(" horiz-adv-x="557"
|
||||
d="M82 561q0 265 77.5 496t223.5 405h113q-148 -182 -227 -412.5t-79 -486.5q0 -483 304 -887h-111q-147 170 -224 397t-77 488z" />
|
||||
<glyph glyph-name="parenright" unicode=")" horiz-adv-x="557"
|
||||
d="M475 561q0 -263 -77.5 -490t-223.5 -395h-111q304 404 304 887q0 257 -79 487.5t-227 411.5h113q147 -175 224 -406.5t77 -494.5z" />
|
||||
<glyph glyph-name="asterisk" unicode="*" horiz-adv-x="1128"
|
||||
d="M631 1556l-37 -405l405 104l21 -131l-395 -39l247 -340l-124 -71l-191 379l-180 -379l-125 71l242 340l-390 39l19 131l401 -104l-39 405h146z" />
|
||||
<glyph glyph-name="plus" unicode="+"
|
||||
d="M625 764h434v-82h-434v-432h-82v432h-432v82h432v434h82v-434z" />
|
||||
<glyph glyph-name="comma" unicode="," horiz-adv-x="440"
|
||||
d="M295 238l12 -21q-75 -265 -174 -481h-65q77 275 110 502h117z" />
|
||||
<glyph glyph-name="hyphen" unicode="-" horiz-adv-x="659"
|
||||
d="M92 512v82h475v-82h-475z" />
|
||||
<glyph glyph-name="period" unicode="." horiz-adv-x="487"
|
||||
d="M162 78q0 98 80 98q82 0 82 -98t-82 -98q-80 0 -80 98z" />
|
||||
<glyph glyph-name="slash" unicode="/" horiz-adv-x="698"
|
||||
d="M674 1462l-545 -1462h-104l544 1462h105z" />
|
||||
<glyph glyph-name="zero" unicode="0"
|
||||
d="M1055 735q0 -385 -117.5 -570t-355.5 -185q-229 0 -348 190.5t-119 564.5q0 382 115.5 566t351.5 184q231 0 352 -190.5t121 -559.5zM223 735q0 -340 89 -502.5t270 -162.5q189 0 275.5 168t86.5 497q0 324 -86.5 492t-275.5 168t-274 -168t-85 -492z" />
|
||||
<glyph glyph-name="one" unicode="1"
|
||||
d="M682 0h-98v1065q0 145 12 301q-15 -15 -31 -29t-309 -243l-57 71l397 297h86v-1462z" />
|
||||
<glyph glyph-name="two" unicode="2"
|
||||
d="M1028 0h-915v88l389 406q164 170 230 260t97 172t31 172q0 131 -86 213t-223 82q-183 0 -350 -133l-54 69q183 154 406 154q191 0 300.5 -102t109.5 -281q0 -145 -73.5 -280.5t-268.5 -334.5l-375 -385v-4h782v-96z" />
|
||||
<glyph glyph-name="three" unicode="3"
|
||||
d="M979 1118q0 -136 -85.5 -229t-229.5 -119v-6q176 -22 268 -112t92 -242q0 -205 -139.5 -317.5t-401.5 -112.5q-223 0 -389 83v99q84 -44 188.5 -69t196.5 -25q221 0 332 89.5t111 252.5q0 145 -113.5 223t-333.5 78h-158v96h160q182 0 288.5 86.5t106.5 234.5
|
||||
q0 122 -86.5 195.5t-226.5 73.5q-109 0 -199 -30.5t-202 -104.5l-49 67q85 71 205 112.5t243 41.5q202 0 312 -95.5t110 -269.5z" />
|
||||
<glyph glyph-name="four" unicode="4"
|
||||
d="M1141 373h-252v-373h-94v373h-752v67l725 1030h121v-1011h252v-86zM795 459v418q0 302 14 507h-8q-20 -37 -123 -188l-516 -737h633z" />
|
||||
<glyph glyph-name="five" unicode="5"
|
||||
d="M537 879q234 0 368.5 -113t134.5 -311q0 -225 -140 -350t-386 -125q-109 0 -207 21.5t-164 61.5v103q108 -55 192 -76.5t179 -21.5q192 0 308 101.5t116 274.5q0 163 -113 256t-307 93q-130 0 -272 -39l-60 39l58 669h704v-96h-610l-45 -516q156 29 244 29z" />
|
||||
<glyph glyph-name="six" unicode="6"
|
||||
d="M131 623q0 285 77.5 479.5t220 288.5t343.5 94q94 0 172 -23v-88q-73 27 -176 27q-247 0 -384.5 -178t-154.5 -518h13q76 98 174 148t207 50q205 0 320.5 -117t115.5 -323q0 -224 -121.5 -353.5t-327.5 -129.5q-222 0 -350.5 169.5t-128.5 473.5zM610 68q164 0 255 103
|
||||
t91 294q0 168 -90 262t-245 94q-102 0 -189.5 -45t-139.5 -119.5t-52 -152.5q0 -111 49.5 -213.5t134 -162.5t186.5 -60z" />
|
||||
<glyph glyph-name="seven" unicode="7"
|
||||
d="M334 0l602 1366h-827v96h946v-73l-604 -1389h-117z" />
|
||||
<glyph glyph-name="eight" unicode="8"
|
||||
d="M582 1487q186 0 299.5 -95t113.5 -257q0 -112 -70.5 -198t-228.5 -159q192 -79 270 -173t78 -228q0 -181 -126.5 -289t-339.5 -108q-221 0 -339 101t-118 294q0 131 83 230t257 169q-161 76 -227 160.5t-66 202.5q0 105 53 184.5t148.5 122.5t212.5 43zM223 360
|
||||
q0 -138 93.5 -214t261.5 -76q164 0 264 80.5t100 218.5q0 124 -78.5 201.5t-302.5 162.5q-184 -71 -261 -157t-77 -216zM580 1397q-141 0 -226.5 -69.5t-85.5 -190.5q0 -70 31.5 -123.5t91 -97t199.5 -101.5q163 63 234 139t71 183q0 120 -84.5 190t-230.5 70z" />
|
||||
<glyph glyph-name="nine" unicode="9"
|
||||
d="M1036 842q0 -288 -75.5 -482t-220 -287t-349.5 -93q-104 0 -192 26v86q43 -14 103.5 -21.5t92.5 -7.5q247 0 387 178.5t156 520.5h-12q-73 -96 -174 -147.5t-211 -51.5q-203 0 -316.5 112t-113.5 318q0 220 124.5 356t323.5 136q144 0 252 -75.5t166.5 -221.5t58.5 -346z
|
||||
M559 1397q-158 0 -252 -106.5t-94 -291.5q0 -174 87 -264t249 -90q101 0 188.5 45t139 119.5t51.5 151.5q0 117 -46.5 219t-130 159.5t-192.5 57.5z" />
|
||||
<glyph glyph-name="colon" unicode=":" horiz-adv-x="487"
|
||||
d="M162 78q0 98 80 98q82 0 82 -98t-82 -98q-80 0 -80 98zM162 971q0 98 80 98q82 0 82 -98q0 -53 -23.5 -76t-58.5 -23q-34 0 -57 23t-23 76z" />
|
||||
<glyph glyph-name="semicolon" unicode=";" horiz-adv-x="487"
|
||||
d="M303 238l12 -21q-75 -265 -174 -481h-65q29 97 62 245.5t48 256.5h117zM162 971q0 98 80 98q82 0 82 -98q0 -53 -23.5 -76t-58.5 -23q-34 0 -57 23t-23 76z" />
|
||||
<glyph glyph-name="less" unicode="<"
|
||||
d="M1059 266l-948 416v61l948 474v-95l-823 -405l823 -355v-96z" />
|
||||
<glyph glyph-name="equal" unicode="="
|
||||
d="M111 885v82h948v-82h-948zM111 477v82h948v-82h-948z" />
|
||||
<glyph glyph-name="greater" unicode=">"
|
||||
d="M111 362l823 355l-823 405v95l948 -474v-61l-948 -416v96z" />
|
||||
<glyph glyph-name="question" unicode="?" horiz-adv-x="862"
|
||||
d="M293 377v37q0 123 37.5 201t138.5 167l91 79q72 61 103 121t31 138q0 127 -83.5 202t-219.5 75q-79 0 -148 -17.5t-149 -56.5l-37 80q110 48 184.5 64t153.5 16q183 0 288 -98.5t105 -270.5q0 -68 -18 -119t-50.5 -94.5t-78.5 -84t-102 -87.5q-64 -54 -98.5 -98.5
|
||||
t-50 -93.5t-15.5 -146v-14h-82zM260 78q0 98 80 98q82 0 82 -98t-82 -98q-80 0 -80 98z" />
|
||||
<glyph glyph-name="at" unicode="@" horiz-adv-x="1815"
|
||||
d="M1702 725q0 -228 -90.5 -366t-245.5 -138q-89 0 -144.5 54t-64.5 147h-4q-43 -100 -124 -150.5t-189 -50.5q-148 0 -229 96.5t-81 270.5q0 202 120.5 330.5t314.5 128.5q138 0 286 -41l-22 -464v-30q0 -104 35 -156.5t116 -52.5q103 0 168.5 116.5t65.5 303.5
|
||||
q0 194 -79 340t-225.5 224.5t-334.5 78.5q-230 0 -405.5 -99.5t-270 -281.5t-94.5 -418q0 -322 167 -497.5t474 -175.5q93 0 188.5 18t231.5 70v-99q-203 -80 -414 -80q-349 0 -544 200.5t-195 557.5q0 256 108.5 460.5t307 317.5t448.5 113q215 0 380.5 -89t255 -254.5
|
||||
t89.5 -383.5zM633 590q0 -143 55 -215t174 -72q255 0 273 346l16 291q-79 27 -193 27q-149 0 -237 -102.5t-88 -274.5z" />
|
||||
<glyph glyph-name="A" unicode="A" horiz-adv-x="1229"
|
||||
d="M911 516h-594l-204 -516h-113l588 1468h65l576 -1468h-115zM354 608h523l-199 527q-25 62 -60 172q-27 -96 -59 -174z" />
|
||||
<glyph glyph-name="B" unicode="B" horiz-adv-x="1284"
|
||||
d="M207 1462h401q271 0 398 -92t127 -278q0 -127 -77.5 -211.5t-226.5 -108.5v-6q175 -26 257.5 -110.5t82.5 -235.5q0 -202 -134 -311t-380 -109h-448v1462zM309 811h322q206 0 299.5 68.5t93.5 214.5t-105.5 212t-314.5 66h-295v-561zM309 721v-631h344q406 0 406 330
|
||||
q0 301 -428 301h-322z" />
|
||||
<glyph glyph-name="C" unicode="C" horiz-adv-x="1272"
|
||||
d="M831 1391q-275 0 -433 -176t-158 -482q0 -313 149 -486t426 -173q184 0 338 47v-90q-145 -51 -362 -51q-308 0 -485 199t-177 556q0 223 84.5 393t243 262.5t368.5 92.5q214 0 383 -80l-41 -92q-160 80 -336 80z" />
|
||||
<glyph glyph-name="D" unicode="D" horiz-adv-x="1446"
|
||||
d="M1317 745q0 -368 -193 -556.5t-567 -188.5h-350v1462h395q350 0 532.5 -183t182.5 -534zM1206 741q0 314 -159.5 472.5t-468.5 158.5h-269v-1282h242q655 0 655 651z" />
|
||||
<glyph glyph-name="E" unicode="E" horiz-adv-x="1130"
|
||||
d="M1006 0h-799v1462h799v-94h-697v-553h658v-94h-658v-627h697v-94z" />
|
||||
<glyph glyph-name="F" unicode="F" horiz-adv-x="1028"
|
||||
d="M309 0h-102v1462h801v-94h-699v-620h660v-95h-660v-653z" />
|
||||
<glyph glyph-name="G" unicode="G" horiz-adv-x="1481"
|
||||
d="M782 737h539v-667q-212 -90 -477 -90q-346 0 -530.5 195.5t-184.5 553.5q0 223 91.5 395.5t262 266.5t391.5 94q239 0 429 -88l-41 -92q-190 88 -394 88q-289 0 -458.5 -178.5t-169.5 -481.5q0 -330 161 -496.5t473 -166.5q202 0 343 57v514h-435v96z" />
|
||||
<glyph glyph-name="H" unicode="H" horiz-adv-x="1473"
|
||||
d="M1266 0h-103v719h-854v-719h-102v1462h102v-649h854v649h103v-1462z" />
|
||||
<glyph glyph-name="J" unicode="J" horiz-adv-x="506"
|
||||
d="M-33 -369q-92 0 -151 27v88q78 -20 149 -20q242 0 242 264v1472h102v-1462q0 -369 -342 -369z" />
|
||||
<glyph glyph-name="K" unicode="K" horiz-adv-x="1190"
|
||||
d="M1190 0h-125l-561 772l-195 -172v-600h-102v1462h102v-760l162 162l573 598h130l-599 -618z" />
|
||||
<glyph glyph-name="L" unicode="L" horiz-adv-x="1051"
|
||||
d="M207 0v1462h102v-1366h697v-96h-799z" />
|
||||
<glyph glyph-name="M" unicode="M" horiz-adv-x="1767"
|
||||
d="M850 0l-545 1350h-8q8 -124 8 -254v-1096h-98v1462h158l518 -1286h6l518 1286h154v-1462h-103v1108q0 116 12 240h-8l-547 -1348h-65z" />
|
||||
<glyph glyph-name="N" unicode="N" horiz-adv-x="1477"
|
||||
d="M1270 0h-103l-866 1298h-8q12 -232 12 -350v-948h-98v1462h102l865 -1296h6q-9 180 -9 342v954h99v-1462z" />
|
||||
<glyph glyph-name="O" unicode="O" horiz-adv-x="1565"
|
||||
d="M1436 733q0 -348 -174 -550.5t-480 -202.5q-305 0 -479 202.5t-174 552.5q0 349 175.5 549.5t479.5 200.5q306 0 479 -201.5t173 -550.5zM240 733q0 -314 140 -485.5t402 -171.5q264 0 403.5 170t139.5 487q0 316 -139.5 484.5t-401.5 168.5q-261 0 -402.5 -170
|
||||
t-141.5 -483z" />
|
||||
<glyph glyph-name="P" unicode="P" horiz-adv-x="1198"
|
||||
d="M1087 1042q0 -212 -144 -325t-408 -113h-226v-604h-102v1462h358q522 0 522 -420zM309 692h201q247 0 357 81.5t110 264.5q0 169 -104 250.5t-322 81.5h-242v-678z" />
|
||||
<glyph glyph-name="Q" unicode="Q" horiz-adv-x="1565"
|
||||
d="M1436 733q0 -294 -126 -486.5t-349 -246.5l333 -348h-166l-282 330l-33 -2h-31q-305 0 -479 202.5t-174 552.5q0 349 175.5 549.5t479.5 200.5q306 0 479 -201.5t173 -550.5zM240 733q0 -314 140 -485.5t402 -171.5q264 0 403.5 170t139.5 487q0 316 -139.5 484.5
|
||||
t-401.5 168.5q-261 0 -402.5 -170t-141.5 -483z" />
|
||||
<glyph glyph-name="R" unicode="R" horiz-adv-x="1217"
|
||||
d="M309 637v-637h-102v1462h348q272 0 402 -100.5t130 -302.5q0 -147 -77.5 -248t-235.5 -145l397 -666h-122l-377 637h-363zM309 725h279q185 0 287 82.5t102 243.5q0 167 -100 243t-326 76h-242v-645z" />
|
||||
<glyph glyph-name="S" unicode="S" horiz-adv-x="1116"
|
||||
d="M1014 377q0 -183 -134.5 -290t-357.5 -107q-268 0 -411 59v102q158 -67 403 -67q180 0 285.5 82.5t105.5 216.5q0 83 -35 137.5t-114 99.5t-232 97q-224 77 -309.5 166.5t-85.5 238.5q0 164 128.5 267.5t330.5 103.5q206 0 387 -78l-37 -88q-182 76 -348 76
|
||||
q-162 0 -258 -75t-96 -204q0 -81 29.5 -133t96.5 -93.5t230 -99.5q171 -59 257 -114.5t125.5 -126t39.5 -170.5z" />
|
||||
<glyph glyph-name="T" unicode="T" horiz-adv-x="1073"
|
||||
d="M588 0h-103v1366h-475v96h1053v-96h-475v-1366z" />
|
||||
<glyph glyph-name="U" unicode="U" horiz-adv-x="1473"
|
||||
d="M1282 1462v-946q0 -252 -146 -394t-407 -142q-254 0 -396.5 142.5t-142.5 397.5v942h103v-946q0 -211 117 -328.5t331 -117.5q209 0 324 115.5t115 320.5v956h102z" />
|
||||
<glyph glyph-name="V" unicode="V" horiz-adv-x="1182"
|
||||
d="M1071 1462h111l-547 -1462h-90l-545 1462h109l368 -995q84 -225 113 -338q20 75 79 233z" />
|
||||
<glyph glyph-name="W" unicode="W" horiz-adv-x="1827"
|
||||
d="M1372 0h-84l-321 1128q-40 139 -60 228q-16 -87 -45.5 -200t-322.5 -1156h-86l-402 1462h107l256 -942q15 -57 28 -105.5t23.5 -91t19 -82t15.5 -79.5q24 136 102 413l250 887h113l293 -1018q51 -176 73 -284q13 72 33.5 153t308.5 1149h103z" />
|
||||
<glyph glyph-name="X" unicode="X" horiz-adv-x="1102"
|
||||
d="M1102 0h-117l-432 682l-440 -682h-113l492 762l-447 700h115l395 -626l401 626h109l-453 -698z" />
|
||||
<glyph glyph-name="Y" unicode="Y" horiz-adv-x="1081"
|
||||
d="M543 662l428 800h110l-487 -897v-565h-105v557l-489 905h117z" />
|
||||
<glyph glyph-name="Z" unicode="Z" horiz-adv-x="1180"
|
||||
d="M1098 0h-1016v76l856 1290h-817v96h954v-76l-858 -1290h881v-96z" />
|
||||
<glyph glyph-name="bracketleft" unicode="[" horiz-adv-x="653"
|
||||
d="M602 -324h-428v1786h428v-94h-330v-1597h330v-95z" />
|
||||
<glyph glyph-name="backslash" unicode="\" horiz-adv-x="698"
|
||||
d="M127 1462l547 -1462h-103l-546 1462h102z" />
|
||||
<glyph glyph-name="bracketright" unicode="]" horiz-adv-x="653"
|
||||
d="M51 -229h330v1597h-330v94h428v-1786h-428v95z" />
|
||||
<glyph glyph-name="asciicircum" unicode="^"
|
||||
d="M88 561l465 912h68l460 -912h-100l-395 791l-398 -791h-100z" />
|
||||
<glyph glyph-name="underscore" unicode="_" horiz-adv-x="842"
|
||||
d="M846 -266h-850v82h850v-82z" />
|
||||
<glyph glyph-name="grave" unicode="`" horiz-adv-x="1182"
|
||||
d="M776 1241h-69q-96 79 -188.5 171.5t-125.5 139.5v17h142q26 -48 98.5 -142t142.5 -170v-16z" />
|
||||
<glyph glyph-name="a" unicode="a" horiz-adv-x="1085"
|
||||
d="M842 0l-25 172h-8q-82 -105 -168.5 -148.5t-204.5 -43.5q-160 0 -249 82t-89 227q0 159 132.5 247t383.5 93l207 6v72q0 155 -63 234t-203 79q-151 0 -313 -84l-37 86q179 84 354 84q179 0 267.5 -93t88.5 -290v-723h-73zM442 70q174 0 274.5 99.5t100.5 276.5v107
|
||||
l-190 -8q-229 -11 -326.5 -71.5t-97.5 -188.5q0 -102 62.5 -158.5t176.5 -56.5z" />
|
||||
<glyph glyph-name="b" unicode="b" horiz-adv-x="1219"
|
||||
d="M641 1108q228 0 343.5 -143.5t115.5 -419.5q0 -271 -121.5 -418t-341.5 -147q-116 0 -209 48t-147 136h-9l-28 -164h-62v1556h99v-391q0 -88 -4 -162l-3 -85h7q62 98 149.5 144t210.5 46zM639 1018q-192 0 -275 -110t-83 -363v-17q0 -246 86.5 -353t269.5 -107
|
||||
q178 0 268 124.5t90 354.5q0 471 -356 471z" />
|
||||
<glyph glyph-name="c" unicode="c" horiz-adv-x="973"
|
||||
d="M616 -20q-233 0 -365 147t-132 410q0 270 137 420.5t375 150.5q141 0 270 -49l-27 -88q-141 47 -245 47q-200 0 -303 -123.5t-103 -355.5q0 -220 103 -344.5t288 -124.5q148 0 275 53v-92q-104 -51 -273 -51z" />
|
||||
<glyph glyph-name="d" unicode="d" horiz-adv-x="1219"
|
||||
d="M580 1108q118 0 204 -43t154 -147h6q-6 126 -6 247v391h98v-1556h-65l-25 166h-8q-124 -186 -356 -186q-225 0 -344 140t-119 408q0 282 118 431t343 149zM580 1018q-178 0 -267.5 -125t-89.5 -363q0 -462 359 -462q184 0 270 107t86 353v17q0 252 -84.5 362.5
|
||||
t-273.5 110.5z" />
|
||||
<glyph glyph-name="e" unicode="e" horiz-adv-x="1124"
|
||||
d="M621 -20q-237 0 -369.5 146t-132.5 409q0 260 128 416.5t345 156.5q192 0 303 -134t111 -364v-80h-783q2 -224 104.5 -342t293.5 -118q93 0 163.5 13t178.5 56v-90q-92 -40 -170 -54.5t-172 -14.5zM592 1020q-157 0 -252 -103.5t-111 -298.5h672q0 189 -82 295.5
|
||||
t-227 106.5z" />
|
||||
<glyph glyph-name="f" unicode="f" horiz-adv-x="614"
|
||||
d="M586 1001h-256v-1001h-99v1001h-202v58l202 37v84q0 200 73.5 293.5t240.5 93.5q90 0 180 -27l-23 -86q-80 25 -159 25q-116 0 -164.5 -68.5t-48.5 -222.5v-101h256v-86z" />
|
||||
<glyph glyph-name="g" unicode="g" horiz-adv-x="1071"
|
||||
d="M1030 1087v-69l-225 -14q90 -112 90 -246q0 -157 -104.5 -254.5t-280.5 -97.5q-74 0 -104 6q-59 -31 -90 -73t-31 -89q0 -52 39.5 -76t132.5 -24h190q177 0 271 -71.5t94 -211.5q0 -172 -139.5 -265.5t-397.5 -93.5q-205 0 -317.5 79t-112.5 220q0 112 69.5 186
|
||||
t188.5 101q-49 21 -78.5 59.5t-29.5 88.5q0 109 139 192q-95 39 -148 122.5t-53 191.5q0 163 103.5 261.5t279.5 98.5q107 0 166 -21h348zM150 -184q0 -224 333 -224q428 0 428 273q0 98 -67 142t-217 44h-178q-299 0 -299 -235zM233 748q0 -126 76.5 -195.5t204.5 -69.5
|
||||
q136 0 208.5 69t72.5 200q0 139 -74.5 208.5t-208.5 69.5q-130 0 -204.5 -74.5t-74.5 -207.5z" />
|
||||
<glyph glyph-name="h" unicode="h" horiz-adv-x="1208"
|
||||
d="M940 0v705q0 164 -69 238.5t-214 74.5q-195 0 -285.5 -98.5t-90.5 -319.5v-600h-99v1556h99v-495l-5 -139h7q61 98 154 142t231 44q370 0 370 -397v-711h-98z" />
|
||||
<glyph glyph-name="i" unicode="i" horiz-adv-x="463"
|
||||
d="M281 0h-99v1087h99v-1087zM168 1389q0 96 63 96q31 0 48.5 -25t17.5 -71q0 -45 -17.5 -71t-48.5 -26q-63 0 -63 97z" />
|
||||
<glyph glyph-name="j" unicode="j" horiz-adv-x="463"
|
||||
d="M37 -492q-80 0 -135 25v86q69 -20 129 -20q151 0 151 176v1312h99v-1298q0 -135 -63.5 -208t-180.5 -73zM168 1389q0 96 63 96q31 0 48.5 -25t17.5 -71q0 -45 -17.5 -71t-48.5 -26q-63 0 -63 97z" />
|
||||
<glyph glyph-name="k" unicode="k" horiz-adv-x="991"
|
||||
d="M279 477l555 610h120l-428 -464l465 -623h-119l-413 549l-178 -162v-387h-99v1556h99v-780l-7 -299h5z" />
|
||||
<glyph glyph-name="l" unicode="l" horiz-adv-x="463"
|
||||
d="M281 0h-99v1556h99v-1556z" />
|
||||
<glyph glyph-name="m" unicode="m" horiz-adv-x="1808"
|
||||
d="M1540 0v713q0 159 -62 232t-190 73q-167 0 -247 -92t-80 -289v-637h-101v743q0 275 -252 275q-171 0 -249 -99.5t-78 -318.5v-600h-99v1087h82l21 -149h6q45 81 128 125.5t183 44.5q257 0 330 -193h4q53 93 142.5 143t203.5 50q178 0 267 -95t89 -302v-711h-98z" />
|
||||
<glyph glyph-name="n" unicode="n" horiz-adv-x="1208"
|
||||
d="M940 0v705q0 164 -69 238.5t-214 74.5q-195 0 -285.5 -98.5t-90.5 -319.5v-600h-99v1087h84l19 -149h6q106 170 377 170q370 0 370 -397v-711h-98z" />
|
||||
<glyph glyph-name="o" unicode="o" horiz-adv-x="1200"
|
||||
d="M1081 545q0 -266 -129 -415.5t-356 -149.5q-143 0 -252 69t-167 198t-58 298q0 266 129 414.5t354 148.5q224 0 351.5 -150.5t127.5 -412.5zM223 545q0 -224 98.5 -349.5t278.5 -125.5t278.5 125.5t98.5 349.5q0 225 -99.5 349t-279.5 124t-277.5 -123.5t-97.5 -349.5z
|
||||
" />
|
||||
<glyph glyph-name="p" unicode="p" horiz-adv-x="1219"
|
||||
d="M647 -20q-251 0 -366 188h-7l3 -84q4 -74 4 -162v-414h-99v1579h84l19 -155h6q112 176 358 176q220 0 335.5 -144.5t115.5 -420.5q0 -268 -121.5 -415.5t-331.5 -147.5zM645 68q167 0 258.5 124t91.5 347q0 479 -346 479q-190 0 -279 -104.5t-89 -340.5v-32
|
||||
q0 -255 85.5 -364t278.5 -109z" />
|
||||
<glyph glyph-name="q" unicode="q" horiz-adv-x="1219"
|
||||
d="M569 -20q-214 0 -332 142t-118 410q0 275 118 425.5t338 150.5q236 0 353 -174h6l18 153h84v-1579h-98v414q0 122 6 248h-6q-118 -190 -369 -190zM571 68q198 0 282.5 109t84.5 366v12q0 245 -85 354t-271 109q-176 0 -267.5 -124t-91.5 -364q0 -229 89.5 -345.5
|
||||
t258.5 -116.5z" />
|
||||
<glyph glyph-name="r" unicode="r" horiz-adv-x="797"
|
||||
d="M610 1108q69 0 148 -14l-19 -95q-68 17 -141 17q-139 0 -228 -118t-89 -298v-600h-99v1087h84l10 -196h7q67 120 143 168.5t184 48.5z" />
|
||||
<glyph glyph-name="s" unicode="s" horiz-adv-x="954"
|
||||
d="M856 283q0 -146 -111 -224.5t-315 -78.5q-218 0 -346 67v107q164 -82 346 -82q161 0 244.5 53.5t83.5 142.5q0 82 -66.5 138t-218.5 110q-163 59 -229 101.5t-99.5 96t-33.5 130.5q0 122 102.5 193t286.5 71q176 0 334 -66l-37 -90q-160 66 -297 66q-133 0 -211 -44
|
||||
t-78 -122q0 -85 60.5 -136t236.5 -114q147 -53 214 -95.5t100.5 -96.5t33.5 -127z" />
|
||||
<glyph glyph-name="t" unicode="t" horiz-adv-x="686"
|
||||
d="M469 68q94 0 164 16v-80q-72 -24 -166 -24q-144 0 -212.5 77t-68.5 242v702h-161v58l161 45l50 246h51v-263h319v-86h-319v-688q0 -125 44 -185t138 -60z" />
|
||||
<glyph glyph-name="u" unicode="u" horiz-adv-x="1208"
|
||||
d="M268 1087v-704q0 -164 69 -238.5t214 -74.5q194 0 285.5 98t91.5 319v600h98v-1087h-84l-18 150h-6q-106 -170 -377 -170q-371 0 -371 397v710h98z" />
|
||||
<glyph glyph-name="v" unicode="v" horiz-adv-x="940"
|
||||
d="M420 0l-420 1087h102l281 -739q56 -142 84 -248h6q41 136 84 250l281 737h102l-420 -1087h-100z" />
|
||||
<glyph glyph-name="w" unicode="w" horiz-adv-x="1481"
|
||||
d="M1051 0l-238 727q-23 74 -59 217h-6l-21 -74l-45 -145l-242 -725h-98l-311 1087h106l174 -630q61 -234 80 -344h6q59 234 86 311l224 663h90l213 -661q72 -235 88 -311h6q8 65 80 348l166 624h100l-295 -1087h-104z" />
|
||||
<glyph glyph-name="x" unicode="x" horiz-adv-x="1020"
|
||||
d="M449 559l-379 528h114l324 -458l321 458h109l-373 -528l400 -559h-115l-342 485l-344 -485h-109z" />
|
||||
<glyph glyph-name="y" unicode="y" horiz-adv-x="940"
|
||||
d="M0 1087h102l230 -610q105 -281 133 -379h6q42 129 137 385l230 604h102l-487 -1263q-59 -154 -99 -208t-93.5 -81t-129.5 -27q-57 0 -127 21v86q58 -16 125 -16q51 0 90 24t70.5 74.5t73 160t53.5 142.5z" />
|
||||
<glyph glyph-name="z" unicode="z" horiz-adv-x="944"
|
||||
d="M858 0h-776v63l645 936h-598v88h727v-63l-649 -936h651v-88z" />
|
||||
<glyph glyph-name="braceleft" unicode="{" horiz-adv-x="723"
|
||||
d="M389 -27q0 -102 59.5 -152.5t202.5 -53.5v-91q-195 0 -277.5 75t-82.5 231v337q0 205 -230 209v80q122 2 176 51t54 148v350q0 299 360 305v-90q-138 -5 -200 -58t-62 -157v-305q0 -130 -44 -194t-142 -85v-8q97 -20 141.5 -83.5t44.5 -186.5v-322z" />
|
||||
<glyph glyph-name="bar" unicode="|" horiz-adv-x="1108"
|
||||
d="M508 1561h92v-2067h-92v2067z" />
|
||||
<glyph glyph-name="braceright" unicode="}" horiz-adv-x="723"
|
||||
d="M334 295q0 123 44.5 186.5t141.5 83.5v8q-97 20 -141.5 84t-44.5 195v305q0 103 -61.5 156.5t-200.5 58.5v90q174 0 267 -77.5t93 -227.5v-350q0 -100 54.5 -148.5t175.5 -50.5v-80q-230 -4 -230 -209v-337q0 -155 -82.5 -230.5t-277.5 -75.5v91q141 2 201.5 52.5
|
||||
t60.5 153.5v322z" />
|
||||
<glyph glyph-name="asciitilde" unicode="~"
|
||||
d="M334 745q-49 0 -108 -30.5t-115 -89.5v94q108 110 233 110q61 0 115 -13.5t155 -57.5q126 -58 220 -58q56 0 109.5 30.5t115.5 94.5v-96q-48 -49 -104.5 -81t-129.5 -32q-116 0 -270 72q-124 57 -221 57z" />
|
||||
<glyph glyph-name="nonbreakingspace" unicode=" " horiz-adv-x="532"
|
||||
/>
|
||||
<glyph glyph-name="exclamdown" unicode="¡" horiz-adv-x="492"
|
||||
d="M215 711h61l29 -1086h-119zM166 1010q0 98 80 98q82 0 82 -98q0 -53 -23.5 -76t-58.5 -23q-34 0 -57 23t-23 76z" />
|
||||
<glyph glyph-name="cent" unicode="¢"
|
||||
d="M602 190q-186 30 -288.5 175t-102.5 380q0 232 102.5 381.5t288.5 182.5v174h82v-166h14q131 0 275 -55l-31 -84q-134 51 -237 51q-187 0 -288.5 -122.5t-101.5 -358.5q0 -225 100.5 -349.5t280.5 -124.5q131 0 267 58v-92q-110 -56 -267 -56h-12v-204h-82v210z" />
|
||||
<glyph glyph-name="sterling" unicode="£"
|
||||
d="M412 676v-256q0 -116 -35 -196t-113 -128h809v-96h-995v84q110 21 171.5 110t61.5 224v258h-211v82h211v297q0 204 98 315t281 111q175 0 330 -68l-35 -86q-157 66 -295 66q-141 0 -209.5 -81t-68.5 -253v-301h411v-82h-411z" />
|
||||
<glyph glyph-name="currency" unicode="¤"
|
||||
d="M991 723q0 -151 -90 -256l139 -141l-59 -60l-137 142q-110 -93 -260 -93q-153 0 -260 93l-138 -142l-59 60l139 141q-90 106 -90 256q0 147 90 258l-139 141l59 60l138 -142q103 93 260 93q155 0 260 -93l137 142l59 -60l-139 -141q90 -111 90 -258zM584 395
|
||||
q134 0 228.5 95.5t94.5 232.5q0 136 -95 233t-228 97q-134 0 -229 -97t-95 -233t94.5 -232t229.5 -96z" />
|
||||
<glyph glyph-name="yen" unicode="¥"
|
||||
d="M586 666l428 796h110l-432 -788h283v-82h-338v-205h338v-82h-338v-305h-105v305h-337v82h337v205h-337v82h278l-430 788h117z" />
|
||||
<glyph glyph-name="brokenbar" unicode="¦" horiz-adv-x="1108"
|
||||
d="M508 1561h92v-764h-92v764zM508 258h92v-764h-92v764z" />
|
||||
<glyph glyph-name="section" unicode="§" horiz-adv-x="1057"
|
||||
d="M145 813q0 83 50.5 152.5t138.5 107.5q-86 47 -125 102t-39 136q0 117 101.5 183.5t275.5 66.5q175 0 336 -64l-35 -80q-91 34 -158.5 47t-144.5 13q-134 0 -205.5 -44.5t-71.5 -119.5q0 -54 25.5 -88.5t85.5 -65.5t188 -74q192 -64 264 -132.5t72 -170.5
|
||||
q0 -173 -186 -274q86 -42 129 -96t43 -136q0 -135 -113 -207.5t-311 -72.5q-92 0 -171 15t-165 52v95q182 -78 332 -78q162 0 247 49.5t85 140.5q0 55 -25 87.5t-88.5 65.5t-190.5 79q-200 73 -272 141.5t-72 169.5zM246 825q0 -65 31.5 -104t105.5 -75t250 -99
|
||||
q82 41 126 98t44 121q0 62 -32 102t-108.5 77t-236.5 87q-81 -23 -130.5 -79t-49.5 -128z" />
|
||||
<glyph glyph-name="dieresis" unicode="¨" horiz-adv-x="1182"
|
||||
d="M336 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86zM717 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86z" />
|
||||
<glyph glyph-name="copyright" unicode="©" horiz-adv-x="1704"
|
||||
d="M897 1092q-142 0 -222.5 -94.5t-80.5 -264.5q0 -186 74.5 -275t220.5 -89q84 0 198 43v-88q-102 -45 -208 -45q-187 0 -288.5 115t-101.5 331q0 208 111 332.5t297 124.5q119 0 227 -52l-37 -83q-98 45 -190 45zM100 731q0 200 100 375t275 276t377 101q200 0 375 -100
|
||||
t276 -275t101 -377q0 -197 -97 -370t-272 -277t-383 -104q-207 0 -382 103.5t-272.5 276.5t-97.5 371zM193 731q0 -178 88.5 -329.5t240.5 -240.5t330 -89t329.5 88.5t240.5 240.5t89 330q0 174 -85.5 325t-239 243t-334.5 92q-176 0 -328.5 -88.5t-241.5 -242.5t-89 -329z
|
||||
" />
|
||||
<glyph glyph-name="ordfeminine" unicode="ª" horiz-adv-x="686"
|
||||
d="M512 813l-25 72q-84 -84 -202 -84q-95 0 -151 49t-56 139q0 100 80 151.5t241 59.5l95 4v43q0 77 -38 114.5t-106 37.5q-87 0 -196 -49l-33 73q117 56 231 56q228 0 228 -215v-451h-68zM168 993q0 -54 35 -85t96 -31q90 0 142.5 50t52.5 142v64l-88 -5
|
||||
q-116 -6 -177 -36.5t-61 -98.5z" />
|
||||
<glyph glyph-name="guillemotleft" unicode="«" horiz-adv-x="885"
|
||||
d="M82 543l309 393l62 -43l-254 -363l254 -362l-62 -43l-309 391v27zM442 543l310 393l61 -43l-254 -363l254 -362l-61 -43l-310 391v27z" />
|
||||
<glyph glyph-name="logicalnot" unicode="¬"
|
||||
d="M1038 764v-494h-82v412h-845v82h927z" />
|
||||
<glyph glyph-name="uni00AD" unicode="­" horiz-adv-x="659"
|
||||
d="M92 512v82h475v-82h-475z" />
|
||||
<glyph glyph-name="registered" unicode="®" horiz-adv-x="1704"
|
||||
d="M709 731h112q91 0 143 46.5t52 135.5q0 172 -197 172h-110v-354zM1120 918q0 -79 -38.5 -139.5t-110.5 -94.5l237 -393h-121l-210 360h-168v-360h-101v880h211q143 0 222 -62t79 -191zM100 731q0 200 100 375t275 276t377 101q200 0 375 -100t276 -275t101 -377
|
||||
q0 -197 -97 -370t-272 -277t-383 -104q-207 0 -382 103.5t-272.5 276.5t-97.5 371zM193 731q0 -178 88.5 -329.5t240.5 -240.5t330 -89t329.5 88.5t240.5 240.5t89 330q0 174 -85.5 325t-239 243t-334.5 92q-176 0 -328.5 -88.5t-241.5 -242.5t-89 -329z" />
|
||||
<glyph glyph-name="overscore" unicode="¯" horiz-adv-x="1024"
|
||||
d="M1030 1556h-1036v82h1036v-82z" />
|
||||
<glyph glyph-name="degree" unicode="°" horiz-adv-x="877"
|
||||
d="M139 1184q0 132 86.5 215.5t212.5 83.5t212.5 -83.5t86.5 -215.5t-86.5 -215.5t-212.5 -83.5q-130 0 -214.5 83t-84.5 216zM229 1184q0 -91 61 -154t148 -63q86 0 147.5 62t61.5 155q0 92 -60 154.5t-149 62.5q-90 0 -149.5 -64t-59.5 -153z" />
|
||||
<glyph glyph-name="plusminus" unicode="±"
|
||||
d="M111 1v82h948v-82h-948zM625 764h434v-82h-434v-432h-82v432h-432v82h432v434h82v-434z" />
|
||||
<glyph glyph-name="twosuperior" unicode="²" horiz-adv-x="688"
|
||||
d="M629 586h-576v78l242 237q125 121 172 193t47 149q0 71 -46.5 112.5t-123.5 41.5q-108 0 -217 -82l-49 65q119 103 270 103q124 0 194 -63.5t70 -174.5q0 -47 -13 -89t-40 -85.5t-68.5 -90t-308.5 -306.5h447v-88z" />
|
||||
<glyph glyph-name="threesuperior" unicode="³" horiz-adv-x="688"
|
||||
d="M616 1260q0 -78 -44 -131.5t-117 -75.5q186 -45 186 -211q0 -130 -88.5 -201.5t-247.5 -71.5q-144 0 -264 60v88q136 -62 266 -62q115 0 174.5 49t59.5 136q0 83 -59.5 122t-178.5 39h-131v84h135q105 0 158 43.5t53 120.5q0 67 -47 107.5t-127 40.5q-128 0 -246 -78
|
||||
l-47 70q130 94 293 94q127 0 199.5 -60t72.5 -163z" />
|
||||
<glyph glyph-name="acute" unicode="´" horiz-adv-x="1182"
|
||||
d="M393 1257q73 79 144.5 171.5t97.5 140.5h141v-17q-36 -52 -122.5 -138t-190.5 -173h-70v16z" />
|
||||
<glyph glyph-name="mu" unicode="µ" horiz-adv-x="1221"
|
||||
d="M281 1087v-704q0 -164 69 -238.5t213 -74.5q194 0 285.5 98t91.5 319v600h98v-1087h-84l-18 150h-6q-50 -77 -150 -123.5t-217 -46.5q-99 0 -167.5 27.5t-119.5 84.5q5 -92 5 -170v-414h-99v1579h99z" />
|
||||
<glyph glyph-name="paragraph" unicode="¶" horiz-adv-x="1341"
|
||||
d="M1106 -260h-100v1722h-228v-1722h-100v819q-64 -18 -146 -18q-216 0 -317.5 125t-101.5 376q0 260 109 387t341 127h543v-1816z" />
|
||||
<glyph glyph-name="periodcentered" unicode="·" horiz-adv-x="487"
|
||||
d="M162 721q0 98 80 98q82 0 82 -98t-82 -98q-80 0 -80 98z" />
|
||||
<glyph glyph-name="cedilla" unicode="¸" horiz-adv-x="420"
|
||||
d="M393 -291q0 -100 -67.5 -150.5t-188.5 -50.5q-68 0 -94 11v88q30 -10 92 -10q78 0 119 28t41 80q0 94 -193 121l93 174h96l-66 -117q168 -37 168 -174z" />
|
||||
<glyph glyph-name="onesuperior" unicode="¹" horiz-adv-x="688"
|
||||
d="M350 1462h92v-876h-98v547q0 99 12 233q-26 -23 -233 -145l-47 77z" />
|
||||
<glyph glyph-name="ordmasculine" unicode="º" horiz-adv-x="739"
|
||||
d="M670 1141q0 -161 -80 -250.5t-223 -89.5t-220 86t-77 254q0 162 78 250t223 88q142 0 220.5 -87t78.5 -251zM160 1141q0 -264 209 -264t209 264q0 131 -50 194.5t-159 63.5t-159 -63.5t-50 -194.5z" />
|
||||
<glyph glyph-name="guillemotright" unicode="»" horiz-adv-x="885"
|
||||
d="M803 518l-309 -393l-62 43l254 362l-254 363l62 43l309 -391v-27zM442 518l-309 -393l-61 43l254 362l-254 363l61 43l309 -391v-27z" />
|
||||
<glyph glyph-name="onequarter" unicode="¼" horiz-adv-x="1516"
|
||||
d="M1392 242h-129v-241h-90v241h-413v60l407 581h96v-563h129v-78zM1173 320v221q0 132 8 232q-6 -12 -21.5 -35.5t-295.5 -417.5h309zM1148 1462l-811 -1462h-94l811 1462h94zM333 1462h92v-876h-98v547q0 99 12 233q-26 -23 -233 -145l-47 77z" />
|
||||
<glyph glyph-name="onehalf" unicode="½" horiz-adv-x="1516"
|
||||
d="M1073 1462l-811 -1462h-94l811 1462h94zM285 1462h92v-876h-98v547q0 99 12 233q-26 -23 -233 -145l-47 77zM1403 1h-576v78l242 237q125 121 172 193t47 149q0 71 -46.5 112.5t-123.5 41.5q-108 0 -217 -82l-49 65q119 103 270 103q124 0 194 -63.5t70 -174.5
|
||||
q0 -47 -13 -89t-40 -85.5t-68.5 -90t-308.5 -306.5h447v-88z" />
|
||||
<glyph glyph-name="threequarters" unicode="¾" horiz-adv-x="1516"
|
||||
d="M1495 242h-129v-241h-90v241h-413v60l407 581h96v-563h129v-78zM1276 320v221q0 132 8 232q-6 -12 -21.5 -35.5t-295.5 -417.5h309zM1300 1462l-811 -1462h-94l811 1462h94zM616 1260q0 -78 -44 -131.5t-117 -75.5q186 -45 186 -211q0 -130 -88.5 -201.5t-247.5 -71.5
|
||||
q-144 0 -264 60v88q136 -62 266 -62q115 0 174.5 49t59.5 136q0 83 -59.5 122t-178.5 39h-131v84h135q105 0 158 43.5t53 120.5q0 67 -47 107.5t-127 40.5q-128 0 -246 -78l-47 70q130 94 293 94q127 0 199.5 -60t72.5 -163z" />
|
||||
<glyph glyph-name="questiondown" unicode="¿" horiz-adv-x="862"
|
||||
d="M569 711v-37q0 -125 -39.5 -204.5t-136.5 -164.5l-90 -79q-73 -61 -104 -120.5t-31 -138.5q0 -124 82 -200t221 -76q125 0 233 46l64 27l37 -79q-111 -48 -185.5 -64t-152.5 -16q-184 0 -288.5 99t-104.5 269q0 70 20 124t58.5 102t171.5 159q64 53 98.5 98.5t49.5 94
|
||||
t15 145.5v15h82zM440 1010q0 98 80 98q82 0 82 -98q0 -53 -23.5 -76t-58.5 -23q-34 0 -57 23t-23 76z" />
|
||||
<glyph glyph-name="Agrave" unicode="À" horiz-adv-x="1229"
|
||||
d="M911 516h-594l-204 -516h-113l588 1468h65l576 -1468h-115zM354 608h523l-199 527q-25 62 -60 172q-27 -96 -59 -174zM720 1579h-69q-96 79 -188.5 171.5t-125.5 139.5v17h142q26 -48 98.5 -142t142.5 -170v-16z" />
|
||||
<glyph glyph-name="Aacute" unicode="Á" horiz-adv-x="1229"
|
||||
d="M911 516h-594l-204 -516h-113l588 1468h65l576 -1468h-115zM354 608h523l-199 527q-25 62 -60 172q-27 -96 -59 -174zM504 1595q73 79 144.5 171.5t97.5 140.5h141v-17q-36 -52 -122.5 -138t-190.5 -173h-70v16z" />
|
||||
<glyph glyph-name="Acircumflex" unicode="Â" horiz-adv-x="1229"
|
||||
d="M911 516h-594l-204 -516h-113l588 1468h65l576 -1468h-115zM354 608h523l-199 527q-25 62 -60 172q-27 -96 -59 -174zM328 1595q62 67 131.5 156t110.5 156h98q68 -120 242 -312v-16h-70q-122 101 -221 207q-108 -114 -221 -207h-70v16z" />
|
||||
<glyph glyph-name="Atilde" unicode="Ã" horiz-adv-x="1229"
|
||||
d="M911 516h-594l-204 -516h-113l588 1468h65l576 -1468h-115zM354 608h523l-199 527q-25 62 -60 172q-27 -96 -59 -174zM784 1581q-36 0 -75 18.5t-101 71.5q-32 26 -62.5 46t-62.5 20q-45 0 -75 -34.5t-48 -121.5h-73q10 111 63 174.5t137 63.5q48 0 88 -25t82 -59
|
||||
q34 -28 66 -50t61 -22q46 0 77 36.5t48 119.5h76q-16 -116 -69 -177t-132 -61z" />
|
||||
<glyph glyph-name="Adieresis" unicode="Ä" horiz-adv-x="1229"
|
||||
d="M911 516h-594l-204 -516h-113l588 1468h65l576 -1468h-115zM354 608h523l-199 527q-25 62 -60 172q-27 -96 -59 -174zM367 1727q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86zM748 1727q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86z" />
|
||||
<glyph glyph-name="Aring" unicode="Å" horiz-adv-x="1229"
|
||||
d="M836 1610q0 -97 -60 -155t-157 -58t-157 58t-60 155q0 94 60 152.5t157 58.5t157 -59t60 -152zM482 1610q0 -66 37.5 -103.5t99.5 -37.5t99.5 37.5t37.5 103.5q0 64 -39 101.5t-98 37.5q-62 0 -99.5 -38t-37.5 -101zM911 516h-594l-204 -516h-113l588 1468h65l576 -1468
|
||||
h-115zM354 608h523l-199 527q-25 62 -60 172q-27 -96 -59 -174z" />
|
||||
<glyph glyph-name="AE" unicode="Æ" horiz-adv-x="1653"
|
||||
d="M1528 0h-717v516h-475l-227 -516h-111l653 1462h877v-94h-615v-553h576v-94h-576v-627h615v-94zM377 608h434v760h-100z" />
|
||||
<glyph glyph-name="Ccedilla" unicode="Ç" horiz-adv-x="1272"
|
||||
d="M831 1391q-275 0 -433 -176t-158 -482q0 -313 149 -486t426 -173q184 0 338 47v-90q-145 -51 -362 -51q-308 0 -485 199t-177 556q0 223 84.5 393t243 262.5t368.5 92.5q214 0 383 -80l-41 -92q-160 80 -336 80zM911 -291q0 -100 -67.5 -150.5t-188.5 -50.5q-68 0 -94 11
|
||||
v88q30 -10 92 -10q78 0 119 28t41 80q0 94 -193 121l93 174h96l-66 -117q168 -37 168 -174z" />
|
||||
<glyph glyph-name="Egrave" unicode="È" horiz-adv-x="1130"
|
||||
d="M1006 0h-799v1462h799v-94h-697v-553h658v-94h-658v-627h697v-94zM697 1579h-69q-96 79 -188.5 171.5t-125.5 139.5v17h142q26 -48 98.5 -142t142.5 -170v-16z" />
|
||||
<glyph glyph-name="Eacute" unicode="É" horiz-adv-x="1130"
|
||||
d="M1006 0h-799v1462h799v-94h-697v-553h658v-94h-658v-627h697v-94zM463 1595q73 79 144.5 171.5t97.5 140.5h141v-17q-36 -52 -122.5 -138t-190.5 -173h-70v16z" />
|
||||
<glyph glyph-name="Ecircumflex" unicode="Ê" horiz-adv-x="1130"
|
||||
d="M1006 0h-799v1462h799v-94h-697v-553h658v-94h-658v-627h697v-94zM315 1595q62 67 131.5 156t110.5 156h98q68 -120 242 -312v-16h-70q-122 101 -221 207q-108 -114 -221 -207h-70v16z" />
|
||||
<glyph glyph-name="Edieresis" unicode="Ë" horiz-adv-x="1130"
|
||||
d="M1006 0h-799v1462h799v-94h-697v-553h658v-94h-658v-627h697v-94zM354 1727q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86zM735 1727q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86z" />
|
||||
<glyph glyph-name="Eth" unicode="Ð" horiz-adv-x="1466"
|
||||
d="M1317 745q0 -368 -193 -556.5t-567 -188.5h-350v678h-160v94h160v690h395q350 0 532.5 -183t182.5 -534zM1206 741q0 314 -159.5 472.5t-468.5 158.5h-269v-600h406v-94h-406v-588h242q655 0 655 651z" />
|
||||
<glyph glyph-name="Ntilde" unicode="Ñ" horiz-adv-x="1477"
|
||||
d="M1270 0h-103l-866 1298h-8q12 -232 12 -350v-948h-98v1462h102l865 -1296h6q-9 180 -9 342v954h99v-1462zM897 1581q-36 0 -75 18.5t-101 71.5q-32 26 -62.5 46t-62.5 20q-45 0 -75 -34.5t-48 -121.5h-73q10 111 63 174.5t137 63.5q48 0 88 -25t82 -59q34 -28 66 -50
|
||||
t61 -22q46 0 77 36.5t48 119.5h76q-16 -116 -69 -177t-132 -61z" />
|
||||
<glyph glyph-name="Ograve" unicode="Ò" horiz-adv-x="1565"
|
||||
d="M1436 733q0 -348 -174 -550.5t-480 -202.5q-305 0 -479 202.5t-174 552.5q0 349 175.5 549.5t479.5 200.5q306 0 479 -201.5t173 -550.5zM240 733q0 -314 140 -485.5t402 -171.5q264 0 403.5 170t139.5 487q0 316 -139.5 484.5t-401.5 168.5q-261 0 -402.5 -170
|
||||
t-141.5 -483zM885 1579h-69q-96 79 -188.5 171.5t-125.5 139.5v17h142q26 -48 98.5 -142t142.5 -170v-16z" />
|
||||
<glyph glyph-name="Oacute" unicode="Ó" horiz-adv-x="1565"
|
||||
d="M1436 733q0 -348 -174 -550.5t-480 -202.5q-305 0 -479 202.5t-174 552.5q0 349 175.5 549.5t479.5 200.5q306 0 479 -201.5t173 -550.5zM240 733q0 -314 140 -485.5t402 -171.5q264 0 403.5 170t139.5 487q0 316 -139.5 484.5t-401.5 168.5q-261 0 -402.5 -170
|
||||
t-141.5 -483zM686 1595q73 79 144.5 171.5t97.5 140.5h141v-17q-36 -52 -122.5 -138t-190.5 -173h-70v16z" />
|
||||
<glyph glyph-name="Ocircumflex" unicode="Ô" horiz-adv-x="1565"
|
||||
d="M1436 733q0 -348 -174 -550.5t-480 -202.5q-305 0 -479 202.5t-174 552.5q0 349 175.5 549.5t479.5 200.5q306 0 479 -201.5t173 -550.5zM240 733q0 -314 140 -485.5t402 -171.5q264 0 403.5 170t139.5 487q0 316 -139.5 484.5t-401.5 168.5q-261 0 -402.5 -170
|
||||
t-141.5 -483zM492 1595q62 67 131.5 156t110.5 156h98q68 -120 242 -312v-16h-70q-122 101 -221 207q-108 -114 -221 -207h-70v16z" />
|
||||
<glyph glyph-name="Otilde" unicode="Õ" horiz-adv-x="1565"
|
||||
d="M1436 733q0 -348 -174 -550.5t-480 -202.5q-305 0 -479 202.5t-174 552.5q0 349 175.5 549.5t479.5 200.5q306 0 479 -201.5t173 -550.5zM240 733q0 -314 140 -485.5t402 -171.5q264 0 403.5 170t139.5 487q0 316 -139.5 484.5t-401.5 168.5q-261 0 -402.5 -170
|
||||
t-141.5 -483zM940 1581q-36 0 -75 18.5t-101 71.5q-32 26 -62.5 46t-62.5 20q-45 0 -75 -34.5t-48 -121.5h-73q10 111 63 174.5t137 63.5q48 0 88 -25t82 -59q34 -28 66 -50t61 -22q46 0 77 36.5t48 119.5h76q-16 -116 -69 -177t-132 -61z" />
|
||||
<glyph glyph-name="Odieresis" unicode="Ö" horiz-adv-x="1565"
|
||||
d="M1436 733q0 -348 -174 -550.5t-480 -202.5q-305 0 -479 202.5t-174 552.5q0 349 175.5 549.5t479.5 200.5q306 0 479 -201.5t173 -550.5zM240 733q0 -314 140 -485.5t402 -171.5q264 0 403.5 170t139.5 487q0 316 -139.5 484.5t-401.5 168.5q-261 0 -402.5 -170
|
||||
t-141.5 -483zM529 1727q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86zM910 1727q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86z" />
|
||||
<glyph glyph-name="multiply" unicode="×"
|
||||
d="M584 780l409 408l58 -58l-408 -407l406 -408l-58 -57l-407 408l-406 -408l-57 57l405 408l-407 407l57 58z" />
|
||||
<glyph glyph-name="Oslash" unicode="Ø" horiz-adv-x="1565"
|
||||
d="M1436 733q0 -348 -174 -550.5t-480 -202.5q-236 0 -395 120l-86 -120l-74 59l90 127q-188 200 -188 569q0 349 175.5 549.5t479.5 200.5q232 0 392 -121l108 152l72 -60l-111 -153q191 -207 191 -570zM1325 733q0 315 -139 486l-742 -1037q133 -106 338 -106
|
||||
q264 0 403.5 170t139.5 487zM240 733q0 -312 139 -483l739 1034q-133 102 -334 102q-261 0 -402.5 -170t-141.5 -483z" />
|
||||
<glyph glyph-name="Ugrave" unicode="Ù" horiz-adv-x="1473"
|
||||
d="M1282 1462v-946q0 -252 -146 -394t-407 -142q-254 0 -396.5 142.5t-142.5 397.5v942h103v-946q0 -211 117 -328.5t331 -117.5q209 0 324 115.5t115 320.5v956h102zM833 1579h-69q-96 79 -188.5 171.5t-125.5 139.5v17h142q26 -48 98.5 -142t142.5 -170v-16z" />
|
||||
<glyph glyph-name="Uacute" unicode="Ú" horiz-adv-x="1473"
|
||||
d="M1282 1462v-946q0 -252 -146 -394t-407 -142q-254 0 -396.5 142.5t-142.5 397.5v942h103v-946q0 -211 117 -328.5t331 -117.5q209 0 324 115.5t115 320.5v956h102zM633 1595q73 79 144.5 171.5t97.5 140.5h141v-17q-36 -52 -122.5 -138t-190.5 -173h-70v16z" />
|
||||
<glyph glyph-name="Ucircumflex" unicode="Û" horiz-adv-x="1473"
|
||||
d="M1282 1462v-946q0 -252 -146 -394t-407 -142q-254 0 -396.5 142.5t-142.5 397.5v942h103v-946q0 -211 117 -328.5t331 -117.5q209 0 324 115.5t115 320.5v956h102zM444 1595q62 67 131.5 156t110.5 156h98q68 -120 242 -312v-16h-70q-122 101 -221 207
|
||||
q-108 -114 -221 -207h-70v16z" />
|
||||
<glyph glyph-name="Udieresis" unicode="Ü" horiz-adv-x="1473"
|
||||
d="M1282 1462v-946q0 -252 -146 -394t-407 -142q-254 0 -396.5 142.5t-142.5 397.5v942h103v-946q0 -211 117 -328.5t331 -117.5q209 0 324 115.5t115 320.5v956h102zM481 1727q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86zM862 1727q0 46 15.5 66t47.5 20
|
||||
q64 0 64 -86t-64 -86q-63 0 -63 86z" />
|
||||
<glyph glyph-name="Yacute" unicode="Ý" horiz-adv-x="1081"
|
||||
d="M543 662l428 800h110l-487 -897v-565h-105v557l-489 905h117zM434 1595q73 79 144.5 171.5t97.5 140.5h141v-17q-36 -52 -122.5 -138t-190.5 -173h-70v16z" />
|
||||
<glyph glyph-name="Thorn" unicode="Þ" horiz-adv-x="1198"
|
||||
d="M1087 778q0 -212 -144 -325t-408 -113h-226v-340h-102v1462h102v-264h256q522 0 522 -420zM309 428h201q247 0 357 81.5t110 264.5q0 169 -104 250.5t-322 81.5h-242v-678z" />
|
||||
<glyph glyph-name="germandbls" unicode="ß" horiz-adv-x="1194"
|
||||
d="M961 1284q0 -139 -139 -250q-81 -64 -110.5 -100.5t-29.5 -75.5q0 -44 14.5 -68t51.5 -57t102 -78q106 -75 151.5 -124.5t68 -103t22.5 -120.5q0 -156 -88 -241.5t-246 -85.5q-95 0 -174.5 18.5t-126.5 48.5v107q65 -38 148.5 -62t152.5 -24q114 0 174.5 54.5t60.5 160.5
|
||||
q0 83 -39 144t-149 136q-127 87 -175 147t-48 146q0 60 32.5 110t106.5 108q74 57 106.5 105.5t32.5 106.5q0 93 -70 143t-202 50q-145 0 -226 -69t-81 -196v-1214h-99v1206q0 173 103.5 267t292.5 94q188 0 285.5 -72.5t97.5 -210.5z" />
|
||||
<glyph glyph-name="agrave" unicode="à" horiz-adv-x="1085"
|
||||
d="M842 0l-25 172h-8q-82 -105 -168.5 -148.5t-204.5 -43.5q-160 0 -249 82t-89 227q0 159 132.5 247t383.5 93l207 6v72q0 155 -63 234t-203 79q-151 0 -313 -84l-37 86q179 84 354 84q179 0 267.5 -93t88.5 -290v-723h-73zM442 70q174 0 274.5 99.5t100.5 276.5v107
|
||||
l-190 -8q-229 -11 -326.5 -71.5t-97.5 -188.5q0 -102 62.5 -158.5t176.5 -56.5zM638 1241h-69q-96 79 -188.5 171.5t-125.5 139.5v17h142q26 -48 98.5 -142t142.5 -170v-16z" />
|
||||
<glyph glyph-name="aacute" unicode="á" horiz-adv-x="1085"
|
||||
d="M842 0l-25 172h-8q-82 -105 -168.5 -148.5t-204.5 -43.5q-160 0 -249 82t-89 227q0 159 132.5 247t383.5 93l207 6v72q0 155 -63 234t-203 79q-151 0 -313 -84l-37 86q179 84 354 84q179 0 267.5 -93t88.5 -290v-723h-73zM442 70q174 0 274.5 99.5t100.5 276.5v107
|
||||
l-190 -8q-229 -11 -326.5 -71.5t-97.5 -188.5q0 -102 62.5 -158.5t176.5 -56.5zM422 1257q73 79 144.5 171.5t97.5 140.5h141v-17q-36 -52 -122.5 -138t-190.5 -173h-70v16z" />
|
||||
<glyph glyph-name="acircumflex" unicode="â" horiz-adv-x="1085"
|
||||
d="M842 0l-25 172h-8q-82 -105 -168.5 -148.5t-204.5 -43.5q-160 0 -249 82t-89 227q0 159 132.5 247t383.5 93l207 6v72q0 155 -63 234t-203 79q-151 0 -313 -84l-37 86q179 84 354 84q179 0 267.5 -93t88.5 -290v-723h-73zM442 70q174 0 274.5 99.5t100.5 276.5v107
|
||||
l-190 -8q-229 -11 -326.5 -71.5t-97.5 -188.5q0 -102 62.5 -158.5t176.5 -56.5zM251 1257q62 67 131.5 156t110.5 156h98q68 -120 242 -312v-16h-70q-122 101 -221 207q-108 -114 -221 -207h-70v16z" />
|
||||
<glyph glyph-name="atilde" unicode="ã" horiz-adv-x="1085"
|
||||
d="M842 0l-25 172h-8q-82 -105 -168.5 -148.5t-204.5 -43.5q-160 0 -249 82t-89 227q0 159 132.5 247t383.5 93l207 6v72q0 155 -63 234t-203 79q-151 0 -313 -84l-37 86q179 84 354 84q179 0 267.5 -93t88.5 -290v-723h-73zM442 70q174 0 274.5 99.5t100.5 276.5v107
|
||||
l-190 -8q-229 -11 -326.5 -71.5t-97.5 -188.5q0 -102 62.5 -158.5t176.5 -56.5zM697 1243q-36 0 -75 18.5t-101 71.5q-32 26 -62.5 46t-62.5 20q-45 0 -75 -34.5t-48 -121.5h-73q10 111 63 174.5t137 63.5q48 0 88 -25t82 -59q34 -28 66 -50t61 -22q46 0 77 36.5t48 119.5
|
||||
h76q-16 -116 -69 -177t-132 -61z" />
|
||||
<glyph glyph-name="adieresis" unicode="ä" horiz-adv-x="1085"
|
||||
d="M842 0l-25 172h-8q-82 -105 -168.5 -148.5t-204.5 -43.5q-160 0 -249 82t-89 227q0 159 132.5 247t383.5 93l207 6v72q0 155 -63 234t-203 79q-151 0 -313 -84l-37 86q179 84 354 84q179 0 267.5 -93t88.5 -290v-723h-73zM442 70q174 0 274.5 99.5t100.5 276.5v107
|
||||
l-190 -8q-229 -11 -326.5 -71.5t-97.5 -188.5q0 -102 62.5 -158.5t176.5 -56.5zM282 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86zM663 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86z" />
|
||||
<glyph glyph-name="aring" unicode="å" horiz-adv-x="1085"
|
||||
d="M759 1456q0 -97 -60 -155t-157 -58t-157 58t-60 155q0 94 60 152.5t157 58.5t157 -59t60 -152zM405 1456q0 -66 37.5 -103.5t99.5 -37.5t99.5 37.5t37.5 103.5q0 64 -39 101.5t-98 37.5q-62 0 -99.5 -38t-37.5 -101zM842 0l-25 172h-8q-82 -105 -168.5 -148.5
|
||||
t-204.5 -43.5q-160 0 -249 82t-89 227q0 159 132.5 247t383.5 93l207 6v72q0 155 -63 234t-203 79q-151 0 -313 -84l-37 86q179 84 354 84q179 0 267.5 -93t88.5 -290v-723h-73zM442 70q174 0 274.5 99.5t100.5 276.5v107l-190 -8q-229 -11 -326.5 -71.5t-97.5 -188.5
|
||||
q0 -102 62.5 -158.5t176.5 -56.5z" />
|
||||
<glyph glyph-name="ae" unicode="æ" horiz-adv-x="1731"
|
||||
d="M1243 -20q-295 0 -397 256q-68 -133 -168 -194.5t-252 -61.5q-156 0 -242 82.5t-86 226.5q0 154 125 243t377 97l201 6v72q0 155 -61.5 234t-198.5 79q-148 0 -305 -84l-37 86q173 84 346 84q261 0 325 -211q111 213 347 213q184 0 289.5 -134.5t105.5 -363.5v-80h-715
|
||||
q0 -460 348 -460q85 0 150 12t174 57v-90q-92 -41 -165 -55t-161 -14zM434 70q169 0 266 99.5t97 276.5v107l-187 -8q-219 -11 -313 -71.5t-94 -188.5q0 -102 61 -158.5t170 -56.5zM1217 1020q-284 0 -314 -402h604q0 188 -77.5 295t-212.5 107z" />
|
||||
<glyph glyph-name="ccedilla" unicode="ç" horiz-adv-x="973"
|
||||
d="M616 -20q-233 0 -365 147t-132 410q0 270 137 420.5t375 150.5q141 0 270 -49l-27 -88q-141 47 -245 47q-200 0 -303 -123.5t-103 -355.5q0 -220 103 -344.5t288 -124.5q148 0 275 53v-92q-104 -51 -273 -51zM723 -291q0 -100 -67.5 -150.5t-188.5 -50.5q-68 0 -94 11v88
|
||||
q30 -10 92 -10q78 0 119 28t41 80q0 94 -193 121l93 174h96l-66 -117q168 -37 168 -174z" />
|
||||
<glyph glyph-name="egrave" unicode="è" horiz-adv-x="1124"
|
||||
d="M621 -20q-237 0 -369.5 146t-132.5 409q0 260 128 416.5t345 156.5q192 0 303 -134t111 -364v-80h-783q2 -224 104.5 -342t293.5 -118q93 0 163.5 13t178.5 56v-90q-92 -40 -170 -54.5t-172 -14.5zM592 1020q-157 0 -252 -103.5t-111 -298.5h672q0 189 -82 295.5
|
||||
t-227 106.5zM685 1241h-69q-96 79 -188.5 171.5t-125.5 139.5v17h142q26 -48 98.5 -142t142.5 -170v-16z" />
|
||||
<glyph glyph-name="eacute" unicode="é" horiz-adv-x="1124"
|
||||
d="M621 -20q-237 0 -369.5 146t-132.5 409q0 260 128 416.5t345 156.5q192 0 303 -134t111 -364v-80h-783q2 -224 104.5 -342t293.5 -118q93 0 163.5 13t178.5 56v-90q-92 -40 -170 -54.5t-172 -14.5zM592 1020q-157 0 -252 -103.5t-111 -298.5h672q0 189 -82 295.5
|
||||
t-227 106.5zM452 1257q73 79 144.5 171.5t97.5 140.5h141v-17q-36 -52 -122.5 -138t-190.5 -173h-70v16z" />
|
||||
<glyph glyph-name="ecircumflex" unicode="ê" horiz-adv-x="1124"
|
||||
d="M621 -20q-237 0 -369.5 146t-132.5 409q0 260 128 416.5t345 156.5q192 0 303 -134t111 -364v-80h-783q2 -224 104.5 -342t293.5 -118q93 0 163.5 13t178.5 56v-90q-92 -40 -170 -54.5t-172 -14.5zM592 1020q-157 0 -252 -103.5t-111 -298.5h672q0 189 -82 295.5
|
||||
t-227 106.5zM290 1257q62 67 131.5 156t110.5 156h98q68 -120 242 -312v-16h-70q-122 101 -221 207q-108 -114 -221 -207h-70v16z" />
|
||||
<glyph glyph-name="edieresis" unicode="ë" horiz-adv-x="1124"
|
||||
d="M621 -20q-237 0 -369.5 146t-132.5 409q0 260 128 416.5t345 156.5q192 0 303 -134t111 -364v-80h-783q2 -224 104.5 -342t293.5 -118q93 0 163.5 13t178.5 56v-90q-92 -40 -170 -54.5t-172 -14.5zM592 1020q-157 0 -252 -103.5t-111 -298.5h672q0 189 -82 295.5
|
||||
t-227 106.5zM331 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86zM712 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86z" />
|
||||
<glyph glyph-name="igrave" unicode="ì" horiz-adv-x="463"
|
||||
d="M281 0h-99v1087h99v-1087zM349 1241h-69q-96 79 -188.5 171.5t-125.5 139.5v17h142q26 -48 98.5 -142t142.5 -170v-16z" />
|
||||
<glyph glyph-name="iacute" unicode="í" horiz-adv-x="463"
|
||||
d="M281 0h-99v1087h99v-1087zM107 1257q73 79 144.5 171.5t97.5 140.5h141v-17q-36 -52 -122.5 -138t-190.5 -173h-70v16z" />
|
||||
<glyph glyph-name="icircumflex" unicode="î" horiz-adv-x="463"
|
||||
d="M281 0h-99v1087h99v-1087zM-58 1257q62 67 131.5 156t110.5 156h98q68 -120 242 -312v-16h-70q-122 101 -221 207q-108 -114 -221 -207h-70v16z" />
|
||||
<glyph glyph-name="idieresis" unicode="ï" horiz-adv-x="463"
|
||||
d="M281 0h-99v1087h99v-1087zM-21 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86zM360 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86z" />
|
||||
<glyph glyph-name="eth" unicode="ð" horiz-adv-x="1174"
|
||||
d="M1055 559q0 -276 -124 -427.5t-349 -151.5q-214 0 -339.5 130t-125.5 361q0 228 126.5 357.5t342.5 129.5q108 0 187.5 -33t148.5 -96l4 2q-64 270 -269 459l-270 -157l-49 77l244 146q-86 62 -199 119l45 81q147 -69 248 -145l225 137l49 -84l-202 -121
|
||||
q154 -151 230.5 -353t76.5 -431zM950 557q0 146 -97 228.5t-267 82.5q-185 0 -275 -100.5t-90 -304.5q0 -186 94.5 -289.5t268.5 -103.5q179 0 272.5 123t93.5 364z" />
|
||||
<glyph glyph-name="ntilde" unicode="ñ" horiz-adv-x="1208"
|
||||
d="M940 0v705q0 164 -69 238.5t-214 74.5q-195 0 -285.5 -98.5t-90.5 -319.5v-600h-99v1087h84l19 -149h6q106 170 377 170q370 0 370 -397v-711h-98zM779 1243q-36 0 -75 18.5t-101 71.5q-32 26 -62.5 46t-62.5 20q-45 0 -75 -34.5t-48 -121.5h-73q10 111 63 174.5
|
||||
t137 63.5q48 0 88 -25t82 -59q34 -28 66 -50t61 -22q46 0 77 36.5t48 119.5h76q-16 -116 -69 -177t-132 -61z" />
|
||||
<glyph glyph-name="ograve" unicode="ò" horiz-adv-x="1200"
|
||||
d="M1081 545q0 -266 -129 -415.5t-356 -149.5q-143 0 -252 69t-167 198t-58 298q0 266 129 414.5t354 148.5q224 0 351.5 -150.5t127.5 -412.5zM223 545q0 -224 98.5 -349.5t278.5 -125.5t278.5 125.5t98.5 349.5q0 225 -99.5 349t-279.5 124t-277.5 -123.5t-97.5 -349.5z
|
||||
M718 1241h-69q-96 79 -188.5 171.5t-125.5 139.5v17h142q26 -48 98.5 -142t142.5 -170v-16z" />
|
||||
<glyph glyph-name="oacute" unicode="ó" horiz-adv-x="1200"
|
||||
d="M1081 545q0 -266 -129 -415.5t-356 -149.5q-143 0 -252 69t-167 198t-58 298q0 266 129 414.5t354 148.5q224 0 351.5 -150.5t127.5 -412.5zM223 545q0 -224 98.5 -349.5t278.5 -125.5t278.5 125.5t98.5 349.5q0 225 -99.5 349t-279.5 124t-277.5 -123.5t-97.5 -349.5z
|
||||
M499 1257q73 79 144.5 171.5t97.5 140.5h141v-17q-36 -52 -122.5 -138t-190.5 -173h-70v16z" />
|
||||
<glyph glyph-name="ocircumflex" unicode="ô" horiz-adv-x="1200"
|
||||
d="M1081 545q0 -266 -129 -415.5t-356 -149.5q-143 0 -252 69t-167 198t-58 298q0 266 129 414.5t354 148.5q224 0 351.5 -150.5t127.5 -412.5zM223 545q0 -224 98.5 -349.5t278.5 -125.5t278.5 125.5t98.5 349.5q0 225 -99.5 349t-279.5 124t-277.5 -123.5t-97.5 -349.5z
|
||||
M309 1257q62 67 131.5 156t110.5 156h98q68 -120 242 -312v-16h-70q-122 101 -221 207q-108 -114 -221 -207h-70v16z" />
|
||||
<glyph glyph-name="otilde" unicode="õ" horiz-adv-x="1200"
|
||||
d="M1081 545q0 -266 -129 -415.5t-356 -149.5q-143 0 -252 69t-167 198t-58 298q0 266 129 414.5t354 148.5q224 0 351.5 -150.5t127.5 -412.5zM223 545q0 -224 98.5 -349.5t278.5 -125.5t278.5 125.5t98.5 349.5q0 225 -99.5 349t-279.5 124t-277.5 -123.5t-97.5 -349.5z
|
||||
M761 1243q-36 0 -75 18.5t-101 71.5q-32 26 -62.5 46t-62.5 20q-45 0 -75 -34.5t-48 -121.5h-73q10 111 63 174.5t137 63.5q48 0 88 -25t82 -59q34 -28 66 -50t61 -22q46 0 77 36.5t48 119.5h76q-16 -116 -69 -177t-132 -61z" />
|
||||
<glyph glyph-name="odieresis" unicode="ö" horiz-adv-x="1200"
|
||||
d="M1081 545q0 -266 -129 -415.5t-356 -149.5q-143 0 -252 69t-167 198t-58 298q0 266 129 414.5t354 148.5q224 0 351.5 -150.5t127.5 -412.5zM223 545q0 -224 98.5 -349.5t278.5 -125.5t278.5 125.5t98.5 349.5q0 225 -99.5 349t-279.5 124t-277.5 -123.5t-97.5 -349.5z
|
||||
M346 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86zM727 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86z" />
|
||||
<glyph glyph-name="divide" unicode="÷"
|
||||
d="M111 682v82h948v-82h-948zM504 1075q0 99 80 99q82 0 82 -99q0 -52 -23.5 -75t-58.5 -23q-34 0 -57 23t-23 75zM504 371q0 98 80 98q82 0 82 -98q0 -53 -23.5 -76t-58.5 -23q-34 0 -57 23t-23 76z" />
|
||||
<glyph glyph-name="oslash" unicode="ø" horiz-adv-x="1200"
|
||||
d="M1081 545q0 -266 -129 -415.5t-356 -149.5q-173 0 -291 98l-86 -113l-72 58l93 120q-121 153 -121 402q0 266 129 414.5t354 148.5q179 0 301 -104l96 124l74 -55l-104 -137q112 -147 112 -391zM223 545q0 -200 78 -322l543 705q-98 90 -246 90q-180 0 -277.5 -123.5
|
||||
t-97.5 -349.5zM977 545q0 190 -72 309l-543 -702q94 -82 238 -82q180 0 278.5 125.5t98.5 349.5z" />
|
||||
<glyph glyph-name="ugrave" unicode="ù" horiz-adv-x="1208"
|
||||
d="M268 1087v-704q0 -164 69 -238.5t214 -74.5q194 0 285.5 98t91.5 319v600h98v-1087h-84l-18 150h-6q-106 -170 -377 -170q-371 0 -371 397v710h98zM687 1241h-69q-96 79 -188.5 171.5t-125.5 139.5v17h142q26 -48 98.5 -142t142.5 -170v-16z" />
|
||||
<glyph glyph-name="uacute" unicode="ú" horiz-adv-x="1208"
|
||||
d="M268 1087v-704q0 -164 69 -238.5t214 -74.5q194 0 285.5 98t91.5 319v600h98v-1087h-84l-18 150h-6q-106 -170 -377 -170q-371 0 -371 397v710h98zM495 1257q73 79 144.5 171.5t97.5 140.5h141v-17q-36 -52 -122.5 -138t-190.5 -173h-70v16z" />
|
||||
<glyph glyph-name="ucircumflex" unicode="û" horiz-adv-x="1208"
|
||||
d="M268 1087v-704q0 -164 69 -238.5t214 -74.5q194 0 285.5 98t91.5 319v600h98v-1087h-84l-18 150h-6q-106 -170 -377 -170q-371 0 -371 397v710h98zM313 1257q62 67 131.5 156t110.5 156h98q68 -120 242 -312v-16h-70q-122 101 -221 207q-108 -114 -221 -207h-70v16z" />
|
||||
<glyph glyph-name="udieresis" unicode="ü" horiz-adv-x="1208"
|
||||
d="M268 1087v-704q0 -164 69 -238.5t214 -74.5q194 0 285.5 98t91.5 319v600h98v-1087h-84l-18 150h-6q-106 -170 -377 -170q-371 0 -371 397v710h98zM350 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86zM731 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86
|
||||
q-63 0 -63 86z" />
|
||||
<glyph glyph-name="yacute" unicode="ý" horiz-adv-x="940"
|
||||
d="M0 1087h102l230 -610q105 -281 133 -379h6q42 129 137 385l230 604h102l-487 -1263q-59 -154 -99 -208t-93.5 -81t-129.5 -27q-57 0 -127 21v86q58 -16 125 -16q51 0 90 24t70.5 74.5t73 160t53.5 142.5zM361 1257q73 79 144.5 171.5t97.5 140.5h141v-17
|
||||
q-36 -52 -122.5 -138t-190.5 -173h-70v16z" />
|
||||
<glyph glyph-name="thorn" unicode="þ" horiz-adv-x="1219"
|
||||
d="M281 918q114 190 368 190q220 0 335.5 -144.5t115.5 -420.5q0 -268 -121.5 -415.5t-331.5 -147.5q-251 0 -366 188h-7l3 -84q4 -74 4 -162v-414h-99v2048h99v-391l-7 -247h7zM645 68q167 0 258.5 124t91.5 347q0 479 -348 479q-193 0 -279.5 -105t-86.5 -354v-18
|
||||
q0 -255 85.5 -364t278.5 -109z" />
|
||||
<glyph glyph-name="ydieresis" unicode="ÿ" horiz-adv-x="940"
|
||||
d="M0 1087h102l230 -610q105 -281 133 -379h6q42 129 137 385l230 604h102l-487 -1263q-59 -154 -99 -208t-93.5 -81t-129.5 -27q-57 0 -127 21v86q58 -16 125 -16q51 0 90 24t70.5 74.5t73 160t53.5 142.5zM214 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86
|
||||
q-63 0 -63 86zM595 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86z" />
|
||||
<glyph glyph-name="itilde" unicode="ĩ" horiz-adv-x="463"
|
||||
d="M281 0h-99v1087h99v-1087zM390 1243q-36 0 -75 18.5t-101 71.5q-32 26 -62.5 46t-62.5 20q-45 0 -75 -34.5t-48 -121.5h-73q10 111 63 174.5t137 63.5q48 0 88 -25t82 -59q34 -28 66 -50t61 -22q46 0 77 36.5t48 119.5h76q-16 -116 -69 -177t-132 -61z" />
|
||||
<glyph glyph-name="Eng" unicode="Ŋ" horiz-adv-x="1477"
|
||||
d="M1270 0q0 -369 -342 -369q-93 0 -152 27v88q78 -20 150 -20q241 0 241 264v10l-866 1298h-8q12 -232 12 -350v-948h-98v1462h102l865 -1296h6q-9 180 -9 342v954h99v-1462z" />
|
||||
<glyph glyph-name="eng" unicode="ŋ" horiz-adv-x="1208"
|
||||
d="M795 -492q-79 0 -136 25v86q69 -20 129 -20q152 0 152 176v930q0 164 -72.5 238.5t-224.5 74.5q-189 0 -275.5 -99.5t-86.5 -318.5v-600h-99v1087h84l19 -149h6q54 87 147 128.5t205 41.5q201 0 298 -99t97 -298v-922q0 -134 -62.5 -207.5t-180.5 -73.5z" />
|
||||
<glyph glyph-name="OE" unicode="Œ" horiz-adv-x="1839"
|
||||
d="M1714 0h-756q-76 -16 -176 -16q-305 0 -479 200t-174 551q0 347 174.5 545.5t480.5 198.5q78 0 183 -17h747v-94h-655v-553h616v-94h-616v-627h655v-94zM782 80q109 0 174 18v1266q-62 16 -172 16q-262 0 -403 -167.5t-141 -479.5q0 -315 140.5 -484t401.5 -169z" />
|
||||
<glyph glyph-name="oe" unicode="œ" horiz-adv-x="1942"
|
||||
d="M1438 -20q-156 0 -266.5 67.5t-165.5 198.5q-59 -128 -158 -197t-252 -69q-143 0 -252 69t-167 198t-58 298q0 266 129 414.5t354 148.5q151 0 251 -70t157 -209q110 279 399 279q192 0 303 -134t111 -364v-80h-762q2 -230 100.5 -345t276.5 -115q93 0 163.5 13t178.5 56
|
||||
v-90q-92 -40 -170 -54.5t-172 -14.5zM223 545q0 -224 98.5 -349.5t278.5 -125.5q174 0 265 122.5t91 352.5q0 224 -93 348.5t-265 124.5q-180 0 -277.5 -123.5t-97.5 -349.5zM1409 1020q-155 0 -242 -104t-102 -298h653q0 189 -82 295.5t-227 106.5z" />
|
||||
<glyph glyph-name="Scaron" unicode="Š" horiz-adv-x="1116"
|
||||
d="M859 1890q-170 -188 -242 -311h-98q-76 128 -242 311v17h70q114 -94 221 -207q108 114 221 207h70v-17zM1014 377q0 -183 -134.5 -290t-357.5 -107q-268 0 -411 59v102q158 -67 403 -67q180 0 285.5 82.5t105.5 216.5q0 83 -35 137.5t-114 99.5t-232 97
|
||||
q-224 77 -309.5 166.5t-85.5 238.5q0 164 128.5 267.5t330.5 103.5q206 0 387 -78l-37 -88q-182 76 -348 76q-162 0 -258 -75t-96 -204q0 -81 29.5 -133t96.5 -93.5t230 -99.5q171 -59 257 -114.5t125.5 -126t39.5 -170.5z" />
|
||||
<glyph glyph-name="scaron" unicode="š" horiz-adv-x="954"
|
||||
d="M759 1552q-170 -188 -242 -311h-98q-76 128 -242 311v17h70q114 -94 221 -207q108 114 221 207h70v-17zM856 283q0 -146 -111 -224.5t-315 -78.5q-218 0 -346 67v107q164 -82 346 -82q161 0 244.5 53.5t83.5 142.5q0 82 -66.5 138t-218.5 110q-163 59 -229 101.5
|
||||
t-99.5 96t-33.5 130.5q0 122 102.5 193t286.5 71q176 0 334 -66l-37 -90q-160 66 -297 66q-133 0 -211 -44t-78 -122q0 -85 60.5 -136t236.5 -114q147 -53 214 -95.5t100.5 -96.5t33.5 -127z" />
|
||||
<glyph glyph-name="Wcircumflex" unicode="Ŵ" horiz-adv-x="1827"
|
||||
d="M1372 0h-84l-321 1128q-40 139 -60 228q-16 -87 -45.5 -200t-322.5 -1156h-86l-402 1462h107l256 -942q15 -57 28 -105.5t23.5 -91t19 -82t15.5 -79.5q24 136 102 413l250 887h113l293 -1018q51 -176 73 -284q13 72 33.5 153t308.5 1149h103zM618 1595q62 67 131.5 156
|
||||
t110.5 156h98q68 -120 242 -312v-16h-70q-122 101 -221 207q-108 -114 -221 -207h-70v16z" />
|
||||
<glyph glyph-name="Ydieresis" unicode="Ÿ" horiz-adv-x="1081"
|
||||
d="M543 662l428 800h110l-487 -897v-565h-105v557l-489 905h117zM288 1727q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86zM669 1727q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86z" />
|
||||
<glyph glyph-name="Zcaron" unicode="Ž" horiz-adv-x="1180"
|
||||
d="M891 1890q-170 -188 -242 -311h-98q-76 128 -242 311v17h70q114 -94 221 -207q108 114 221 207h70v-17zM1098 0h-1016v76l856 1290h-817v96h954v-76l-858 -1290h881v-96z" />
|
||||
<glyph glyph-name="zcaron" unicode="ž" horiz-adv-x="944"
|
||||
d="M780 1552q-170 -188 -242 -311h-98q-76 128 -242 311v17h70q114 -94 221 -207q108 114 221 207h70v-17zM858 0h-776v63l645 936h-598v88h727v-63l-649 -936h651v-88z" />
|
||||
<glyph glyph-name="florin" unicode="ƒ"
|
||||
d="M303 854v59l207 37v146q0 201 76.5 294t240.5 93q82 0 183 -31l-25 -86q-89 29 -160 29q-115 0 -166 -67.5t-51 -223.5v-162h281v-88h-281v-1028q0 -155 -71 -236.5t-207 -81.5q-85 0 -140 19v90q78 -18 144 -18q176 0 176 217v1038h-207z" />
|
||||
<glyph glyph-name="circumflex" unicode="ˆ" horiz-adv-x="1182"
|
||||
d="M299 1257q62 67 131.5 156t110.5 156h98q68 -120 242 -312v-16h-70q-122 101 -221 207q-108 -114 -221 -207h-70v16z" />
|
||||
<glyph glyph-name="tilde" unicode="˜" horiz-adv-x="1182"
|
||||
d="M780 1243q-36 0 -75 18.5t-101 71.5q-32 26 -62.5 46t-62.5 20q-45 0 -75 -34.5t-48 -121.5h-73q10 111 63 174.5t137 63.5q48 0 88 -25t82 -59q34 -28 66 -50t61 -22q46 0 77 36.5t48 119.5h76q-16 -116 -69 -177t-132 -61z" />
|
||||
<glyph glyph-name="Alphatonos" unicode="Ά" horiz-adv-x="1229"
|
||||
d="M76 1152q29 75 57 184t42 210h119v-17q-18 -77 -63 -191t-97 -202h-58v16zM911 516h-594l-204 -516h-113l588 1468h65l576 -1468h-115zM354 608h523l-199 527q-25 62 -60 172q-27 -96 -59 -174z" />
|
||||
<glyph glyph-name="endash" unicode="–" horiz-adv-x="1024"
|
||||
d="M82 512v82h860v-82h-860z" />
|
||||
<glyph glyph-name="emdash" unicode="—" horiz-adv-x="2048"
|
||||
d="M82 512v82h1884v-82h-1884z" />
|
||||
<glyph glyph-name="quoteleft" unicode="‘" horiz-adv-x="297"
|
||||
d="M41 961l-12 20q32 112 81.5 251t92.5 230h65q-30 -101 -64.5 -257t-45.5 -244h-117z" />
|
||||
<glyph glyph-name="quoteright" unicode="’" horiz-adv-x="297"
|
||||
d="M256 1462l12 -20q-75 -265 -174 -481h-65q29 96 61 241.5t49 259.5h117z" />
|
||||
<glyph glyph-name="quotesinglbase" unicode="‚" horiz-adv-x="451"
|
||||
d="M295 238l12 -20q-75 -265 -174 -481h-65q29 96 61 241.5t49 259.5h117z" />
|
||||
<glyph glyph-name="quotedblleft" unicode="“" horiz-adv-x="614"
|
||||
d="M358 961l-12 20q34 120 83 255t91 226h66q-30 -98 -63 -248.5t-48 -252.5h-117zM41 961l-12 20q32 112 81.5 251t92.5 230h65q-30 -101 -64.5 -257t-45.5 -244h-117z" />
|
||||
<glyph glyph-name="quotedblright" unicode="”" horiz-adv-x="614"
|
||||
d="M256 1462l12 -20q-75 -265 -174 -481h-65q29 96 61 241.5t49 259.5h117zM573 1462l13 -20q-36 -128 -85 -261t-89 -220h-66q30 98 63 248.5t48 252.5h116z" />
|
||||
<glyph glyph-name="quotedblbase" unicode="„" horiz-adv-x="768"
|
||||
d="M295 238l12 -20q-75 -265 -174 -481h-65q29 96 61 241.5t49 259.5h117zM612 238l13 -20q-36 -128 -85 -261t-89 -220h-66q30 98 63 248.5t48 252.5h116z" />
|
||||
<glyph glyph-name="dagger" unicode="†" horiz-adv-x="1006"
|
||||
d="M883 1055l-359 20l27 -1075h-117l27 1075l-338 -20v112l338 -28l-27 417h117l-27 -417l359 28v-112z" />
|
||||
<glyph glyph-name="daggerdbl" unicode="‡" horiz-adv-x="1006"
|
||||
d="M524 461l359 24v-112l-359 24l27 -397h-117l27 397l-338 -24v112l338 -24l-17 325l17 293l-338 -24v112l338 -24l-27 413h117l-27 -413l359 24v-112l-359 24l17 -293z" />
|
||||
<glyph glyph-name="bullet" unicode="•" horiz-adv-x="770"
|
||||
d="M231 748q0 89 40.5 134.5t113.5 45.5t113.5 -47t40.5 -133q0 -85 -41 -133t-113 -48t-113 47t-41 134z" />
|
||||
<glyph glyph-name="ellipsis" unicode="…" horiz-adv-x="1466"
|
||||
d="M162 78q0 98 80 98q82 0 82 -98t-82 -98q-80 0 -80 98zM651 78q0 98 80 98q82 0 82 -98t-82 -98q-80 0 -80 98zM1141 78q0 98 80 98q82 0 82 -98t-82 -98q-80 0 -80 98z" />
|
||||
<glyph glyph-name="perthousand" unicode="‰" horiz-adv-x="2331"
|
||||
d="M211 1026q0 -186 45 -279.5t141 -93.5q193 0 193 373q0 184 -49.5 276.5t-143.5 92.5q-96 0 -141 -92.5t-45 -276.5zM688 1026q0 -226 -75 -343.5t-216 -117.5q-133 0 -208.5 120.5t-75.5 340.5q0 223 72 340t212 117q139 0 215 -120.5t76 -336.5zM1063 438
|
||||
q0 -185 45 -277.5t141 -92.5q193 0 193 370q0 369 -193 369q-96 0 -141 -91.5t-45 -277.5zM1540 438q0 -226 -74 -343.5t-215 -117.5q-136 0 -211 121.5t-75 339.5q0 225 73.5 341t212.5 116q137 0 213 -120t76 -337zM1280 1462l-811 -1462h-96l811 1462h96zM1741 438
|
||||
q0 -185 45 -277.5t141 -92.5q193 0 193 370q0 369 -193 369q-96 0 -141 -91.5t-45 -277.5zM2218 438q0 -226 -74 -343.5t-215 -117.5q-135 0 -211 120.5t-76 340.5q0 225 73.5 341t213.5 116q137 0 213 -120t76 -337z" />
|
||||
<glyph glyph-name="guilsinglleft" unicode="‹" horiz-adv-x="524"
|
||||
d="M82 543l309 393l62 -43l-254 -363l254 -362l-62 -43l-309 391v27z" />
|
||||
<glyph glyph-name="guilsinglright" unicode="›" horiz-adv-x="524"
|
||||
d="M442 518l-309 -393l-61 43l254 362l-254 363l61 43l309 -391v-27z" />
|
||||
<glyph glyph-name="Euro" unicode="€"
|
||||
d="M803 1397q-174 0 -288 -125.5t-155 -364.5h502v-82h-510l-4 -104v-24q0 -65 4 -87h449v-82h-443q30 -217 147.5 -338.5t301.5 -121.5q148 0 287 65v-94q-81 -34 -150.5 -46.5t-140.5 -12.5q-228 0 -367.5 140t-181.5 408h-180v82h172q-4 38 -4 113l4 102h-172v82h184
|
||||
q39 272 183 425t362 153q88 0 161 -17t148 -57l-39 -86q-132 72 -270 72z" />
|
||||
<glyph glyph-name="trademark" unicode="™" horiz-adv-x="1485"
|
||||
d="M313 741h-86v643h-217v78h522v-78h-219v-643zM913 741l-221 609h-6l4 -201v-408h-82v721h125l221 -606l224 606h125v-721h-86v398l4 207h-7l-227 -605h-74z" />
|
||||
<glyph glyph-name="uni0492" unicode="Ғ" horiz-adv-x="1028"
|
||||
d="M309 772h439v-94h-439v-678h-102v678h-160v94h160v690h801v-94h-699v-596z" />
|
||||
<glyph glyph-name="uni0493" unicode="ғ" horiz-adv-x="862"
|
||||
d="M821 1001h-540v-409h366v-86h-366v-506h-99v506h-164v86h164v495h639v-86z" />
|
||||
<glyph glyph-name="uni04A4" unicode="Ҥ" horiz-adv-x="1602"
|
||||
d="M1591 1366h-325v-1366h-103v719h-854v-719h-102v1462h102v-649h854v649h428v-96z" />
|
||||
<glyph glyph-name="uni04A5" unicode="ҥ" horiz-adv-x="1430"
|
||||
d="M281 1087v-477h690v477h418v-86h-320v-1001h-98v524h-690v-524h-99v1087h99z" />
|
||||
<glyph glyph-name="uni04A6" unicode="Ҧ" horiz-adv-x="2146"
|
||||
d="M1184 0h-103v1366h-772v-1366h-102v1462h977v-682q113 23 223 23q194 0 336 -79.5t216.5 -226.5t74.5 -343q0 -321 -136 -493.5t-382 -172.5q-145 0 -259 49v101q134 -56 259 -56q192 0 299.5 150.5t107.5 423.5q0 261 -139 408t-389 147q-116 0 -211 -23v-688z" />
|
||||
<glyph glyph-name="uni04A7" unicode="ҧ" horiz-adv-x="1737"
|
||||
d="M989 610q93 27 174 27q250 0 378 -146t128 -434q0 -267 -96 -413t-275 -146q-138 0 -225 58v100q114 -68 221 -68q132 0 201.5 123.5t69.5 347.5q0 488 -412 488q-91 0 -164 -27v-520h-98v993h-610v-993h-99v1087h807v-477z" />
|
||||
<glyph glyph-name="uni04A8" unicode="Ҩ" horiz-adv-x="1565"
|
||||
d="M1436 678q0 -185 -78.5 -348.5t-212.5 -251.5q89 -68 196 -68q74 0 129 21v-92q-42 -23 -139 -23t-169.5 30.5t-131.5 73.5q-100 -40 -252 -40q-196 0 -344.5 92.5t-226.5 262t-78 390.5q0 361 163 560.5t460 199.5q130 0 209 -27l-27 -96q-75 24 -186 24
|
||||
q-508 0 -508 -663q0 -311 143.5 -479t404.5 -168q38 0 85.5 5.5t74.5 14.5q-105 98 -163 250t-58 332q0 245 94.5 380.5t257.5 135.5q173 0 265 -132.5t92 -383.5zM1329 680q0 416 -250 416q-115 0 -181.5 -109.5t-66.5 -308.5q0 -350 224 -543q132 72 203 215t71 330z" />
|
||||
<glyph glyph-name="uni04A9" unicode="ҩ" horiz-adv-x="1239"
|
||||
d="M686 496q0 -122 39.5 -208t114.5 -151q78 51 126 145t48 220q0 139 -36.5 210.5t-121.5 71.5q-170 0 -170 -288zM1067 -53q-126 0 -240 76q-86 -43 -227 -43q-145 0 -254 70.5t-168 197.5t-59 287q0 266 117 419.5t329 153.5q82 0 146 -18l-21 -91q-69 19 -129 19
|
||||
q-162 0 -250 -124.5t-88 -358.5q0 -139 47.5 -245t138 -163t218.5 -57q78 0 127 22q-172 154 -172 406q0 178 72 277t202 99q128 0 195 -96t67 -276q0 -132 -53 -241.5t-150 -178.5q24 -18 68 -32.5t84 -14.5q62 0 107 14v-88q-44 -14 -107 -14z" />
|
||||
<glyph glyph-name="brevetildecomb" horiz-adv-x="0"
|
||||
d="M-612 1241q-253 0 -275 246h82q14 -87 60.5 -124.5t134.5 -37.5t134.5 37.5t61.5 124.5h80q-30 -246 -278 -246zM-471 1587q-39 0 -74.5 20t-67.5 43.5t-61 43.5t-55 20q-80 0 -105 -129h-73q14 97 60 154t124 57q39 0 73.5 -19.5t66 -43t60.5 -43t58 -19.5q45 0 66 35
|
||||
t32 92h76q-11 -101 -58.5 -156t-121.5 -55z" />
|
||||
<glyph glyph-name="gcommaaccent.alt" horiz-adv-x="1219"
|
||||
d="M938 -2q0 118 6 172h-6q-118 -190 -369 -190q-214 0 -332 142t-118 410q0 275 118 425.5t338 150.5q236 0 353 -174h6l18 153h84v-1107q0 -214 -122 -343t-326 -129q-221 0 -377 70v107q166 -88 383 -88q160 0 252 100t92 280v21zM571 68q198 0 282.5 109t84.5 366v12
|
||||
q0 245 -85 354t-271 109q-176 0 -267.5 -124t-91.5 -364q0 -229 89.5 -345.5t258.5 -116.5zM731 1552q-27 -58 -53.5 -159t-32.5 -152h-112v14q20 77 61.5 165t83.5 149h53v-17z" />
|
||||
<glyph glyph-name="I" unicode="I" horiz-adv-x="516"
|
||||
d="M207 0v1462h102v-1462h-102z" />
|
||||
<glyph glyph-name="Igrave" unicode="Ì" horiz-adv-x="516"
|
||||
d="M207 0v1462h102v-1462h-102zM320 1579h-69q-96 79 -188.5 171.5t-125.5 139.5v17h142q26 -48 98.5 -142t142.5 -170v-16z" />
|
||||
<glyph glyph-name="Iacute" unicode="Í" horiz-adv-x="516"
|
||||
d="M207 0v1462h102v-1462h-102zM191 1595q73 79 144.5 171.5t97.5 140.5h141v-17q-36 -52 -122.5 -138t-190.5 -173h-70v16z" />
|
||||
<glyph glyph-name="Icircumflex" unicode="Î" horiz-adv-x="516"
|
||||
d="M207 0v1462h102v-1462h-102zM-32 1595q62 67 131.5 156t110.5 156h98q68 -120 242 -312v-16h-70q-122 101 -221 207q-108 -114 -221 -207h-70v16z" />
|
||||
<glyph glyph-name="Idieresis" unicode="Ï" horiz-adv-x="516"
|
||||
d="M207 0v1462h102v-1462h-102zM5 1727q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86zM386 1727q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86z" />
|
||||
</font>
|
||||
</defs></svg>
|
After Width: | Height: | Size: 65 KiB |
|
@ -30,16 +30,13 @@
|
|||
<glyph unicode="u" d="M366 174l0-19c0-2-1-4-3-6-2-2-4-3-6-3l-202 0c-2 0-4 1-6 3-2 2-3 4-3 6l0 19c0 2 1 5 3 6 2 2 4 3 6 3l202 0c2 0 4-1 6-3 2-1 3-4 3-6z m0 73l0-18c0-3-1-5-3-7-2-2-4-3-6-3l-202 0c-2 0-4 1-6 3-2 2-3 4-3 7l0 18c0 3 1 5 3 6 2 2 4 3 6 3l202 0c2 0 4-1 6-3 2-1 3-3 3-6z m-256-174l292 0 0 220-119 0c-7 0-14 2-19 8-5 5-8 11-8 19l0 119-146 0z m183 256l107 0c-2 6-4 10-6 12l-90 89c-2 3-6 5-11 7z m146-9l0-256c0-8-3-14-8-19-5-6-12-8-20-8l-310 0c-8 0-15 2-20 8-5 5-8 11-8 19l0 384c0 8 3 14 8 19 5 6 12 8 20 8l182 0c8 0 16-1 26-5 9-4 16-9 21-14l89-89c6-5 10-13 14-22 4-9 6-17 6-25z"/>
|
||||
<glyph unicode="v" d="M256 475c40 0 77-9 110-29 34-20 60-46 80-80 20-33 29-70 29-110 0-40-9-77-29-110-20-34-46-60-80-80-33-20-70-29-110-29-40 0-77 9-110 29-34 20-60 46-80 80-20 33-29 70-29 110 0 40 9 77 29 110 20 34 46 60 80 80 33 20 70 29 110 29z m37-356l0 54c0 3-1 5-3 7-2 2-4 3-6 3l-55 0c-3 0-5-1-7-3-2-2-3-4-3-7l0-54c0-2 1-5 3-6 2-2 4-3 7-3l55 0c2 0 4 1 6 2 2 2 3 4 3 7z m-1 98l5 178c0 2-1 4-3 5-2 2-4 2-7 2l-62 0c-3 0-5 0-7-2-2-1-3-3-3-5l5-178c0-1 1-3 3-5 1-1 4-2 6-2l53 0c3 0 5 1 7 2 2 2 3 4 3 5z"/>
|
||||
<glyph unicode="w" d="M512 174l0-55c0-3-1-5-3-7-2-1-4-2-6-2l-393 0 0-55c0-3-1-5-3-7-2-1-4-2-6-2-3 0-5 1-7 3l-91 91c-2 2-3 4-3 6 0 3 1 5 3 7l91 91c2 2 4 3 7 3 2 0 4-1 6-3 2-2 3-4 3-6l0-55 393 0c2 0 4-1 6-3 2-2 3-4 3-6z m0 155c0-3-1-5-3-6l-91-92c-2-2-4-2-7-2-2 0-4 0-6 2-2 2-3 4-3 7l0 55-393 0c-2 0-4 0-6 2-2 2-3 4-3 7l0 55c0 2 1 4 3 6 2 2 4 3 6 3l393 0 0 55c0 2 1 4 3 6 2 2 4 3 6 3 3 0 5-1 7-3l91-91c2-2 3-4 3-7z"/>
|
||||
<glyph unicode="x" d="M165 302l0-55c0-8-3-14-8-20-6-5-12-8-20-8l-55 0c-7 0-14 3-19 8-5 6-8 12-8 20l0 55c0 7 3 14 8 19 5 5 12 8 19 8l55 0c8 0 14-3 20-8 5-5 8-12 8-19z m146 0l0-55c0-8-3-14-8-20-5-5-12-8-20-8l-54 0c-8 0-15 3-20 8-5 6-8 12-8 20l0 55c0 7 3 14 8 19 5 5 12 8 20 8l54 0c8 0 15-3 20-8 5-5 8-12 8-19z m146 0l0-55c0-8-3-14-8-20-5-5-12-8-19-8l-55 0c-8 0-14 3-20 8-5 6-8 12-8 20l0 55c0 7 3 14 8 19 6 5 12 8 20 8l55 0c7 0 14-3 19-8 5-5 8-12 8-19z"/>
|
||||
<glyph unicode="y" d="M311 155l0-54c0-8-3-15-8-20-5-5-12-8-20-8l-54 0c-8 0-15 3-20 8-5 5-8 12-8 20l0 54c0 8 3 15 8 20 5 5 12 8 20 8l54 0c8 0 15-3 20-8 5-5 8-12 8-20z m0 147l0-55c0-8-3-14-8-20-5-5-12-8-20-8l-54 0c-8 0-15 3-20 8-5 6-8 12-8 20l0 55c0 7 3 14 8 19 5 5 12 8 20 8l54 0c8 0 15-3 20-8 5-5 8-12 8-19z m0 146l0-55c0-7-3-14-8-19-5-6-12-8-20-8l-54 0c-8 0-15 2-20 8-5 5-8 12-8 19l0 55c0 8 3 14 8 19 5 6 12 8 20 8l54 0c8 0 15-2 20-8 5-5 8-11 8-19z"/>
|
||||
<glyph unicode="z" d="M456 428c3-8 2-15-4-20l-141-141 0-212c0-8-4-14-11-17-3-1-5-1-7-1-6 0-10 1-13 5l-73 73c-4 4-6 8-6 13l0 139-141 141c-6 5-7 12-4 20 4 7 9 11 17 11l366 0c8 0 13-4 17-11z"/>
|
||||
<glyph unicode="A" d="M201 165c0-8-1-16-3-24-3-8-7-15-13-22-6-6-12-9-20-9-8 0-15 3-21 9-6 7-10 14-12 22-3 8-4 16-4 24 0 7 1 15 4 23 2 8 6 15 12 22 6 6 13 9 21 9 8 0 14-3 20-9 6-7 10-14 13-22 2-8 3-16 3-23z m183 0c0-8-1-16-4-24-2-8-6-15-12-22-6-6-13-9-21-9-8 0-14 3-20 9-6 7-10 14-13 22-2 8-3 16-3 24 0 7 1 15 3 23 3 8 7 15 13 22 6 6 12 9 20 9 8 0 15-3 21-9 6-7 10-14 12-22 3-8 4-16 4-23z m46 0c0 22-7 42-20 58-13 16-31 24-53 24-8 0-27-2-56-6-14-2-29-3-45-3-16 0-31 1-45 3-29 4-47 6-56 6-22 0-40-8-53-24-13-16-20-36-20-58 0-17 3-32 9-44 7-13 14-23 24-30 9-7 21-13 34-17 14-4 28-7 40-8 13-2 27-2 43-2l48 0c16 0 30 0 43 2 12 1 26 4 40 8 13 4 25 10 34 17 10 7 17 17 24 30 6 12 9 27 9 44z m64 50c0-40-6-71-18-95-7-14-17-27-30-38-13-10-26-19-40-24-14-6-30-11-49-14-18-3-34-5-49-6-14-1-30-1-47-1-15 0-29 0-41 0-12 1-26 2-42 4-16 2-31 5-44 9-13 3-26 8-39 14-13 6-24 14-34 23-11 10-19 21-25 33-12 24-18 55-18 95 0 45 13 83 39 113-5 16-8 32-8 49 0 22 5 42 15 62 21 0 39-4 54-11 16-8 34-20 54-36 28 7 58 10 89 10 28 0 54-3 80-9 20 16 37 27 53 35 16 7 34 11 54 11 10-20 15-40 15-62 0-17-3-33-8-48 26-31 39-69 39-114z"/>
|
||||
<glyph unicode="B" d="M293 119l0 55c0 2-1 5-3 6-2 2-4 3-7 3l-54 0c-3 0-5-1-7-3-2-1-3-4-3-6l0-55c0-3 1-5 3-7 2-1 4-2 7-2l54 0c3 0 5 1 7 2 2 2 3 4 3 7z m73 192c0 17-6 32-16 46-11 15-24 26-40 34-16 7-32 11-48 11-47 0-82-20-106-61-3-4-2-8 2-12l38-28c1-1 3-2 5-2 3 0 6 1 7 4 10 13 19 21 25 26 6 4 15 7 24 7 10 0 18-3 25-8 7-5 11-10 11-17 0-7-2-13-6-17-4-4-10-9-20-13-12-5-23-13-33-25-10-11-15-23-15-35l0-11c0-2 1-5 3-6 2-2 4-3 7-3l54 0c3 0 5 1 7 3 2 1 3 4 3 6 0 4 2 9 6 14 4 6 9 11 15 15 6 3 11 6 14 8 4 2 8 5 13 10 6 4 10 9 13 13 3 5 6 11 8 18 3 7 4 14 4 23z m109-55c0-40-9-77-29-110-20-34-46-60-80-80-33-20-70-29-110-29-40 0-77 9-110 29-34 20-60 46-80 80-20 33-29 70-29 110 0 40 9 77 29 110 20 34 46 60 80 80 33 20 70 29 110 29 40 0 77-9 110-29 34-20 60-46 80-80 20-33 29-70 29-110z"/>
|
||||
<glyph unicode="C" d="M468 210c0-1 0-1 0-2-12-51-38-92-77-124-38-32-84-47-136-47-28 0-55 5-81 15-26 11-49 26-69 45l-37-37c-4-3-8-5-13-5-5 0-9 2-13 5-4 4-5 8-5 13l0 128c0 5 1 9 5 13 4 4 8 5 13 5l128 0c5 0 9-1 13-5 3-4 5-8 5-13 0-5-2-9-5-13l-39-39c13-12 28-22 46-29 17-7 35-10 53-10 26 0 49 6 71 18 23 13 40 30 54 51 2 4 7 15 15 34 1 4 4 6 8 6l55 0c3 0 5 0 7-2 1-2 2-4 2-7z m7 229l0-128c0-5-1-9-5-13-4-4-8-5-13-5l-128 0c-5 0-9 1-13 5-3 4-5 8-5 13 0 5 2 9 5 13l40 39c-28 26-62 39-100 39-26 0-49-6-71-18-23-13-40-30-54-51-2-4-7-15-15-34-1-4-4-6-8-6l-57 0c-3 0-5 0-7 2-1 2-2 4-2 7l0 2c12 51 38 92 77 124 39 32 85 47 137 47 28 0 55-5 81-15 26-11 50-26 70-45l37 37c4 3 8 5 13 5 5 0 9-2 13-5 4-4 5-8 5-13z"/>
|
||||
<glyph unicode="D" d="M107 6c-2-7-7-8-14-4-6 3-8 9-8 17 2 35 10 73 26 116-34 53-43 107-27 162 4-11 9-24 17-40 7-16 15-29 22-41 8-12 13-17 17-15 2 1 2 15 0 42-3 27-5 55-6 85-1 30 3 57 13 81 7 15 21 31 41 48 19 17 37 29 53 36-8-16-14-32-17-49-3-16-4-29-2-40 2-10 5-15 11-16 4 0 18 21 43 62 24 40 42 61 54 62 16 1 35-4 58-15 24-11 38-22 42-33 4-8 4-22 0-41-4-18-11-33-20-42-15-15-40-26-75-32-35-6-54-10-58-12-6-4-4-9 6-18 18-16 48-19 90-10-19-27-42-47-70-58-27-12-49-18-67-20-18-1-27-3-28-5-1-8 7-17 25-27 18-11 36-13 52-8-10-19-21-33-32-43-12-9-21-15-28-17-7-3-20-5-39-6-19-1-33-3-43-4 0 0-36-115-36-115"/>
|
||||
<glyph unicode="E" d="M435 486c8 0 14-2 19-7 4-5 7-11 7-18 0 0 0-435 0-435 0 0-103 0-103 0 0 0 0 435 0 435 0 17 7 25 21 25 0 0 56 0 56 0m-153-153c7 0 13-3 18-8 5-5 7-11 7-18 0 0 0-281 0-281 0 0-102 0-102 0 0 0 0 281 0 281 0 17 7 26 20 26 0 0 57 0 57 0m-154-154c8 0 14-2 18-7 5-6 8-12 8-18 0 0 0-128 0-128 0 0-103 0-103 0 0 0 0 128 0 128 0 17 7 25 21 25 0 0 56 0 56 0"/>
|
||||
<glyph unicode="F" d="M388 461c0 0 73-80 73-80 0 0 0-279 0-279 0-13-5-25-15-35-10-11-22-16-36-16 0 0-308 0-308 0-13 0-25 5-35 16-11 10-16 22-16 35 0 0 0 308 0 308 0 14 5 26 16 36 10 10 22 15 35 15 0 0 286 0 286 0m-30-154c0 0 0 128 0 128 0 0-204 0-204 0 0 0 0-128 0-128 0-7 2-13 7-18 5-5 11-7 18-7 0 0 154 0 154 0 7 0 13 2 18 7 5 5 7 11 7 18m-25 103c0 0 0-103 0-103 0 0-51 0-51 0 0 0 0 103 0 103 0 0 51 0 51 0"/>
|
||||
<glyph unicode="G" d="M184 20c0 0 0 54 0 54 0 0 144 0 144 0 0 0 0-54 0-54-24-14-48-21-73-20-23-1-47 6-71 20m141 84c0 0-138 0-138 0 0 25-6 49-19 72-12 23-25 43-40 58-14 15-26 34-37 57-11 23-16 47-14 71 3 41 19 77 48 106 30 29 73 44 130 44 58 0 102-15 131-44 29-29 45-65 49-106 1-20-2-39-9-57-6-18-15-35-26-50-11-14-22-29-33-43-12-14-21-31-30-49-8-19-12-38-12-59m-193 254c-2-1-2-4 0-10 1-5 1-9 1-10-1-1 0-5 2-10 3-5 4-8 3-9 0-1 1-4 4-9 3-5 5-9 6-10 1-1 3-5 7-10 3-5 6-8 7-9 1-2 3-5 7-11 5-6 7-10 9-12 30-42 49-78 57-108 0 0 42 0 42 0 8 32 27 68 57 108 2 2 6 8 13 18 7 10 12 16 13 18 1 3 4 8 9 15 4 8 7 13 8 17 1 4 2 9 3 14 1 6 1 12 0 18-5 67-47 101-125 101-77 0-118-34-123-101"/>
|
||||
<glyph unicode="H" d="M256 484c-126 0-228-102-228-228 0-126 102-228 228-228 126 0 228 102 228 228 0 126-102 228-228 228z m0-399c-94 0-171 77-171 171 0 94 77 171 171 171 94 0 171-77 171-171 0-94-77-171-171-171z m-2 312c-23-2-40-23-37-46l12-118c2-13 12-24 26-26 16-1 30 10 31 26l13 118c0 3 0 6 0 8-2 23-22 40-45 38z m-21-220c-7-7-11-16-11-25 0-10 4-19 11-26 7-6 16-10 25-10 9 0 19 4 25 10 7 7 11 16 11 26 0 9-4 18-11 25-13 13-37 13-50 0z"/>
|
||||
<glyph unicode="I" d="M427 491l-363 0c-35 0-64-29-64-64l0-256c0-36 43-43 64-43l0-128 192 128 171 0c35 0 64 29 64 64l0 235c0 35-29 64-64 64z m21-299c0-12-10-21-21-21l-192 0-128-107 0 107-43 0c-12 0-21 9-21 21l0 235c0 11 9 21 21 21l363 0c11 0 21-10 21-21z"/>
|
||||
<glyph unicode="K" d="M128 384l64 0 0-64-64 0z m0-96l64 0 0-64-64 0z m0-96l64 0 0-64-64 0z m128 0l128 0 0-64-128 0z m224 320l-448 0c-18 0-32-14-32-32l0-448c0-18 14-32 32-32l448 0c18 0 32 14 32 32l0 448c0 18-14 32-32 32z m-32-448l-384 0 0 384 384 0z m-192 224l128 0 0-64-128 0z m0 96l128 0 0-64-128 0z"/>
|
||||
|
@ -49,7 +46,6 @@
|
|||
<glyph unicode="Q" d="M224 512c-123 0-223-104-223-232 0-128 100-231 223-231 52 0 100 18 137 49l99-98 51 52-101 101c23 37 37 80 37 127 0 128-100 232-223 232z m0-32c107 0 193-89 193-200 0-111-86-200-193-200-107 0-193 89-193 200 0 111 86 200 193 200z"/>
|
||||
<glyph unicode="L" d="M0 510l0-508 512 0 0 508z m52-51l409 0 0-408-409 0z m32-86l344 0 0-35-344 0z m0-68l344 0 0-35-344 0z m0-67l344 0 0-36-344 0z m0-68l344 0 0-35-344 0z"/>
|
||||
<glyph unicode="T" d="M0 455l0-398c0-32 25-57 57-57l398 0c32 0 57 25 57 57l0 398c0 32-25 57-57 57l-398 0c-32 0-57-25-57-57z m341-114c0-47-38-85-85-85-47 0-85 38-85 85 0 48 38 86 85 86 47 0 85-38 85-86z m-256-228c0 58 114 89 171 89 57 0 171-31 171-89l0-28-342 0z"/>
|
||||
<glyph unicode="J" d="M480 224l-64 0c-18 0-32 14-32 32 0 18 14 32 32 32l64 0c18 0 32-14 32-32 0-18-14-32-32-32z m-88 122c-13-12-33-12-45 0-13 13-13 33 0 46l45 45c12 12 33 12 45 0 13-13 13-33 0-45z m-136-346c-18 0-32 14-32 32l0 64c0 18 14 32 32 32 18 0 32-14 32-32l0-64c0-18-14-32-32-32z m0 384c-18 0-32 14-32 32l0 64c0 18 14 32 32 32 18 0 32-14 32-32l0-64c0-18-14-32-32-32z m-136-309c-12-13-32-13-45 0-12 12-12 33 0 45l45 45c13 13 33 13 46 0 12-12 12-32 0-45z m0 271l-45 46c-12 12-12 32 0 45 13 12 33 12 45 0l46-45c12-13 12-33 0-46-13-12-33-12-46 0z m8-90c0-18-14-32-32-32l-64 0c-18 0-32 14-32 32 0 18 14 32 32 32l64 0c18 0 32-14 32-32z m264-91l45-45c13-12 13-33 0-45-12-13-33-13-45 0l-45 45c-13 13-13 33 0 45 12 13 32 13 45 0z"/>
|
||||
<glyph unicode="N" d="M112 49l44-45 100 100 100-100 44 45-144 144z m288 414l-44 45-100-100-100 100-44-45 144-144z"/>
|
||||
<glyph unicode="U" d="M328 511l-284 1c0 0-2-336-2-492l46 0 59 38 43-58 60 97 56-75 57 56c5-5 12-11 19-18 8-8 17-17 25-24 7-7 12-13 17-16l46 0 0 349z m50-386l-16 15-51-51-65 86-59-97-29 39-63-46 0 393 223 1 0-102c0-2 0-3 1-4 1-1 3-1 4-1l95 0 0-277c-21 19-40 44-40 44z"/>
|
||||
<glyph unicode="R" d="M0 512l0-512 512 0 0 512z m52-51l179 0 0-102-179 0z m230 0l179 0 0-410-179 0z m-230-154l179 0 0-106-179 0z m0-157l179 0 0-99-179 0z"/>
|
||||
|
@ -59,4 +55,9 @@
|
|||
<glyph unicode="X" d="M456 343c0 1 0 1 0 1 0 5-2 10-5 13l0 1-40 69c-1 6-6 10-13 10 0 0 0 0-1 0l0 0-283 0 0 0c0 0 0 0 0 0-5 0-9-3-12-7l0 0-42-72 0 0c-3-4-4-9-4-14 0 0 0 0 0-1l0-247c0 0 0 0 0 0 0-12 9-21 20-21 1 0 1 0 1 0l358 0c0 0 0 0 0 0 12 0 21 9 21 21 0 0 0 0 0 0l0 247z m-131-125l-64-90c-1-1-3-2-5-2 0 0 0 0 0 0-2 0-4 1-5 2l-64 90c-1 2-1 4 0 6 1 2 3 3 5 3l30 0 0 81c0 3 3 6 6 6l56 0c3 0 6-3 6-6l0-81 30 0c2 0 4-1 5-3 1-2 1-4 0-6z m-231 147l27 47 270 0 27-47z"/>
|
||||
<glyph unicode="Y" d="M256 352l130-130 41 40-171 171-171-171 41-40z m-171-273l342 0 0 57-342 0z"/>
|
||||
<glyph unicode="Z" d="M171 128l170 0 0 171 114 0-199 199-199-199 114 0z m-114-57l398 0 0-57-398 0z"/>
|
||||
<glyph unicode="A" d="M201 165c0-8-1-16-3-24-3-8-7-15-13-22-6-6-12-9-20-9-8 0-15 3-21 9-6 7-10 14-12 22-3 8-4 16-4 24 0 7 1 15 4 23 2 8 6 15 12 22 6 6 13 9 21 9 8 0 14-3 20-9 6-7 10-14 13-22 2-8 3-16 3-23z m183 0c0-8-1-16-4-24-2-8-6-15-12-22-6-6-13-9-21-9-8 0-14 3-20 9-6 7-10 14-13 22-2 8-3 16-3 24 0 7 1 15 3 23 3 8 7 15 13 22 6 6 12 9 20 9 8 0 15-3 21-9 6-7 10-14 12-22 3-8 4-16 4-23z m46 0c0 22-7 42-20 58-13 16-31 24-53 24-8 0-27-2-56-6-14-2-29-3-45-3-16 0-31 1-45 3-29 4-47 6-56 6-22 0-40-8-53-24-13-16-20-36-20-58 0-17 3-32 9-44 7-13 14-23 24-30 9-7 21-13 34-17 14-4 28-7 40-8 13-2 27-2 43-2l48 0c16 0 30 0 43 2 12 1 26 4 40 8 13 4 25 10 34 17 10 7 17 17 24 30 6 12 9 27 9 44z m64 50c0-40-6-71-18-95-7-14-17-27-30-38-13-10-26-19-40-24-14-6-30-11-49-14-18-3-34-5-49-6-14-1-30-1-47-1-15 0-29 0-41 0-12 1-26 2-42 4-16 2-31 5-44 9-13 3-26 8-39 14-13 6-24 14-34 23-11 10-19 21-25 33-12 24-18 55-18 95 0 45 13 83 39 113-5 16-8 32-8 49 0 22 5 42 15 62 21 0 39-4 54-11 16-8 34-20 54-36 28 7 58 10 89 10 28 0 54-3 80-9 20 16 37 27 53 35 16 7 34 11 54 11 10-20 15-40 15-62 0-17-3-33-8-48 26-31 39-69 39-114z"/>
|
||||
<glyph unicode="x" d="M411 167l-182 0 0 0c0 0 0 0 0 0-6 0-11-6-11-12 0 0 0 0 0-1l0-53 0 0c0-6 5-11 11-11l0 0 182 0 0 0c6 0 11 5 11 11l0 53c0 1 0 1 0 1 0 6-5 12-11 12z m-256 0l-54 0c-6 0-11-6-11-12l0-54c0-6 5-11 11-11l54 0c6 0 12 5 12 11l0 54c0 6-6 12-12 12z m256 128l-182 0 0 0c0 0 0 0 0 0-6 0-11-6-11-12 0 0 0 0 0-1l0-53 0 0c0-6 5-11 11-11l0 0 182 0 0 0c6 0 11 5 11 11l0 53c0 1 0 1 0 1 0 6-5 12-11 12z m-256 0l-54 0c-6 0-11-6-11-12l0-54c0-6 5-11 11-11l54 0c6 0 12 5 12 11l0 54c0 6-6 12-12 12z m63 62l0 0c0-6 5-12 11-12l0 0 182 0 0 0c6 0 11 6 11 12l0 53c0 0 0 0 0 1 0 6-5 11-11 11l0 0-182 0 0 0c0 0 0 0 0 0-6 0-11-5-11-11 0-1 0-1 0-1l0-53z m-63 65l-54 0c-6 0-11-5-11-11l0-54c0-6 5-12 11-12l54 0c6 0 12 6 12 12l0 54c0 6-6 11-12 11z"/>
|
||||
<glyph unicode="G" d="M1 332l369 0 49-182 57 215-378 0 16 27 226 0 21 37 114 0c0 0 17 2 30-15 13-17 0-59 0-59l-72-272-368 0z"/>
|
||||
<glyph unicode="J" d="M494 327c0-4-3-9-8-14l-103-101 24-143c0-1 0-3 0-5 0-4-1-8-3-10-2-3-4-5-8-5-4 0-8 2-12 4l-128 67-128-67c-4-2-8-4-12-4-4 0-7 2-9 5-2 2-3 6-3 10 0 1 0 3 1 5l24 143-104 101c-4 6-7 10-7 14 0 7 6 12 16 13l144 21 64 130c4 8 8 12 14 12 6 0 10-4 14-12l64-130 144-21c10-1 16-6 16-13z"/>
|
||||
<glyph unicode="0" d="M343 225l88 85-121 18-54 109-54-109-121-18 88-85-21-120 108 57 108-57z m151 102c0-4-3-9-8-14l-103-101 24-143c0-1 0-3 0-5 0-10-3-15-11-15-4 0-8 2-12 4l-128 67-128-67c-4-2-8-4-12-4-4 0-7 2-9 5-2 2-3 6-3 10 0 1 0 3 1 5l24 143-104 101c-4 6-7 10-7 14 0 7 6 12 16 13l144 21 64 130c4 8 8 12 14 12 6 0 10-4 14-12l64-130 144-21c10-1 16-6 16-13z"/>
|
||||
</font></defs></svg>
|
||||
|
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 402 B |
|
@ -2,22 +2,23 @@ doctype html
|
|||
html(lang="en")
|
||||
head
|
||||
meta(charset="utf-8")
|
||||
title Taiga
|
||||
meta(http-equiv="content-type", content="text/html; charset=utf-8")
|
||||
meta(name="description", content="Taiga Landing page")
|
||||
meta(name="keywords", content="Agile, Taiga, Management, Github")
|
||||
meta(name="fragment", content="!")
|
||||
|
||||
// Main meta
|
||||
title Taiga
|
||||
meta(name="description", content="Taiga is a project management platform for startups and agile developers & designers who want a simple, beautiful tool that makes work truly enjoyable.")
|
||||
meta(name="keywords", content="agile, scrum, taiga, management, project, developer, designer, user experience")
|
||||
//-meta(name="viewport", content="width=device-width, user-scalable=no")
|
||||
link(rel="stylesheet", href="/styles/main.css")
|
||||
link(rel="icon", type="image/png", href="/images/favicon.png")
|
||||
|
||||
//- PRERENDER SERVICE: This is to know when the page is completely loaded.
|
||||
script(type='text/javascript').
|
||||
window.prerenderReady = false;
|
||||
|
||||
body(tg-main)
|
||||
include partials/includes/modules/projects-nav
|
||||
|
||||
//- the content of nav.menu is in coffe.modules.base TaigaMain directive
|
||||
nav.menu.hidden(tg-project-menu)
|
||||
|
||||
include partials/includes/components/notification-message
|
||||
div(tg-navigation-bar)
|
||||
|
||||
div.master(ng-view)
|
||||
|
||||
|
@ -31,13 +32,11 @@ html(lang="en")
|
|||
include partials/includes/modules/lightbox-generic-error
|
||||
div.lightbox.lightbox-generic-loading
|
||||
include partials/includes/modules/lightbox-generic-loading
|
||||
div.lightbox.lightbox-search(tg-search-box)
|
||||
include partials/includes/modules/lightbox-search
|
||||
div.lightbox.lightbox-feedback.lightbox-generic-form(tg-lb-feedback)
|
||||
include partials/includes/modules/lightbox-feedback
|
||||
|
||||
include partials/includes/modules/loader
|
||||
|
||||
include partials/includes/components/notification-message
|
||||
|
||||
script(src="/js/libs.js?v=#{v}")
|
||||
script(src="/js/templates.js?v=#{v}")
|
||||
script(src="/js/app-loader.js?v=#{v}")
|
||||
|
|
|
@ -0,0 +1,326 @@
|
|||
/*
|
||||
--replace
|
||||
minError -> angular.$$minErr
|
||||
isString -> angular.isString
|
||||
isArray -> angular.isArray
|
||||
var expression = $attr.ngRepeat; -> var expression = $attr.tgRepeat;
|
||||
forEach(nextBlockOrder, function(block) { -> nextBlockOrder.forEach(function(block) {
|
||||
$scope.$watchCollection(rhs, function ngRepeatAction(collection) {
|
||||
->
|
||||
$scope.$watch(rhs, function ngRepeatAction(immutable_collection) {
|
||||
var collection = []
|
||||
|
||||
if (immutable_collection.toJS) {
|
||||
collection = immutable_collection.toJS();
|
||||
}
|
||||
$scope[aliasAs] = collection; -> $scope[aliasAs] = immutable_collection;
|
||||
|
||||
value = collection[key];
|
||||
immutable_value = immutable_collection.get(key); #x2
|
||||
|
||||
trackById = trackByIdFn(key, value, index);
|
||||
->
|
||||
trackById = trackByIdFn(key, immutable_value, index);
|
||||
|
||||
updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength);
|
||||
-> (x2)
|
||||
updateScope(block.scope, index, valueIdentifier, immutable_value, keyIdentifier, key, collectionLength);
|
||||
|
||||
--copy from angular
|
||||
copy angular hashKey
|
||||
copy angular createMap
|
||||
copy angular isArrayLike
|
||||
copy angular isWindow
|
||||
copy angular NODE_TYPE_ELEMENT
|
||||
copy angular nextUid
|
||||
copy angular getBlockNodes
|
||||
--add
|
||||
jqLite = $
|
||||
var uid = 0;
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var NODE_TYPE_ELEMENT = 1;
|
||||
var uid = 0;
|
||||
|
||||
function nextUid() {
|
||||
return ++uid;
|
||||
}
|
||||
|
||||
function hashKey(obj, nextUidFn) {
|
||||
var key = obj && obj.$$hashKey;
|
||||
|
||||
if (key) {
|
||||
if (typeof key === 'function') {
|
||||
key = obj.$$hashKey();
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
var objType = typeof obj;
|
||||
if (objType == 'function' || (objType == 'object' && obj !== null)) {
|
||||
key = obj.$$hashKey = objType + ':' + (nextUidFn || nextUid)();
|
||||
} else {
|
||||
key = objType + ':' + obj;
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
function createMap() {
|
||||
return Object.create(null);
|
||||
}
|
||||
|
||||
function isArrayLike(obj) {
|
||||
if (obj == null || isWindow(obj)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var length = obj.length;
|
||||
|
||||
if (obj.nodeType === NODE_TYPE_ELEMENT && length) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return angular.isString(obj) || angular.isArray(obj) || length === 0 ||
|
||||
typeof length === 'number' && length > 0 && (length - 1) in obj;
|
||||
}
|
||||
|
||||
function isWindow(obj) {
|
||||
return obj && obj.window === obj;
|
||||
}
|
||||
|
||||
function isString(value) {return typeof value === 'string';}
|
||||
|
||||
function getBlockNodes(nodes) {
|
||||
// TODO(perf): just check if all items in `nodes` are siblings and if they are return the original
|
||||
// collection, otherwise update the original collection.
|
||||
var node = nodes[0];
|
||||
var endNode = nodes[nodes.length - 1];
|
||||
var blockNodes = [node];
|
||||
|
||||
do {
|
||||
node = node.nextSibling;
|
||||
if (!node) break;
|
||||
blockNodes.push(node);
|
||||
} while (node !== endNode);
|
||||
|
||||
return jqLite(blockNodes);
|
||||
}
|
||||
|
||||
var isArray = Array.isArray;
|
||||
|
||||
var jqLite = $;
|
||||
|
||||
var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
|
||||
var NG_REMOVED = '$$NG_REMOVED';
|
||||
var ngRepeatMinErr = angular.$$minErr('ngRepeat');
|
||||
var updateScope = function(scope, index, valueIdentifier, value, keyIdentifier, key, arrayLength) {
|
||||
// TODO(perf): generate setters to shave off ~40ms or 1-1.5%
|
||||
scope[valueIdentifier] = value;
|
||||
if (keyIdentifier) scope[keyIdentifier] = key;
|
||||
scope.$index = index;
|
||||
scope.$first = (index === 0);
|
||||
scope.$last = (index === (arrayLength - 1));
|
||||
scope.$middle = !(scope.$first || scope.$last);
|
||||
// jshint bitwise: false
|
||||
scope.$odd = !(scope.$even = (index&1) === 0);
|
||||
// jshint bitwise: true
|
||||
};
|
||||
var getBlockStart = function(block) {
|
||||
return block.clone[0];
|
||||
};
|
||||
var getBlockEnd = function(block) {
|
||||
return block.clone[block.clone.length - 1];
|
||||
};
|
||||
return {
|
||||
restrict: 'A',
|
||||
multiElement: true,
|
||||
transclude: 'element',
|
||||
priority: 1000,
|
||||
terminal: true,
|
||||
$$tlb: true,
|
||||
compile: function ngRepeatCompile($element, $attr) {
|
||||
var expression = $attr.tgRepeat;
|
||||
var ngRepeatEndComment = document.createComment(' end ngRepeat: ' + expression + ' ');
|
||||
var match = expression.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+track\s+by\s+([\s\S]+?))?\s*$/);
|
||||
if (!match) {
|
||||
throw ngRepeatMinErr('iexp', "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.",
|
||||
expression);
|
||||
}
|
||||
var lhs = match[1];
|
||||
var rhs = match[2];
|
||||
var aliasAs = match[3];
|
||||
var trackByExp = match[4];
|
||||
|
||||
match = lhs.match(/^(?:(\s*[\$\w]+)|\(\s*([\$\w]+)\s*,\s*([\$\w]+)\s*\))$/);
|
||||
if (!match) {
|
||||
throw ngRepeatMinErr('iidexp', "'_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.",
|
||||
lhs);
|
||||
}
|
||||
var valueIdentifier = match[3] || match[1];
|
||||
var keyIdentifier = match[2];
|
||||
if (aliasAs && (!/^[$a-zA-Z_][$a-zA-Z0-9_]*$/.test(aliasAs) ||
|
||||
/^(null|undefined|this|\$index|\$first|\$middle|\$last|\$even|\$odd|\$parent|\$root|\$id)$/.test(aliasAs))) {
|
||||
throw ngRepeatMinErr('badident', "alias '{0}' is invalid --- must be a valid JS identifier which is not a reserved name.",
|
||||
aliasAs);
|
||||
}
|
||||
var trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn;
|
||||
var hashFnLocals = {$id: hashKey};
|
||||
if (trackByExp) {
|
||||
trackByExpGetter = $parse(trackByExp);
|
||||
} else {
|
||||
trackByIdArrayFn = function(key, value) {
|
||||
return hashKey(value);
|
||||
};
|
||||
trackByIdObjFn = function(key) {
|
||||
return key;
|
||||
};
|
||||
}
|
||||
return function ngRepeatLink($scope, $element, $attr, ctrl, $transclude) {
|
||||
if (trackByExpGetter) {
|
||||
trackByIdExpFn = function(key, value, index) {
|
||||
// assign key, value, and $index to the locals so that they can be used in hash functions
|
||||
if (keyIdentifier) hashFnLocals[keyIdentifier] = key;
|
||||
hashFnLocals[valueIdentifier] = value;
|
||||
hashFnLocals.$index = index;
|
||||
return trackByExpGetter($scope, hashFnLocals);
|
||||
};
|
||||
}
|
||||
// Store a list of elements from previous run. This is a hash where key is the item from the
|
||||
// iterator, and the value is objects with following properties.
|
||||
// - scope: bound scope
|
||||
// - element: previous element.
|
||||
// - index: position
|
||||
//
|
||||
// We are using no-proto object so that we don't need to guard against inherited props via
|
||||
// hasOwnProperty.
|
||||
var lastBlockMap = createMap();
|
||||
$scope.$watch(rhs, function ngRepeatAction(immutable_collection) {
|
||||
var collection = []
|
||||
|
||||
if (immutable_collection && immutable_collection.toJS) {
|
||||
collection = immutable_collection.toJS();
|
||||
}
|
||||
|
||||
var index, length,
|
||||
previousNode = $element[0], // node that cloned nodes should be inserted after
|
||||
// initialized to the comment node anchor
|
||||
nextNode,
|
||||
// Same as lastBlockMap but it has the current state. It will become the
|
||||
// lastBlockMap on the next iteration.
|
||||
nextBlockMap = createMap(),
|
||||
collectionLength,
|
||||
key, value, // key/value of iteration
|
||||
trackById,
|
||||
trackByIdFn,
|
||||
collectionKeys,
|
||||
block, // last object information {scope, element, id}
|
||||
nextBlockOrder,
|
||||
elementsToRemove;
|
||||
if (aliasAs) {
|
||||
$scope[aliasAs] = immutable_collection;
|
||||
}
|
||||
if (isArrayLike(collection)) {
|
||||
collectionKeys = collection;
|
||||
trackByIdFn = trackByIdExpFn || trackByIdArrayFn;
|
||||
} else {
|
||||
trackByIdFn = trackByIdExpFn || trackByIdObjFn;
|
||||
// if object, extract keys, in enumeration order, unsorted
|
||||
collectionKeys = [];
|
||||
for (var itemKey in collection) {
|
||||
if (collection.hasOwnProperty(itemKey) && itemKey.charAt(0) !== '$') {
|
||||
collectionKeys.push(itemKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
collectionLength = collectionKeys.length;
|
||||
nextBlockOrder = new Array(collectionLength);
|
||||
// locate existing items
|
||||
for (index = 0; index < collectionLength; index++) {
|
||||
key = (collection === collectionKeys) ? index : collectionKeys[index];
|
||||
value = collection[key];
|
||||
immutable_value = immutable_collection.get(key);
|
||||
trackById = trackByIdFn(key, immutable_value, index);
|
||||
if (lastBlockMap[trackById]) {
|
||||
// found previously seen block
|
||||
block = lastBlockMap[trackById];
|
||||
delete lastBlockMap[trackById];
|
||||
nextBlockMap[trackById] = block;
|
||||
nextBlockOrder[index] = block;
|
||||
} else if (nextBlockMap[trackById]) {
|
||||
// if collision detected. restore lastBlockMap and throw an error
|
||||
nextBlockOrder.forEach(function(block) {
|
||||
if (block && block.scope) lastBlockMap[block.id] = block;
|
||||
});
|
||||
throw ngRepeatMinErr('dupes',
|
||||
"Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}, Duplicate value: {2}",
|
||||
expression, trackById, value);
|
||||
} else {
|
||||
// new never before seen block
|
||||
nextBlockOrder[index] = {id: trackById, scope: undefined, clone: undefined};
|
||||
nextBlockMap[trackById] = true;
|
||||
}
|
||||
}
|
||||
// remove leftover items
|
||||
for (var blockKey in lastBlockMap) {
|
||||
block = lastBlockMap[blockKey];
|
||||
elementsToRemove = getBlockNodes(block.clone);
|
||||
$animate.leave(elementsToRemove);
|
||||
if (elementsToRemove[0].parentNode) {
|
||||
// if the element was not removed yet because of pending animation, mark it as deleted
|
||||
// so that we can ignore it later
|
||||
for (index = 0, length = elementsToRemove.length; index < length; index++) {
|
||||
elementsToRemove[index][NG_REMOVED] = true;
|
||||
}
|
||||
}
|
||||
block.scope.$destroy();
|
||||
}
|
||||
// we are not using forEach for perf reasons (trying to avoid #call)
|
||||
for (index = 0; index < collectionLength; index++) {
|
||||
key = (collection === collectionKeys) ? index : collectionKeys[index];
|
||||
value = collection[key];
|
||||
immutable_value = immutable_collection.get(key);
|
||||
block = nextBlockOrder[index];
|
||||
if (block.scope) {
|
||||
// if we have already seen this object, then we need to reuse the
|
||||
// associated scope/element
|
||||
nextNode = previousNode;
|
||||
// skip nodes that are already pending removal via leave animation
|
||||
do {
|
||||
nextNode = nextNode.nextSibling;
|
||||
} while (nextNode && nextNode[NG_REMOVED]);
|
||||
if (getBlockStart(block) != nextNode) {
|
||||
// existing item which got moved
|
||||
$animate.move(getBlockNodes(block.clone), null, jqLite(previousNode));
|
||||
}
|
||||
previousNode = getBlockEnd(block);
|
||||
updateScope(block.scope, index, valueIdentifier, immutable_value, keyIdentifier, key, collectionLength);
|
||||
} else {
|
||||
// new item which we don't know about
|
||||
$transclude(function ngRepeatTransclude(clone, scope) {
|
||||
block.scope = scope;
|
||||
// http://jsperf.com/clone-vs-createcomment
|
||||
var endNode = ngRepeatEndComment.cloneNode(false);
|
||||
clone[clone.length++] = endNode;
|
||||
// TODO(perf): support naked previousNode in `enter` to avoid creation of jqLite wrapper?
|
||||
$animate.enter(clone, null, jqLite(previousNode));
|
||||
previousNode = endNode;
|
||||
// Note: We only need the first/last node of the cloned nodes.
|
||||
// However, we need to keep the reference to the jqlite wrapper as it might be changed later
|
||||
// by a directive with templateUrl when its template arrives.
|
||||
block.clone = clone;
|
||||
nextBlockMap[block.id] = block;
|
||||
updateScope(block.scope, index, valueIdentifier, immutable_value, keyIdentifier, key, collectionLength);
|
||||
});
|
||||
}
|
||||
}
|
||||
lastBlockMap = nextBlockMap;
|
||||
});
|
||||
};
|
||||
}
|
||||
};
|
||||
}];
|
||||
|
||||
angular.module("tgRepeat", []).directive("tgRepeat", ngRepeatDirective);
|
||||
})();
|
|
@ -100,6 +100,10 @@
|
|||
"SAT": "Ds"
|
||||
}
|
||||
},
|
||||
"SEE_USER_PROFILE": "See {{username }} profile",
|
||||
"USER_STORY": "Història d'usuari",
|
||||
"TASK": "Task",
|
||||
"ISSUE": "Issue",
|
||||
"TAGS": {
|
||||
"PLACEHOLDER": "Afegir tag",
|
||||
"DELETE": "Elimina l'etiqueta",
|
||||
|
@ -125,7 +129,8 @@
|
|||
"ASSIGNED_TO": "Assignat a",
|
||||
"POINTS": "Punts",
|
||||
"BLOCKED_NOTE": "Nota de bloqueig",
|
||||
"IS_BLOCKED": "està bloquejat"
|
||||
"IS_BLOCKED": "està bloquejat",
|
||||
"REF": "Ref"
|
||||
},
|
||||
"ROLES": {
|
||||
"ALL": "Tot"
|
||||
|
@ -231,14 +236,107 @@
|
|||
"ADD_WIKI_LINKS": "Afegir link de wiki",
|
||||
"DELETE_WIKI_LINKS": "Esborrar enllaços de wiki"
|
||||
}
|
||||
},
|
||||
"META": {
|
||||
"PAGE_TITLE": "Taiga",
|
||||
"PAGE_DESCRIPTION": "Taiga is a project management platform for startups and agile developers & designers who want a simple, beautiful tool that makes work truly enjoyable."
|
||||
}
|
||||
},
|
||||
"LOGIN": {
|
||||
"PAGE_TITLE": "Login - Taiga",
|
||||
"PAGE_DESCRIPTION": "Logging in to Taiga, a project management platform for startups and agile developers & designers who want a simple, beautiful tool that makes work truly enjoyable."
|
||||
},
|
||||
"AUTH": {
|
||||
"INVITED_YOU": "T'ha convidat a participar en el projecte",
|
||||
"NOT_REGISTERED_YET": "No t'has registrat encara?",
|
||||
"REGISTER": "Registrat",
|
||||
"CREATE_ACCOUNT": "Crea el teu conter gratis ací"
|
||||
},
|
||||
"LOGIN_COMMON": {
|
||||
"HEADER": "Ja tinc un conter de Taiga",
|
||||
"PLACEHOLDER_AUTH_NAME": "Nom d'usuari i correu electrònic (sensible a majúscules i minúscules)",
|
||||
"LINK_FORGOT_PASSWORD": "L'has oblidat?",
|
||||
"TITLE_LINK_FORGOT_PASSWORD": "Has oblidat la teua contrasenya?",
|
||||
"ACTION_ENTER": "Entrar",
|
||||
"ACTION_SIGN_IN": "Entrar",
|
||||
"PLACEHOLDER_AUTH_PASSWORD": "Contrasenya (sensible a majúscules i minúscules)"
|
||||
},
|
||||
"LOGIN_FORM": {
|
||||
"ERROR_AUTH_INCORRECT": "Segons els Oompa Loompas, el vostre nom d'usuari/correu electrònic o contrasenya són incorrectes.",
|
||||
"SUCCESS": "Our Oompa Loompas están contents, benvinguts a Taiga."
|
||||
},
|
||||
"REGISTER": {
|
||||
"PAGE_TITLE": "Register - Taiga",
|
||||
"PAGE_DESCRIPTION": "Create your account in Taiga, a project management platform for startups and agile developers & designers who want a simple, beautiful tool that makes work truly enjoyable."
|
||||
},
|
||||
"REGISTER_FORM": {
|
||||
"TITLE": "Register a new Taiga account (free)",
|
||||
"PLACEHOLDER_NAME": "Trieu un nom d'usuari (sensible a majúscules i minúscules)",
|
||||
"PLACEHOLDER_FULL_NAME": "Escriu el teu nom complet",
|
||||
"PLACEHOLDER_EMAIL": "El teu correu",
|
||||
"PLACEHOLDER_PASSWORD": "Tria una contrasenya(sensible a majúscules i minúscules)",
|
||||
"ACTION_SIGN_UP": "Registrar-se",
|
||||
"TITLE_LINK_LOGIN": "Entrar",
|
||||
"LINK_LOGIN": "Ja estàs registrat? Entra"
|
||||
},
|
||||
"FORGOT_PASSWORD": {
|
||||
"PAGE_TITLE": "Forgot password - Taiga",
|
||||
"PAGE_DESCRIPTION": "Enter your username or email to get a new password and you can access to Taiga again."
|
||||
},
|
||||
"FORGOT_PASSWORD_FORM": {
|
||||
"TITLE": "Oops, has oblidat la teua contrasenya?",
|
||||
"SUBTITLE": "Escriviu el vostre nom d'usuari o correu electrònic per a conseguir-ne un de nou",
|
||||
"PLACEHOLDER_FIELD": "Nom d'usuari o correu electrònic",
|
||||
"ACTION_RESET_PASSWORD": "Resetejar contrasenya",
|
||||
"LINK_CANCEL": "No, portam enrere, crec que ho recorde.",
|
||||
"SUCCESS": "<strong>Mira el teu correu!</strong><br /> Hem enviat un correu amb les instrucciones per a setejar una nova contrasenya.",
|
||||
"ERROR": "Segons els nostres Oompa Loompas, no estàs registrat encara."
|
||||
},
|
||||
"CHANGE_PASSWORD": {
|
||||
"PAGE_TITLE": "Change you password - Taiga",
|
||||
"PAGE_DESCRIPTION": "Set a new passoword for your Taiga account and hey!, you may want to eat some more iron-rich food, it's good for your brain :P",
|
||||
"SECTION_NAME": "Canvi de contrasenya",
|
||||
"FIELD_CURRENT_PASSWORD": "Contrasenya actual",
|
||||
"PLACEHOLDER_CURRENT_PASSWORD": "La teua contrasenya actua (buit si no tens contrasenya encara)",
|
||||
"FIELD_NEW_PASSWORD": "Nova contrasenya",
|
||||
"PLACEHOLDER_NEW_PASSWORD": "Escriu una nova contrasenya",
|
||||
"FIELD_RETYPE_PASSWORD": "Reescriu contrasenya",
|
||||
"PLACEHOLDER_RETYPE_PASSWORD": "Reescriu contrasenya",
|
||||
"ERROR_PASSWORD_MATCH": "Les contrasenyes no coincideixen"
|
||||
},
|
||||
"CHANGE_PASSWORD_RECOVERY_FORM": {
|
||||
"TITLE": "Crea un nou password",
|
||||
"SUBTITLE": "Menja un poc més de ferro, es bo pel cervell :P ",
|
||||
"PLACEHOLDER_RECOVER_PASSWORD_TOKEN": "Recuperar token de contrasenya",
|
||||
"LINK_NEED_TOKEN": "Neccesites un?",
|
||||
"TITLE_LINK_NEED_TOKEN": "Necessites un token per a recuperar la teua contrasenya perque l'has oblidat?",
|
||||
"PLACEHOLDER_NEW_PASSWORD": "nova contrasenya",
|
||||
"PLACEHOLDER_RE_TYPE_NEW_PASSWORD": "Reescriu la nova contrasenya",
|
||||
"ACTION_RESET_PASSWORD": "Resetejar contrasenya",
|
||||
"SUCCESS": "Els Oompa Loompas han salvat la teua contrasenya <br /> Prova a <strong>entrar</strong> amb ella."
|
||||
},
|
||||
"INVITATION": {
|
||||
"PAGE_TITLE": "Invitation acceptance - Taiga",
|
||||
"PAGE_DESCRIPTION": "Accept the invitation to join a project in Taiga, a project management platform for startups and agile developers & designers who want a simple, beautiful tool that makes work truly enjoyable."
|
||||
},
|
||||
"INVITATION_LOGIN_FORM": {
|
||||
"NOT_FOUND": "<strong>Ooops, ha hagut un problema</strong><br />Els nosters Oompa Loompas no troben la teua invitació.",
|
||||
"SUCCESS": "T'has incorporat a este projecte. Vos donem la benvinguda a {{project_name}}",
|
||||
"ERROR": "Segons els nostres OOmpa Loompas, no estàs registrat encara o has escrit una contrasenya invàlida."
|
||||
},
|
||||
"HOME": {
|
||||
"PAGE_TITLE": "Home - Taiga",
|
||||
"PAGE_DESCRIPTION": "The Taiga home page with your main projects and all your assigned and watched user stories, tasks and issues",
|
||||
"EMPTY_WATCHING": "<strong>Follow</strong> the projects, User Stories, Tasks, Issues... that you want to know about :)",
|
||||
"EMPTY_PROJECT_LIST": "You don't have any projects yet",
|
||||
"WORKING_ON_SECTION": "Working on",
|
||||
"WATCHING_SECTION": "Watching"
|
||||
},
|
||||
"PROJECTS": {
|
||||
"PAGE_TITLE": "My projects - Taiga",
|
||||
"PAGE_DESCRIPTION": "A list with all your projects, you can reorder or create a new one.",
|
||||
"MY_PROJECTS": "My projects"
|
||||
},
|
||||
"ATTACHMENT": {
|
||||
"SECTION_NAME": "Adjunts",
|
||||
"TITLE": "{{ fileName }} pujat el {{ date }}",
|
||||
|
@ -276,6 +374,7 @@
|
|||
},
|
||||
"MEMBERSHIPS": {
|
||||
"TITLE": "Gestió de Membres",
|
||||
"PAGE_TITLE": "Memberships - {{projectName}}",
|
||||
"ADD_BUTTON": "+ Nou membre",
|
||||
"ADD_BUTTON_TITLE": "Afegir nou membre"
|
||||
},
|
||||
|
@ -311,7 +410,7 @@
|
|||
"SALT_CHAT_ROOM": "Pots afegir un code salt a la sala de xat"
|
||||
},
|
||||
"PROJECT_PROFILE": {
|
||||
"PAGE_TITLE": "Perfil de projecte - {{sectionName}} - {{projectName}}",
|
||||
"PAGE_TITLE": "{{sectionName}} - Project profile - {{projectName}}",
|
||||
"PROJECT_DETAILS": "Detalls de projecte",
|
||||
"PROJECT_NAME": "Nom del projecte",
|
||||
"PROJECT_SLUG": "Slug de projecte",
|
||||
|
@ -352,23 +451,26 @@
|
|||
"ISSUE_ADD": "Afegix camps personalitzats en incidències"
|
||||
},
|
||||
"PROJECT_VALUES": {
|
||||
"APP_TITLE": "Valors de projecte - {{sectionName}} - {{projectName}}",
|
||||
"PAGE_TITLE": "{{sectionName}} - Project values - {{projectName}}",
|
||||
"REPLACEMENT": "Tots els elements amb aquest valor seràn canviats a",
|
||||
"ERROR_DELETE_ALL": "No pots esborrar tots els valors."
|
||||
},
|
||||
"PROJECT_VALUES_POINTS": {
|
||||
"TITLE": "Punts d'US",
|
||||
"TITLE": "Points",
|
||||
"SUBTITLE": "Especifica els punts en els que poden ser estimades les històries d'usuari",
|
||||
"US_TITLE": "US points",
|
||||
"ACTION_ADD": "Afegir punts nous"
|
||||
},
|
||||
"PROJECT_VALUES_PRIORITIES": {
|
||||
"TITLE": "Prioritats d'incidències",
|
||||
"TITLE": "Priorities",
|
||||
"SUBTITLE": "Especifica les prioritats que tindran les teues tasques",
|
||||
"ISSUE_TITLE": "Issue priorities",
|
||||
"ACTION_ADD": "Add new priority"
|
||||
},
|
||||
"PROJECT_VALUES_SEVERITIES": {
|
||||
"TITLE": "Severitat d'incidències",
|
||||
"TITLE": "Severities",
|
||||
"SUBTITLE": "Especifica les severitats que tindran les teues incidències",
|
||||
"ISSUE_TITLE": "Issue severities",
|
||||
"ACTION_ADD": "Add new severity"
|
||||
},
|
||||
"PROJECT_VALUES_STATUS": {
|
||||
|
@ -382,10 +484,10 @@
|
|||
"TITLE": "Tipus",
|
||||
"SUBTITLE": "Especifica quin tipus d'incidència podria ser.",
|
||||
"ISSUE_TITLE": "Tipus d'incidències",
|
||||
"ACTION_ADD": "Add new type"
|
||||
"ACTION_ADD": "Afegir now {{objName}}"
|
||||
},
|
||||
"ROLES": {
|
||||
"SECTION_NAME": "Rols - {{projectName}}",
|
||||
"PAGE_TITLE": "Roles - {{projectName}}",
|
||||
"WARNING_NO_ROLE": "Ves amb compte, cap rol en el teu projecte pot estimar punts per a les històries d'usuari",
|
||||
"HELP_ROLE_ENABLED": "Si està activat, els membres assignats a aquest rol podràn estimar els punts d'històries d'usuaris",
|
||||
"COUNT_MEMBERS": "{{ role.members_count }} membres amb aquest rol",
|
||||
|
@ -402,20 +504,20 @@
|
|||
},
|
||||
"BITBUCKET": {
|
||||
"SECTION_NAME": "Bitbucket",
|
||||
"APP_TITLE": "Bitbucket - {{projectName}}",
|
||||
"PAGE_TITLE": "Bitbucket - {{projectName}}",
|
||||
"INFO_VERIFYING_IP": "Les peticions a Bitbuket no estan signades. El millor mode de verificar l'oritge es per IP. Si el camp està buit no hi haurà verificació per IP."
|
||||
},
|
||||
"GITLAB": {
|
||||
"SECTION_NAME": "Gitlab",
|
||||
"APP_TITLE": "Gitlab - {{projectName}}",
|
||||
"PAGE_TITLE": "Gitlab - {{projectName}}",
|
||||
"INFO_VERIFYING_IP": "Les peticions a Bitbuket no estan signades. El millor mode de verificar l'oritge es per IP. Si el camp està buit no hi haurà verificació per IP."
|
||||
},
|
||||
"GITHUB": {
|
||||
"SECTION_NAME": "Github",
|
||||
"APP_TITLE": "Github - {{projectName}}"
|
||||
"PAGE_TITLE": "Github - {{projectName}}"
|
||||
},
|
||||
"WEBHOOKS": {
|
||||
"APP_TITLE": "Webhooks - {{projectName}}",
|
||||
"PAGE_TITLE": "Webhooks - {{projectName}}",
|
||||
"SECTION_NAME": "Webhooks",
|
||||
"SUBTITLE": "Els Webhooks notifiquen serveis extens de events en taiga com comentaris, històries d'usuari...",
|
||||
"ADD_NEW": "Afegir un nou Webhook",
|
||||
|
@ -441,6 +543,7 @@
|
|||
"WEBHOOK_NAME": "Webhook '{{name}}'"
|
||||
},
|
||||
"CUSTOM_ATTRIBUTES": {
|
||||
"PAGE_TITLE": "{{sectionName}} - Custom Attributes - {{projectName}}",
|
||||
"ADD": "Afegix camp personalitzat",
|
||||
"EDIT": "Edita el camp personalitzat",
|
||||
"DELETE": "Esborrar camp personalitzat",
|
||||
|
@ -518,9 +621,36 @@
|
|||
"TITLE": "Serveis"
|
||||
}
|
||||
},
|
||||
"USER": {
|
||||
"PROFILE": {
|
||||
"PAGE_TITLE": "{{userFullName}} (@{{userUsername}})",
|
||||
"EDIT": "Edit profile",
|
||||
"FOLLOW": "Follow",
|
||||
"PROJECTS": "Projectes",
|
||||
"CLOSED_US": "Closed US",
|
||||
"CONTACTS": "Contacts",
|
||||
"REPORT": "Report Abuse",
|
||||
"ACTIVITY_TAB": "Activity Tab",
|
||||
"PROJECTS_TAB": "Projects Tab",
|
||||
"CONTACTS_TAB": "Contacts Tab",
|
||||
"FAVORITES_TAB": "Favorites Tab",
|
||||
"CONTACTS_EMPTY": "{{username}} doesn't have contacts yet",
|
||||
"CURRENT_USER_CONTACTS_EMPTY": "You don't have contacts yet",
|
||||
"CURRENT_USER_CONTACTS_EMPTY_EXPLAIN": "The people with whom you work at Taiga will be your contacts automatically",
|
||||
"PROJECTS_EMPTY": "{{username}} doesn't' have projects yet"
|
||||
},
|
||||
"PROFILE_SIDEBAR": {
|
||||
"TITLE": "Your profile",
|
||||
"DESCRIPTION": "La gent pot vore tot el que fas i en qué estàs treballant. Afegix una bio interessant per a donar una millor versió de la teua informació.",
|
||||
"ADD_INFO": "Edita la teua bio"
|
||||
}
|
||||
},
|
||||
"PROJECT": {
|
||||
"PAGE_TITLE": "{{projectName}}",
|
||||
"WELCOME": "Benvinguts",
|
||||
"SECTION_PROJECTS": "Projectes",
|
||||
"HELP": "Reorder your projects to set in the top the most used ones.<br/> The top 10 projects will appear in the top navigation bar project list",
|
||||
"PRIVATE": "Projecte privat",
|
||||
"STATS": {
|
||||
"PROJECT": "punts<br/> projecte",
|
||||
"DEFINED": "punts<br/> definits",
|
||||
|
@ -529,6 +659,7 @@
|
|||
},
|
||||
"SECTION": {
|
||||
"SEARCH": "Cerca",
|
||||
"TIMELINE": "Timeline",
|
||||
"BACKLOG": "Backlog",
|
||||
"KANBAN": "Kanban",
|
||||
"ISSUES": "Incidències",
|
||||
|
@ -541,9 +672,32 @@
|
|||
"SECTION_TITLE": "Els teus projectes",
|
||||
"PLACEHOLDER_SEARCH": "Cerca en...",
|
||||
"ACTION_CREATE_PROJECT": "Crear projecte",
|
||||
"TITLE_ACTION_IMPORT": "Importar projecte",
|
||||
"ACTION_IMPORT_PROJECT": "Import project",
|
||||
"SEE_MORE_PROJECTS": "See more projects",
|
||||
"TITLE_CREATE_PROJECT": "Create project",
|
||||
"TITLE_IMPORT_PROJECT": "Import project",
|
||||
"TITLE_PRVIOUS_PROJECT": "Mostra projectes previs",
|
||||
"TITLE_NEXT_PROJECT": "Mostrar próxims projectes"
|
||||
"TITLE_NEXT_PROJECT": "Mostrar próxims projectes",
|
||||
"HELP_TITLE": "Taiga Support Page",
|
||||
"HELP": "Help",
|
||||
"FEEDBACK_TITLE": "Enviar sugerències",
|
||||
"FEEDBACK": "Sugerències",
|
||||
"NOTIFICATIONS_TITLE": "Edit your notification settings",
|
||||
"NOTIFICATIONS": "Notificacions",
|
||||
"ORGANIZATIONS_TITLE": "Edit your organizations",
|
||||
"ORGANIZATIONS": "Edit organizations",
|
||||
"SETTINGS_TITLE": "Edit your settings",
|
||||
"SETTINGS": "Settings",
|
||||
"VIEW_PROFILE_TITLE": "View Profile",
|
||||
"VIEW_PROFILE": "View Profile",
|
||||
"EDIT_PROFILE_TITLE": "Edit your profile",
|
||||
"EDIT_PROFILE": "Edit Profile",
|
||||
"CHANGE_PASSWORD_TITLE": "Canvi de contrasenya",
|
||||
"CHANGE_PASSWORD": "Canvi de contrasenya",
|
||||
"DASHBOARD_TITLE": "Dashboard",
|
||||
"DISCOVER_TITLE": "Discover trending projects",
|
||||
"DISCOVER": "Discover",
|
||||
"ACTION_REORDER": "Drag & drop to reorder"
|
||||
},
|
||||
"IMPORT": {
|
||||
"TITLE": "Important Projecte",
|
||||
|
@ -624,6 +778,8 @@
|
|||
}
|
||||
},
|
||||
"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": "Panell de tasques",
|
||||
"TITLE_LINK_TASKBOARD": "Anar a panell de tasques",
|
||||
|
@ -711,6 +867,8 @@
|
|||
}
|
||||
},
|
||||
"BACKLOG": {
|
||||
"PAGE_TITLE": "Backlog - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "The backlog panel, with user stories and sprints of the project {{projectName}}: {{projectDescription}}",
|
||||
"SECTION_NAME": "Backlog",
|
||||
"MOVE_US_TO_CURRENT_SPRINT": "Envia al Sprint",
|
||||
"SHOW_FILTERS": "Mostra filtres",
|
||||
|
@ -790,6 +948,8 @@
|
|||
"VERSION_ERROR": "Algú dins de Taiga ha canviat aȯ abans i els Oompa Loompas no pode aplicar els teus canvis. Per favor recarrega i aplica els teus canvis (es perdràn)"
|
||||
},
|
||||
"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}}.",
|
||||
"SECTION_NAME": "Panell de tasques",
|
||||
"TITLE_ACTION_ADD": "Afegir nova tasca",
|
||||
"TITLE_ACTION_ADD_BULK": "Afegeix noves històries d'usuari en grup",
|
||||
|
@ -813,6 +973,8 @@
|
|||
}
|
||||
},
|
||||
"TASK": {
|
||||
"PAGE_TITLE": "{{taskSubject}} - Task {{taskRef}} - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "Status: {{taskStatus }}. Description: {{taskDescription}}",
|
||||
"SECTION_NAME": "Detalls de la tasca",
|
||||
"LINK_TASKBOARD": "Panell de tasques",
|
||||
"TITLE_LINK_TASKBOARD": "Anar a panell de tasques",
|
||||
|
@ -858,56 +1020,9 @@
|
|||
"ACTION_CHANGE_EMAIL": "Canviar correu",
|
||||
"SUCCESS": "Els Oompa Loompas han actualitzat el teu correu"
|
||||
},
|
||||
"CHANGE_PASSWORD_RECOVERY_FORM": {
|
||||
"TITLE": "Crea un nou password",
|
||||
"SUBTITLE": "Menja un poc més de ferro, es bo pel cervell :P ",
|
||||
"PLACEHOLDER_RECOVER_PASSWORD_TOKEN": "Recuperar token de contrasenya",
|
||||
"LINK_NEED_TOKEN": "Neccesites un?",
|
||||
"TITLE_LINK_NEED_TOKEN": "Necessites un token per a recuperar la teua contrasenya perque l'has oblidat?",
|
||||
"PLACEHOLDER_NEW_PASSWORD": "nova contrasenya",
|
||||
"PLACEHOLDER_RE_TYPE_NEW_PASSWORD": "Reescriu la nova contrasenya",
|
||||
"ACTION_RESET_PASSWORD": "Resetejar contrasenya",
|
||||
"SUCCESS": "Els Oompa Loompas han salvat la teua contrasenya <br /> Prova a <strong>entrar</strong> amb ella."
|
||||
},
|
||||
"FORGOT_PASSWORD_FORM": {
|
||||
"TITLE": "Oops, has oblidat la teua contrasenya?",
|
||||
"SUBTITLE": "Escriviu el vostre nom d'usuari o correu electrònic per a conseguir-ne un de nou",
|
||||
"PLACEHOLDER_FIELD": "Nom d'usuari o correu electrònic",
|
||||
"ACTION_RESET_PASSWORD": "Resetejar contrasenya",
|
||||
"LINK_CANCEL": "No, portam enrere, crec que ho recorde.",
|
||||
"SUCCESS": "<strong>Mira el teu correu!</strong><br /> Hem enviat un correu amb les instrucciones per a setejar una nova contrasenya.",
|
||||
"ERROR": "Segons els nostres Oompa Loompas, no estàs registrat encara."
|
||||
},
|
||||
"LOGIN_COMMON": {
|
||||
"HEADER": "Ja tinc un conter de Taiga",
|
||||
"PLACEHOLDER_AUTH_NAME": "Nom d'usuari i correu electrònic (sensible a majúscules i minúscules)",
|
||||
"LINK_FORGOT_PASSWORD": "L'has oblidat?",
|
||||
"TITLE_LINK_FORGOT_PASSWORD": "Has oblidat la teua contrasenya?",
|
||||
"ACTION_ENTER": "Entrar",
|
||||
"ACTION_SIGN_IN": "Entrar",
|
||||
"PLACEHOLDER_AUTH_PASSWORD": "Contrasenya (sensible a majúscules i minúscules)"
|
||||
},
|
||||
"LOGIN_FORM": {
|
||||
"ERROR_AUTH_INCORRECT": "Segons els Oompa Loompas, el vostre nom d'usuari/correu electrònic o contrasenya són incorrectes.",
|
||||
"ERROR_GENERIC": "Segons els Oompa Loompas ha hagut un error.",
|
||||
"SUCCESS": "Our Oompa Loompas están contents, benvinguts a Taiga."
|
||||
},
|
||||
"INVITATION_LOGIN_FORM": {
|
||||
"NOT_FOUND": "<strong>Ooops, ha hagut un problema</strong><br />Els nosters Oompa Loompas no troben la teua invitació.",
|
||||
"SUCCESS": "T'has incorporat a este projecte. Vos donem la benvinguda a {{project_name}}",
|
||||
"ERROR": "Segons els nostres OOmpa Loompas, no estàs registrat encara o has escrit una contrasenya invàlida."
|
||||
},
|
||||
"REGISTER_FORM": {
|
||||
"TITLE": "Register a new Taiga account (free)",
|
||||
"PLACEHOLDER_NAME": "Trieu un nom d'usuari (sensible a majúscules i minúscules)",
|
||||
"PLACEHOLDER_FULL_NAME": "Escriu el teu nom complet",
|
||||
"PLACEHOLDER_EMAIL": "El teu correu",
|
||||
"PLACEHOLDER_PASSWORD": "Tria una contrasenya(sensible a majúscules i minúscules)",
|
||||
"ACTION_SIGN_UP": "Registrar-se",
|
||||
"TITLE_LINK_LOGIN": "Entrar",
|
||||
"LINK_LOGIN": "Ja estàs registrat? Entra"
|
||||
},
|
||||
"ISSUES": {
|
||||
"PAGE_TITLE": "Issues - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "The issues list panel of the project {{projectName}}: {{projectDescription}}",
|
||||
"LIST_SECTION_NAME": "Incidències",
|
||||
"SECTION_NAME": "Issue details",
|
||||
"ACTION_NEW_ISSUE": "+ NOVA INCIDÈNCIA",
|
||||
|
@ -921,6 +1036,11 @@
|
|||
"TITLE_NEXT_ISSUE": "pròxima incidència",
|
||||
"ACTION_DELETE": "Esborrar incidència",
|
||||
"LIGHTBOX_TITLE_BLOKING_ISSUE": "Bloquejant incidència",
|
||||
"FIELDS": {
|
||||
"PRIORITY": "Prioritat",
|
||||
"SEVERITY": "Severitat",
|
||||
"TYPE": "Tipus"
|
||||
},
|
||||
"CONFIRM_PROMOTE": {
|
||||
"TITLE": "Promociona aquesta incidència a història d'usuari",
|
||||
"MESSAGE": "Segur que vols crear una nova US desde aquesta incidència"
|
||||
|
@ -966,7 +1086,13 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"ISSUE": {
|
||||
"PAGE_TITLE": "{{issueSubject}} - Issue {{issueRef}} - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "Status: {{issueStatus }}. Type: {{issueType}}, Priority: {{issuePriority}}. Severity: {{issueSeverity}}. Description: {{issueDescription}}"
|
||||
},
|
||||
"KANBAN": {
|
||||
"PAGE_TITLE": "Kanban - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "The kanban panel, with user stories of the project {{projectName}}: {{projectDescription}}",
|
||||
"SECTION_NAME": "Kanban",
|
||||
"TITLE_ACTION_FOLD": "Plegar columna",
|
||||
"TITLE_ACTION_UNFOLD": "Desplegar columna",
|
||||
|
@ -981,6 +1107,8 @@
|
|||
"UNDO_ARCHIVED": "Arrastra de nou per desfer"
|
||||
},
|
||||
"SEARCH": {
|
||||
"PAGE_TITLE": "Search - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "Search anything, user stories, issues, tasks or wiki pages, in the project {{projectName}}: {{projectDescription}}",
|
||||
"FILTER_USER_STORIES": "Històries d'usuari",
|
||||
"FILTER_ISSUES": "Incidències",
|
||||
"FILTER_TASKS": "Tasca",
|
||||
|
@ -991,6 +1119,8 @@
|
|||
"EMPTY_DESCRIPTION": "Prova amb una de les pestanyes o busca de nou"
|
||||
},
|
||||
"TEAM": {
|
||||
"PAGE_TITLE": "Team - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "The team panel to show all the members of the project {{projectName}}: {{projectDescription}}",
|
||||
"SECTION_NAME": "Equip",
|
||||
"APP_TITLE": "EQUIP - {{projectName}}",
|
||||
"PLACEHOLDER_INPUT_SEARCH": "Busca per nom complet...",
|
||||
|
@ -1011,16 +1141,6 @@
|
|||
"CONFIRM_LEAVE_PROJECT": "Segur que vols deixar el projecte?",
|
||||
"ACTION_LEAVE_PROJECT": "Abandonar aquest projecte"
|
||||
},
|
||||
"CHANGE_PASSWORD": {
|
||||
"SECTION_NAME": "Canvi de contrasenya",
|
||||
"FIELD_CURRENT_PASSWORD": "Contrasenya actual",
|
||||
"PLACEHOLDER_CURRENT_PASSWORD": "La teua contrasenya actua (buit si no tens contrasenya encara)",
|
||||
"FIELD_NEW_PASSWORD": "Nova contrasenya",
|
||||
"PLACEHOLDER_NEW_PASSWORD": "Escriu una nova contrasenya",
|
||||
"FIELD_RETYPE_PASSWORD": "Reescriu contrasenya",
|
||||
"PLACEHOLDER_RETYPE_PASSWORD": "Reescriu contrasenya",
|
||||
"ERROR_PASSWORD_MATCH": "Les contrasenyes no coincideixen"
|
||||
},
|
||||
"USER_SETTINGS": {
|
||||
"AVATAR_MAX_SIZE": "[Max. grandària: {{maxFileSize}}]",
|
||||
"MENU": {
|
||||
|
@ -1059,7 +1179,7 @@
|
|||
"EMAIL": "Correu electrònic",
|
||||
"FULL_NAME": "Nom complet",
|
||||
"PLACEHOLDER_FULL_NAME": "Esciur el teu nom complet (ex. Íñigo Montoya)",
|
||||
"BIO": "Bio",
|
||||
"BIO": "Bio (max. 210 caràcters)",
|
||||
"PLACEHOLDER_BIO": "Contans algo sobre tu mateix",
|
||||
"LANGUAGE": "Idioma",
|
||||
"LANGUAGE_DEFAULT": "-- utiliza l'idioma per defecte --"
|
||||
|
@ -1074,6 +1194,8 @@
|
|||
"PROGRESS_NAME_DESCRIPTION": "Nom i descripció"
|
||||
},
|
||||
"WIKI": {
|
||||
"PAGE_TITLE": "{{wikiPageName}} - Wiki - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "Last edition on {{lastModifiedDate}} ({{totalEditions}} editions in total) Content: {{ wikiPageContent }}",
|
||||
"DATETIME": "DD MMM YYYY HH:mm",
|
||||
"PLACEHOLDER_PAGE": "Esciu pàgina del Wiki",
|
||||
"REMOVE": "Esborrar pàgina de Wiki",
|
||||
|
@ -1087,5 +1209,43 @@
|
|||
"LAST_EDIT": "última <br />edició",
|
||||
"LAST_MODIFICATION": "última modificació"
|
||||
}
|
||||
},
|
||||
"HINTS": {
|
||||
"SECTION_NAME": "Hint",
|
||||
"LINK": "If you want to know how to use it visit our support page",
|
||||
"LINK_TITLE": "Visit our support page",
|
||||
"HINT1_TITLE": "Did you know you can import and export projects?",
|
||||
"HINT1_TEXT": "This allow you to extract all your data from one Taiga and move it to another one.",
|
||||
"HINT2_TITLE": "Did you know you can create custom fields?",
|
||||
"HINT2_TEXT": "Teams can now create custom fields as a flexible means to enter specific data useful for their particular workflow",
|
||||
"HINT3_TITLE": "Reorder your projects to feature those most relevant to you",
|
||||
"HINT3_TEXT": "The top 10 project will be in your top bar direct access",
|
||||
"HINT4_TITLE": "Did you forgot what were you working on?",
|
||||
"HINT4_TEXT": "Don't worry, on your dashboard you'll find your open tasks, issues, and user stories in the order you worked on them."
|
||||
},
|
||||
"TIMELINE": {
|
||||
"UPLOAD_ATTACHMENT": "{{username}} has uploaded a new attachment in {{obj_name}}",
|
||||
"US_CREATED": "{{username}} has created a new US {{obj_name}} in {{project_name}}",
|
||||
"ISSUE_CREATED": "{{username}} has created a new issue {{obj_name}} in {{project_name}}",
|
||||
"TASK_CREATED": "{{username}} has created a new task {{obj_name}} in {{project_name}}",
|
||||
"TASK_CREATED_WITH_US": "{{username}} has created a new task {{obj_name}} in {{project_name}} which belongs to the US {{us_name}}",
|
||||
"WIKI_CREATED": "{{username}} has created a new wiki page {{obj_name}} in {{project_name}}",
|
||||
"MILESTONE_CREATED": "{{username}} has created a new sprint {{obj_name}} in {{project_name}}",
|
||||
"NEW_PROJECT": "{{username}} created the project {{project_name}}",
|
||||
"MILESTONE_UPDATED": "{{username}} has updated the sprint {{obj_name}}",
|
||||
"US_UPDATED": "{{username}} has updated the attribute \"{{field_name}}\" of the US {{obj_name}}",
|
||||
"ISSUE_UPDATED": "{{username}} has updated the attribute \"{{field_name}}\" of the issue {{obj_name}}",
|
||||
"TASK_UPDATED": "{{username}} has updated the attribute \"{{field_name}}\" of the task {{obj_name}}",
|
||||
"TASK_UPDATED_WITH_US": "{{username}} has updated the attribute \"{{field_name}}\" of the task {{obj_name}} which belongs to the US {{us_name}}",
|
||||
"WIKI_UPDATED": "{{username}} has updated the wiki page {{obj_name}}",
|
||||
"NEW_COMMENT_US": "{{username}} has commented in the US {{obj_name}}",
|
||||
"NEW_COMMENT_ISSUE": "{{username}} has commented in the issue {{obj_name}}",
|
||||
"NEW_COMMENT_TASK": "{{username}} has commented in the task {{obj_name}}",
|
||||
"NEW_MEMBER": "{{project_name}} has a new member",
|
||||
"US_ADDED_MILESTONE": "{{username}} has added the US {{obj_name}} to {{sprint_name}}",
|
||||
"US_REMOVED_FROM_MILESTONE": "{{username}} has added the US {{obj_name}} to the backlog",
|
||||
"BLOCKED": "{{username}} has blocked {{obj_name}}",
|
||||
"UNBLOCKED": "{{username}} has unblocked {{obj_name}}",
|
||||
"NEW_USER": "{{username}} has joined Taiga"
|
||||
}
|
||||
}
|
|
@ -100,6 +100,10 @@
|
|||
"SAT": "Sat"
|
||||
}
|
||||
},
|
||||
"SEE_USER_PROFILE": "See {{username }} profile",
|
||||
"USER_STORY": "User story",
|
||||
"TASK": "Task",
|
||||
"ISSUE": "Issue",
|
||||
"TAGS": {
|
||||
"PLACEHOLDER": "I'm it! Tag me...",
|
||||
"DELETE": "Delete tag",
|
||||
|
@ -125,7 +129,8 @@
|
|||
"ASSIGNED_TO": "Assigned to",
|
||||
"POINTS": "Points",
|
||||
"BLOCKED_NOTE": "blocked note",
|
||||
"IS_BLOCKED": "is blocked"
|
||||
"IS_BLOCKED": "is blocked",
|
||||
"REF": "Ref"
|
||||
},
|
||||
"ROLES": {
|
||||
"ALL": "All"
|
||||
|
@ -231,14 +236,107 @@
|
|||
"ADD_WIKI_LINKS": "Add wiki links",
|
||||
"DELETE_WIKI_LINKS": "Delete wiki links"
|
||||
}
|
||||
},
|
||||
"META": {
|
||||
"PAGE_TITLE": "Taiga",
|
||||
"PAGE_DESCRIPTION": "Taiga is a project management platform for startups and agile developers & designers who want a simple, beautiful tool that makes work truly enjoyable."
|
||||
}
|
||||
},
|
||||
"LOGIN": {
|
||||
"PAGE_TITLE": "Login - Taiga",
|
||||
"PAGE_DESCRIPTION": "Logging in to Taiga, a project management platform for startups and agile developers & designers who want a simple, beautiful tool that makes work truly enjoyable."
|
||||
},
|
||||
"AUTH": {
|
||||
"INVITED_YOU": "has invited you to join the project",
|
||||
"NOT_REGISTERED_YET": "Not registered yet?",
|
||||
"REGISTER": "Register",
|
||||
"CREATE_ACCOUNT": "create your free account here"
|
||||
},
|
||||
"LOGIN_COMMON": {
|
||||
"HEADER": "I already have a Taiga login",
|
||||
"PLACEHOLDER_AUTH_NAME": "Username or email (case sensitive)",
|
||||
"LINK_FORGOT_PASSWORD": "Forgot it?",
|
||||
"TITLE_LINK_FORGOT_PASSWORD": "Did you forgot your password?",
|
||||
"ACTION_ENTER": "Enter",
|
||||
"ACTION_SIGN_IN": "Sign in",
|
||||
"PLACEHOLDER_AUTH_PASSWORD": "Password (case sensitive)"
|
||||
},
|
||||
"LOGIN_FORM": {
|
||||
"ERROR_AUTH_INCORRECT": "According to our Oompa Loompas, your username/email or password are incorrect.",
|
||||
"SUCCESS": "Our Oompa Loompas are happy, welcome to Taiga."
|
||||
},
|
||||
"REGISTER": {
|
||||
"PAGE_TITLE": "Register - Taiga",
|
||||
"PAGE_DESCRIPTION": "Create your account in Taiga, a project management platform for startups and agile developers & designers who want a simple, beautiful tool that makes work truly enjoyable."
|
||||
},
|
||||
"REGISTER_FORM": {
|
||||
"TITLE": "Register a new Taiga account (free)",
|
||||
"PLACEHOLDER_NAME": "Pick a username (case sensitive)",
|
||||
"PLACEHOLDER_FULL_NAME": "Pick your full name",
|
||||
"PLACEHOLDER_EMAIL": "Your email",
|
||||
"PLACEHOLDER_PASSWORD": "Set a password (case sensitive)",
|
||||
"ACTION_SIGN_UP": "Sign up",
|
||||
"TITLE_LINK_LOGIN": "Log in",
|
||||
"LINK_LOGIN": "Are you already registered? Log in"
|
||||
},
|
||||
"FORGOT_PASSWORD": {
|
||||
"PAGE_TITLE": "Forgot password - Taiga",
|
||||
"PAGE_DESCRIPTION": "Enter your username or email to get a new password and you can access to Taiga again."
|
||||
},
|
||||
"FORGOT_PASSWORD_FORM": {
|
||||
"TITLE": "Oops, did you forget your password?",
|
||||
"SUBTITLE": "Enter your username or email to get a new one",
|
||||
"PLACEHOLDER_FIELD": "Username or email",
|
||||
"ACTION_RESET_PASSWORD": "Reset Password",
|
||||
"LINK_CANCEL": "Nah, take me back. I think I remember it.",
|
||||
"SUCCESS": "<strong>Check your inbox!</strong><br />We have 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": {
|
||||
"PAGE_TITLE": "Change you password - Taiga",
|
||||
"PAGE_DESCRIPTION": "Set a new passoword for your Taiga account and hey!, you may want to eat some more iron-rich food, it's good for your brain :P",
|
||||
"SECTION_NAME": "Change password",
|
||||
"FIELD_CURRENT_PASSWORD": "Current password",
|
||||
"PLACEHOLDER_CURRENT_PASSWORD": "Your current password (or empty if you have no password yet)",
|
||||
"FIELD_NEW_PASSWORD": "New password",
|
||||
"PLACEHOLDER_NEW_PASSWORD": "Type a new password",
|
||||
"FIELD_RETYPE_PASSWORD": "Retype new password",
|
||||
"PLACEHOLDER_RETYPE_PASSWORD": "Retype the new password",
|
||||
"ERROR_PASSWORD_MATCH": "The passwords doesn't match"
|
||||
},
|
||||
"CHANGE_PASSWORD_RECOVERY_FORM": {
|
||||
"TITLE": "Create a new Taiga pass",
|
||||
"SUBTITLE": "And hey, you may want to eat some more iron-rich food, it's good for your brain :P",
|
||||
"PLACEHOLDER_RECOVER_PASSWORD_TOKEN": "Recover password token",
|
||||
"LINK_NEED_TOKEN": "Need one?",
|
||||
"TITLE_LINK_NEED_TOKEN": "Did you need a token to recover your password because you forgot it?",
|
||||
"PLACEHOLDER_NEW_PASSWORD": "New password",
|
||||
"PLACEHOLDER_RE_TYPE_NEW_PASSWORD": "Re-type new password",
|
||||
"ACTION_RESET_PASSWORD": "Reset Password",
|
||||
"SUCCESS": "Our Oompa Loompas saved your new password.<br /> Try to <strong>sign in</strong> with it."
|
||||
},
|
||||
"INVITATION": {
|
||||
"PAGE_TITLE": "Invitation acceptance - Taiga",
|
||||
"PAGE_DESCRIPTION": "Accept the invitation to join a project in Taiga, a project management platform for startups and agile developers & designers who want a simple, beautiful tool that makes work truly enjoyable."
|
||||
},
|
||||
"INVITATION_LOGIN_FORM": {
|
||||
"NOT_FOUND": "<strong>Ooops, we have a problem</strong><br />Our Oompa Loompas can't find your invitation.",
|
||||
"SUCCESS": "You've successfully joined this project, Welcome to {{project_name}}",
|
||||
"ERROR": "According to our Oompa Loompas, your are not registered yet or typed an invalid password."
|
||||
},
|
||||
"HOME": {
|
||||
"PAGE_TITLE": "Home - Taiga",
|
||||
"PAGE_DESCRIPTION": "The Taiga home page with your main projects and all your assigned and watched user stories, tasks and issues",
|
||||
"EMPTY_WATCHING": "<strong>Follow</strong> the projects, User Stories, Tasks, Issues... that you want to know about :)",
|
||||
"EMPTY_PROJECT_LIST": "You don't have any projects yet",
|
||||
"WORKING_ON_SECTION": "Working on",
|
||||
"WATCHING_SECTION": "Watching"
|
||||
},
|
||||
"PROJECTS": {
|
||||
"PAGE_TITLE": "My projects - Taiga",
|
||||
"PAGE_DESCRIPTION": "A list with all your projects, you can reorder or create a new one.",
|
||||
"MY_PROJECTS": "My projects"
|
||||
},
|
||||
"ATTACHMENT": {
|
||||
"SECTION_NAME": "attachments",
|
||||
"TITLE": "{{ fileName }} uploaded on {{ date }}",
|
||||
|
@ -276,6 +374,7 @@
|
|||
},
|
||||
"MEMBERSHIPS": {
|
||||
"TITLE": "Manage members",
|
||||
"PAGE_TITLE": "Memberships - {{projectName}}",
|
||||
"ADD_BUTTON": "+ New member",
|
||||
"ADD_BUTTON_TITLE": "Add new member"
|
||||
},
|
||||
|
@ -311,7 +410,7 @@
|
|||
"SALT_CHAT_ROOM": "If you want you can append a salt code to the name of the chat room"
|
||||
},
|
||||
"PROJECT_PROFILE": {
|
||||
"PAGE_TITLE": "Project profile - {{sectionName}} - {{projectName}}",
|
||||
"PAGE_TITLE": "{{sectionName}} - Project profile - {{projectName}}",
|
||||
"PROJECT_DETAILS": "Project details",
|
||||
"PROJECT_NAME": "Project name",
|
||||
"PROJECT_SLUG": "Project slug",
|
||||
|
@ -352,23 +451,26 @@
|
|||
"ISSUE_ADD": "Add a custom field in issues"
|
||||
},
|
||||
"PROJECT_VALUES": {
|
||||
"APP_TITLE": "Project values - {{sectionName}} - {{projectName}}",
|
||||
"PAGE_TITLE": "{{sectionName}} - Project values - {{projectName}}",
|
||||
"REPLACEMENT": "All items with this value will be changed to",
|
||||
"ERROR_DELETE_ALL": "You can't delete all values."
|
||||
},
|
||||
"PROJECT_VALUES_POINTS": {
|
||||
"TITLE": "Us points",
|
||||
"TITLE": "Points",
|
||||
"SUBTITLE": "Specify the points your user stories could be estimated to",
|
||||
"US_TITLE": "US points",
|
||||
"ACTION_ADD": "Add new point"
|
||||
},
|
||||
"PROJECT_VALUES_PRIORITIES": {
|
||||
"TITLE": "Issue priorities",
|
||||
"TITLE": "Priorities",
|
||||
"SUBTITLE": "Specify the priorities your issues will have",
|
||||
"ISSUE_TITLE": "Issue priorities",
|
||||
"ACTION_ADD": "Add new priority"
|
||||
},
|
||||
"PROJECT_VALUES_SEVERITIES": {
|
||||
"TITLE": "Issue severities",
|
||||
"TITLE": "Severities",
|
||||
"SUBTITLE": "Specify the severities your issues will have",
|
||||
"ISSUE_TITLE": "Issue severities",
|
||||
"ACTION_ADD": "Add new severity"
|
||||
},
|
||||
"PROJECT_VALUES_STATUS": {
|
||||
|
@ -382,10 +484,10 @@
|
|||
"TITLE": "Types",
|
||||
"SUBTITLE": "Specify the types your issues could be",
|
||||
"ISSUE_TITLE": "Issues types",
|
||||
"ACTION_ADD": "Add new type"
|
||||
"ACTION_ADD": "Add new {{objName}}"
|
||||
},
|
||||
"ROLES": {
|
||||
"SECTION_NAME": "Roles - {{projectName}}",
|
||||
"PAGE_TITLE": "Roles - {{projectName}}",
|
||||
"WARNING_NO_ROLE": "Be careful, no role in your project will be able to estimate the point value for user stories",
|
||||
"HELP_ROLE_ENABLED": "When enabled, members assigned to this role will be able to estimate the point value for user stories",
|
||||
"COUNT_MEMBERS": "{{ role.members_count }} members with this role",
|
||||
|
@ -402,20 +504,20 @@
|
|||
},
|
||||
"BITBUCKET": {
|
||||
"SECTION_NAME": "Bitbucket",
|
||||
"APP_TITLE": "Bitbucket - {{projectName}}",
|
||||
"PAGE_TITLE": "Bitbucket - {{projectName}}",
|
||||
"INFO_VERIFYING_IP": "Bitbucket requests are not signed so the best way of verifying the origin is by IP. If the field is empty there will be no IP validation."
|
||||
},
|
||||
"GITLAB": {
|
||||
"SECTION_NAME": "Gitlab",
|
||||
"APP_TITLE": "Gitlab - {{projectName}}",
|
||||
"PAGE_TITLE": "Gitlab - {{projectName}}",
|
||||
"INFO_VERIFYING_IP": "Gitlab requests are not signed so the best way of verifying the origin is by IP. If the field is empty there will be no IP validation."
|
||||
},
|
||||
"GITHUB": {
|
||||
"SECTION_NAME": "Github",
|
||||
"APP_TITLE": "Github - {{projectName}}"
|
||||
"PAGE_TITLE": "Github - {{projectName}}"
|
||||
},
|
||||
"WEBHOOKS": {
|
||||
"APP_TITLE": "Webhooks - {{projectName}}",
|
||||
"PAGE_TITLE": "Webhooks - {{projectName}}",
|
||||
"SECTION_NAME": "Webhooks",
|
||||
"SUBTITLE": "Webhooks notify external services about events in Taiga, like comments, user stories....",
|
||||
"ADD_NEW": "Add a New Webhook",
|
||||
|
@ -441,6 +543,7 @@
|
|||
"WEBHOOK_NAME": "Webhook '{{name}}'"
|
||||
},
|
||||
"CUSTOM_ATTRIBUTES": {
|
||||
"PAGE_TITLE": "{{sectionName}} - Custom Attributes - {{projectName}}",
|
||||
"ADD": "Add custom field",
|
||||
"EDIT": "Edit Custom Field",
|
||||
"DELETE": "Delete Custom Field",
|
||||
|
@ -518,9 +621,36 @@
|
|||
"TITLE": "Services"
|
||||
}
|
||||
},
|
||||
"USER": {
|
||||
"PROFILE": {
|
||||
"PAGE_TITLE": "{{userFullName}} (@{{userUsername}})",
|
||||
"EDIT": "Edit profile",
|
||||
"FOLLOW": "Follow",
|
||||
"PROJECTS": "Projects",
|
||||
"CLOSED_US": "Closed US",
|
||||
"CONTACTS": "Contacts",
|
||||
"REPORT": "Report Abuse",
|
||||
"ACTIVITY_TAB": "Activity Tab",
|
||||
"PROJECTS_TAB": "Projects Tab",
|
||||
"CONTACTS_TAB": "Contacts Tab",
|
||||
"FAVORITES_TAB": "Favorites Tab",
|
||||
"CONTACTS_EMPTY": "{{username}} doesn't have contacts yet",
|
||||
"CURRENT_USER_CONTACTS_EMPTY": "You don't have contacts yet",
|
||||
"CURRENT_USER_CONTACTS_EMPTY_EXPLAIN": "The people with whom you work at Taiga will be your contacts automatically",
|
||||
"PROJECTS_EMPTY": "{{username}} doesn't' have projects yet"
|
||||
},
|
||||
"PROFILE_SIDEBAR": {
|
||||
"TITLE": "Your profile",
|
||||
"DESCRIPTION": "People can see everything you do and what are you working on. Add a nice bio to give an enhanced version of your information.",
|
||||
"ADD_INFO": "Edit your bio"
|
||||
}
|
||||
},
|
||||
"PROJECT": {
|
||||
"PAGE_TITLE": "{{projectName}}",
|
||||
"WELCOME": "Welcome",
|
||||
"SECTION_PROJECTS": "Projects",
|
||||
"HELP": "Reorder your projects to set in the top the most used ones.<br/> The top 10 projects will appear in the top navigation bar project list",
|
||||
"PRIVATE": "Private project",
|
||||
"STATS": {
|
||||
"PROJECT": "project<br/> points",
|
||||
"DEFINED": "defined<br/> points",
|
||||
|
@ -529,6 +659,7 @@
|
|||
},
|
||||
"SECTION": {
|
||||
"SEARCH": "Search",
|
||||
"TIMELINE": "Timeline",
|
||||
"BACKLOG": "Backlog",
|
||||
"KANBAN": "Kanban",
|
||||
"ISSUES": "Issues",
|
||||
|
@ -541,9 +672,32 @@
|
|||
"SECTION_TITLE": "Your projects",
|
||||
"PLACEHOLDER_SEARCH": "Search in...",
|
||||
"ACTION_CREATE_PROJECT": "Create project",
|
||||
"TITLE_ACTION_IMPORT": "Import project",
|
||||
"ACTION_IMPORT_PROJECT": "Import project",
|
||||
"SEE_MORE_PROJECTS": "See more projects",
|
||||
"TITLE_CREATE_PROJECT": "Create project",
|
||||
"TITLE_IMPORT_PROJECT": "Import project",
|
||||
"TITLE_PRVIOUS_PROJECT": "Show previous projects",
|
||||
"TITLE_NEXT_PROJECT": "Show next projects"
|
||||
"TITLE_NEXT_PROJECT": "Show next projects",
|
||||
"HELP_TITLE": "Taiga Support Page",
|
||||
"HELP": "Help",
|
||||
"FEEDBACK_TITLE": "Send feedback",
|
||||
"FEEDBACK": "Feedback",
|
||||
"NOTIFICATIONS_TITLE": "Edit your notification settings",
|
||||
"NOTIFICATIONS": "Notifications",
|
||||
"ORGANIZATIONS_TITLE": "Edit your organizations",
|
||||
"ORGANIZATIONS": "Edit organizations",
|
||||
"SETTINGS_TITLE": "Edit your settings",
|
||||
"SETTINGS": "Settings",
|
||||
"VIEW_PROFILE_TITLE": "View Profile",
|
||||
"VIEW_PROFILE": "View Profile",
|
||||
"EDIT_PROFILE_TITLE": "Edit your profile",
|
||||
"EDIT_PROFILE": "Edit Profile",
|
||||
"CHANGE_PASSWORD_TITLE": "Change password",
|
||||
"CHANGE_PASSWORD": "Change password",
|
||||
"DASHBOARD_TITLE": "Dashboard",
|
||||
"DISCOVER_TITLE": "Discover trending projects",
|
||||
"DISCOVER": "Discover",
|
||||
"ACTION_REORDER": "Drag & drop to reorder"
|
||||
},
|
||||
"IMPORT": {
|
||||
"TITLE": "Importing Project",
|
||||
|
@ -625,6 +779,9 @@
|
|||
}
|
||||
},
|
||||
"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",
|
||||
|
@ -712,6 +869,8 @@
|
|||
}
|
||||
},
|
||||
"BACKLOG": {
|
||||
"PAGE_TITLE": "Backlog - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "The backlog panel, with user stories and sprints of the project {{projectName}}: {{projectDescription}}",
|
||||
"SECTION_NAME": "Backlog",
|
||||
"MOVE_US_TO_CURRENT_SPRINT": "Move to Current Sprint",
|
||||
"SHOW_FILTERS": "Show filters",
|
||||
|
@ -792,6 +951,8 @@
|
|||
"VERSION_ERROR": "Someone inside Taiga has changed this before and our Oompa Loompas cannot apply your changes. Please reload and apply your changes again (they will be lost)."
|
||||
},
|
||||
"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}}." ,
|
||||
"SECTION_NAME": "Taskboard",
|
||||
"TITLE_ACTION_ADD": "Add a new Task",
|
||||
"TITLE_ACTION_ADD_BULK": "Add some new Tasks in bulk",
|
||||
|
@ -815,6 +976,8 @@
|
|||
}
|
||||
},
|
||||
"TASK": {
|
||||
"PAGE_TITLE": "{{taskSubject}} - Task {{taskRef}} - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "Status: {{taskStatus }}. Description: {{taskDescription}}",
|
||||
"SECTION_NAME": "Task details",
|
||||
"LINK_TASKBOARD": "Taskboard",
|
||||
"TITLE_LINK_TASKBOARD": "Go to the taskboard",
|
||||
|
@ -860,56 +1023,9 @@
|
|||
"ACTION_CHANGE_EMAIL": "Change email",
|
||||
"SUCCESS": "Our Oompa Loompas updated your email"
|
||||
},
|
||||
"CHANGE_PASSWORD_RECOVERY_FORM": {
|
||||
"TITLE": "Create a new Taiga pass",
|
||||
"SUBTITLE": "And hey, you may want to eat some more iron-rich food, it's good for your brain :P",
|
||||
"PLACEHOLDER_RECOVER_PASSWORD_TOKEN": "Recover password token",
|
||||
"LINK_NEED_TOKEN": "Need one?",
|
||||
"TITLE_LINK_NEED_TOKEN": "Did you need a token to recover your password because you forgot it?",
|
||||
"PLACEHOLDER_NEW_PASSWORD": "New password",
|
||||
"PLACEHOLDER_RE_TYPE_NEW_PASSWORD": "Re-type new password",
|
||||
"ACTION_RESET_PASSWORD": "Reset Password",
|
||||
"SUCCESS": "Our Oompa Loompas saved your new password.<br /> Try to <strong>sign in</strong> with it."
|
||||
},
|
||||
"FORGOT_PASSWORD_FORM": {
|
||||
"TITLE": "Oops, did you forget your password?",
|
||||
"SUBTITLE": "Enter your username or email to get a new one",
|
||||
"PLACEHOLDER_FIELD": "Username or email",
|
||||
"ACTION_RESET_PASSWORD": "Reset Password",
|
||||
"LINK_CANCEL": "Nah, take me back. I think I remember it.",
|
||||
"SUCCESS": "<strong>Check your inbox!</strong><br />We have sent you an email with the instructions to set a new password",
|
||||
"ERROR": "According to our Oompa Loompas, your are not registered yet."
|
||||
},
|
||||
"LOGIN_COMMON": {
|
||||
"HEADER": "I already have a Taiga login",
|
||||
"PLACEHOLDER_AUTH_NAME": "Username or email (case sensitive)",
|
||||
"LINK_FORGOT_PASSWORD": "Forgot it?",
|
||||
"TITLE_LINK_FORGOT_PASSWORD": "Did you forgot your password?",
|
||||
"ACTION_ENTER": "Enter",
|
||||
"ACTION_SIGN_IN": "Sign in",
|
||||
"PLACEHOLDER_AUTH_PASSWORD": "Password (case sensitive)"
|
||||
},
|
||||
"LOGIN_FORM": {
|
||||
"ERROR_AUTH_INCORRECT": "According to our Oompa Loompas, your username/email or password are incorrect.",
|
||||
"ERROR_GENERIC": "According to our Oompa Loompas there was an error.",
|
||||
"SUCCESS": "Our Oompa Loompas are happy, welcome to Taiga."
|
||||
},
|
||||
"INVITATION_LOGIN_FORM": {
|
||||
"NOT_FOUND": "<strong>Ooops, we have a problem</strong><br />Our Oompa Loompas can't find your invitation.",
|
||||
"SUCCESS": "You've successfully joined this project, Welcome to {{project_name}}",
|
||||
"ERROR": "According to our Oompa Loompas, your are not registered yet or typed an invalid password."
|
||||
},
|
||||
"REGISTER_FORM": {
|
||||
"TITLE": "Register a new Taiga account (free)",
|
||||
"PLACEHOLDER_NAME": "Pick a username (case sensitive)",
|
||||
"PLACEHOLDER_FULL_NAME": "Pick your full name",
|
||||
"PLACEHOLDER_EMAIL": "Your email",
|
||||
"PLACEHOLDER_PASSWORD": "Set a password (case sensitive)",
|
||||
"ACTION_SIGN_UP": "Sign up",
|
||||
"TITLE_LINK_LOGIN": "Log in",
|
||||
"LINK_LOGIN": "Are you already registered? Log in"
|
||||
},
|
||||
"ISSUES": {
|
||||
"PAGE_TITLE": "Issues - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "The issues list panel of the project {{projectName}}: {{projectDescription}}",
|
||||
"LIST_SECTION_NAME": "Issues",
|
||||
"SECTION_NAME": "Issue details",
|
||||
"ACTION_NEW_ISSUE": "+ NEW ISSUE",
|
||||
|
@ -923,6 +1039,11 @@
|
|||
"TITLE_NEXT_ISSUE": "next issue",
|
||||
"ACTION_DELETE": "Delete issue",
|
||||
"LIGHTBOX_TITLE_BLOKING_ISSUE": "Blocking issue",
|
||||
"FIELDS": {
|
||||
"PRIORITY": "Priority",
|
||||
"SEVERITY": "Severity",
|
||||
"TYPE": "Type"
|
||||
},
|
||||
"CONFIRM_PROMOTE": {
|
||||
"TITLE": "Promote this issue to a new user story",
|
||||
"MESSAGE": "Are you sure you want to create a new US from this Issue?"
|
||||
|
@ -968,7 +1089,13 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"ISSUE": {
|
||||
"PAGE_TITLE": "{{issueSubject}} - Issue {{issueRef}} - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "Status: {{issueStatus }}. Type: {{issueType}}, Priority: {{issuePriority}}. Severity: {{issueSeverity}}. Description: {{issueDescription}}"
|
||||
},
|
||||
"KANBAN": {
|
||||
"PAGE_TITLE": "Kanban - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "The kanban panel, with user stories of the project {{projectName}}: {{projectDescription}}",
|
||||
"SECTION_NAME": "Kanban",
|
||||
"TITLE_ACTION_FOLD": "Fold column",
|
||||
"TITLE_ACTION_UNFOLD": "Unfold column",
|
||||
|
@ -983,6 +1110,8 @@
|
|||
"UNDO_ARCHIVED": "Drag & drop again to undo"
|
||||
},
|
||||
"SEARCH": {
|
||||
"PAGE_TITLE": "Search - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "Search anything, user stories, issues, tasks or wiki pages, in the project {{projectName}}: {{projectDescription}}",
|
||||
"FILTER_USER_STORIES": "User Stories",
|
||||
"FILTER_ISSUES": "Issues",
|
||||
"FILTER_TASKS": "Tasks",
|
||||
|
@ -993,6 +1122,8 @@
|
|||
"EMPTY_DESCRIPTION": "Maybe try one of the tabs above or search again"
|
||||
},
|
||||
"TEAM": {
|
||||
"PAGE_TITLE": "Team - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "The team panel to show all the members of the project {{projectName}}: {{projectDescription}}",
|
||||
"SECTION_NAME": "Team",
|
||||
"APP_TITLE": "TEAM - {{projectName}}",
|
||||
"PLACEHOLDER_INPUT_SEARCH": "Search by full name...",
|
||||
|
@ -1013,16 +1144,6 @@
|
|||
"CONFIRM_LEAVE_PROJECT": "Are you sure you want to leave the project?",
|
||||
"ACTION_LEAVE_PROJECT": "Leave this project"
|
||||
},
|
||||
"CHANGE_PASSWORD": {
|
||||
"SECTION_NAME": "Change password",
|
||||
"FIELD_CURRENT_PASSWORD": "Current password",
|
||||
"PLACEHOLDER_CURRENT_PASSWORD": "Your current password (or empty if you have no password yet)",
|
||||
"FIELD_NEW_PASSWORD": "New password",
|
||||
"PLACEHOLDER_NEW_PASSWORD": "Type a new password",
|
||||
"FIELD_RETYPE_PASSWORD": "Retype new password",
|
||||
"PLACEHOLDER_RETYPE_PASSWORD": "Retype the new password",
|
||||
"ERROR_PASSWORD_MATCH": "The passwords doesn't match"
|
||||
},
|
||||
"USER_SETTINGS": {
|
||||
"AVATAR_MAX_SIZE": "[Max. size: {{maxFileSize}}]",
|
||||
"MENU": {
|
||||
|
@ -1061,7 +1182,7 @@
|
|||
"EMAIL": "Email",
|
||||
"FULL_NAME": "Full name",
|
||||
"PLACEHOLDER_FULL_NAME": "Set your full name (ex. Íñigo Montoya)",
|
||||
"BIO": "Bio",
|
||||
"BIO": "Bio (max. 210 chars)",
|
||||
"PLACEHOLDER_BIO": "Tell us something about you",
|
||||
"LANGUAGE": "Language",
|
||||
"LANGUAGE_DEFAULT": "-- use default language --"
|
||||
|
@ -1076,6 +1197,8 @@
|
|||
"PROGRESS_NAME_DESCRIPTION": "Name and description"
|
||||
},
|
||||
"WIKI": {
|
||||
"PAGE_TITLE": "{{wikiPageName}} - Wiki - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "Last edition on {{lastModifiedDate}} ({{totalEditions}} editions in total) Content: {{ wikiPageContent }}",
|
||||
"DATETIME": "DD MMM YYYY HH:mm",
|
||||
"PLACEHOLDER_PAGE": "Write your wiki page",
|
||||
"REMOVE": "Remove this wiki page",
|
||||
|
@ -1089,5 +1212,43 @@
|
|||
"LAST_EDIT": "last <br />edit",
|
||||
"LAST_MODIFICATION": "last modification"
|
||||
}
|
||||
},
|
||||
"HINTS": {
|
||||
"SECTION_NAME": "Hint",
|
||||
"LINK": "If you want to know how to use it visit our support page",
|
||||
"LINK_TITLE": "Visit our support page",
|
||||
"HINT1_TITLE": "Did you know you can import and export projects?",
|
||||
"HINT1_TEXT": "This allow you to extract all your data from one Taiga and move it to another one.",
|
||||
"HINT2_TITLE": "Did you know you can create custom fields?",
|
||||
"HINT2_TEXT": "Teams can now create custom fields as a flexible means to enter specific data useful for their particular workflow",
|
||||
"HINT3_TITLE": "Reorder your projects to feature those most relevant to you",
|
||||
"HINT3_TEXT": "The top 10 project will be in your top bar direct access",
|
||||
"HINT4_TITLE": "Did you forgot what were you working on?",
|
||||
"HINT4_TEXT": "Don't worry, on your dashboard you'll find your open tasks, issues, and user stories in the order you worked on them."
|
||||
},
|
||||
"TIMELINE": {
|
||||
"UPLOAD_ATTACHMENT": "{{username}} has uploaded a new attachment in {{obj_name}}",
|
||||
"US_CREATED": "{{username}} has created a new US {{obj_name}} in {{project_name}}",
|
||||
"ISSUE_CREATED": "{{username}} has created a new issue {{obj_name}} in {{project_name}}",
|
||||
"TASK_CREATED": "{{username}} has created a new task {{obj_name}} in {{project_name}}",
|
||||
"TASK_CREATED_WITH_US": "{{username}} has created a new task {{obj_name}} in {{project_name}} which belongs to the US {{us_name}}",
|
||||
"WIKI_CREATED": "{{username}} has created a new wiki page {{obj_name}} in {{project_name}}",
|
||||
"MILESTONE_CREATED": "{{username}} has created a new sprint {{obj_name}} in {{project_name}}",
|
||||
"NEW_PROJECT": "{{username}} created the project {{project_name}}",
|
||||
"MILESTONE_UPDATED": "{{username}} has updated the sprint {{obj_name}}",
|
||||
"US_UPDATED": "{{username}} has updated the attribute \"{{field_name}}\" of the US {{obj_name}}",
|
||||
"ISSUE_UPDATED": "{{username}} has updated the attribute \"{{field_name}}\" of the issue {{obj_name}}",
|
||||
"TASK_UPDATED": "{{username}} has updated the attribute \"{{field_name}}\" of the task {{obj_name}}",
|
||||
"TASK_UPDATED_WITH_US": "{{username}} has updated the attribute \"{{field_name}}\" of the task {{obj_name}} which belongs to the US {{us_name}}",
|
||||
"WIKI_UPDATED": "{{username}} has updated the wiki page {{obj_name}}",
|
||||
"NEW_COMMENT_US": "{{username}} has commented in the US {{obj_name}}",
|
||||
"NEW_COMMENT_ISSUE": "{{username}} has commented in the issue {{obj_name}}",
|
||||
"NEW_COMMENT_TASK": "{{username}} has commented in the task {{obj_name}}",
|
||||
"NEW_MEMBER": "{{project_name}} has a new member",
|
||||
"US_ADDED_MILESTONE": "{{username}} has added the US {{obj_name}} to {{sprint_name}}",
|
||||
"US_REMOVED_FROM_MILESTONE": "{{username}} has added the US {{obj_name}} to the backlog",
|
||||
"BLOCKED": "{{username}} has blocked {{obj_name}}",
|
||||
"UNBLOCKED": "{{username}} has unblocked {{obj_name}}",
|
||||
"NEW_USER": "{{username}} has joined Taiga"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"YES": "Si",
|
||||
"NO": "No",
|
||||
"LOADING": "Cargando...",
|
||||
"LOADING_PROJECT": "Cargando projecto...",
|
||||
"LOADING_PROJECT": "Cargando proyecto...",
|
||||
"DATE": "DD MMM YYYY",
|
||||
"DATETIME": "DD MMM YYYY HH:mm",
|
||||
"SAVE": "Guardar",
|
||||
|
@ -100,6 +100,10 @@
|
|||
"SAT": "Sáb"
|
||||
}
|
||||
},
|
||||
"SEE_USER_PROFILE": "Ver el perfil de {{username }}",
|
||||
"USER_STORY": "Historia de usuario",
|
||||
"TASK": "Tarea",
|
||||
"ISSUE": "Petición",
|
||||
"TAGS": {
|
||||
"PLACEHOLDER": "¿Qué soy? Etiquétame...",
|
||||
"DELETE": "Borrar etiqueta",
|
||||
|
@ -125,7 +129,8 @@
|
|||
"ASSIGNED_TO": "Asignado a",
|
||||
"POINTS": "Puntos",
|
||||
"BLOCKED_NOTE": "Motivo del bloqueo",
|
||||
"IS_BLOCKED": "está bloqueada"
|
||||
"IS_BLOCKED": "está bloqueada",
|
||||
"REF": "Ref"
|
||||
},
|
||||
"ROLES": {
|
||||
"ALL": "Todos"
|
||||
|
@ -231,14 +236,107 @@
|
|||
"ADD_WIKI_LINKS": "Crear enlaces",
|
||||
"DELETE_WIKI_LINKS": "Borrar enlaces"
|
||||
}
|
||||
},
|
||||
"META": {
|
||||
"PAGE_TITLE": "Taiga",
|
||||
"PAGE_DESCRIPTION": "Taiga es una plataforma de gestión de proyectos orientada a startups y equipos ágiles que buscan una herramienta sencilla, elegante y que les haga disfrutar trabajando."
|
||||
}
|
||||
},
|
||||
"LOGIN": {
|
||||
"PAGE_TITLE": "Login - Taiga",
|
||||
"PAGE_DESCRIPTION": "Inicia sesión en Taiga, una plataforma de gestión de proyectos orientada a startups y equipos ágiles que buscan una herramienta sencilla, elegante y que les haga disfrutar trabajando."
|
||||
},
|
||||
"AUTH": {
|
||||
"INVITED_YOU": "te ha invitado a unirte al proyecto",
|
||||
"NOT_REGISTERED_YET": "¿Aún no está registrado?",
|
||||
"REGISTER": "Registro",
|
||||
"CREATE_ACCOUNT": "crea tu cuenta gratis aquí"
|
||||
},
|
||||
"LOGIN_COMMON": {
|
||||
"HEADER": "Ya tengo una cuenta en Taiga",
|
||||
"PLACEHOLDER_AUTH_NAME": "Nombre de usuario o email (distingue mayúsculas y minúsculas)",
|
||||
"LINK_FORGOT_PASSWORD": "¿La olvidaste?",
|
||||
"TITLE_LINK_FORGOT_PASSWORD": "¿Has olvidado tu contraseña?",
|
||||
"ACTION_ENTER": "Entrar",
|
||||
"ACTION_SIGN_IN": "Ingresar",
|
||||
"PLACEHOLDER_AUTH_PASSWORD": "Contraseña (distingue mayúsculas y minúsculas)"
|
||||
},
|
||||
"LOGIN_FORM": {
|
||||
"ERROR_AUTH_INCORRECT": "Nuestros Oompa Loompas indican que tu nombre de usuario/correo o contraseña son incorrectos",
|
||||
"SUCCESS": "Nuestros Oompa Loompas están felices, bienvenido a Taiga."
|
||||
},
|
||||
"REGISTER": {
|
||||
"PAGE_TITLE": "Registro - Taiga",
|
||||
"PAGE_DESCRIPTION": "Crea tu cuenta en Taiga, una plataforma de gestión de proyectos orientada a startups y equipos ágiles que buscan una herramienta sencilla, elegante y que les haga disfrutar trabajando."
|
||||
},
|
||||
"REGISTER_FORM": {
|
||||
"TITLE": "Crea tu nueva cuenta en Taiga, ¡es gratis!",
|
||||
"PLACEHOLDER_NAME": "Escribe un nombre de usuario (distingue mayúsculas y minúsculas)",
|
||||
"PLACEHOLDER_FULL_NAME": "Escribe tu nombre completo",
|
||||
"PLACEHOLDER_EMAIL": "Tu email",
|
||||
"PLACEHOLDER_PASSWORD": "Establece una contraseña (distingue mayúsculas y minúsculas)",
|
||||
"ACTION_SIGN_UP": "Registrarme",
|
||||
"TITLE_LINK_LOGIN": "Iniciar sesión",
|
||||
"LINK_LOGIN": "¿Ya te has registrado? Inicia sesión"
|
||||
},
|
||||
"FORGOT_PASSWORD": {
|
||||
"PAGE_TITLE": "Has olvidado tu contraseña - Taiga",
|
||||
"PAGE_DESCRIPTION": "A partir de tu nombre de usuario o email obtendrás una nueva contraseña para acceder a Taiga nuevamente."
|
||||
},
|
||||
"FORGOT_PASSWORD_FORM": {
|
||||
"TITLE": "Vaya, ¿has olvidado tu contraseña?",
|
||||
"SUBTITLE": "Escribe tu nombre de usuario o email para obtener una nueva",
|
||||
"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": "<strong>¡Revisa tu bandeja de entrada!</strong><br />Te hemos enviado un mail con las instrucciones necesarias para restablecer tu contraseña\n",
|
||||
"ERROR": "Según nuestros Oompa Loompas tú no estás registrado"
|
||||
},
|
||||
"CHANGE_PASSWORD": {
|
||||
"PAGE_TITLE": "Cambia tu contraseña - Taiga",
|
||||
"PAGE_DESCRIPTION": "Indica una nueva contraseña para tu cuenta en Taiga y bueno, es posible que necesites comer un poco más de alimentos ricos en hierro, son buenos para tu cerebro :P",
|
||||
"SECTION_NAME": "Cambiar contraseña",
|
||||
"FIELD_CURRENT_PASSWORD": "Contraseña actual",
|
||||
"PLACEHOLDER_CURRENT_PASSWORD": "Tu contraseña actual (o déjalo vacío si todavía no tienes contraseña)",
|
||||
"FIELD_NEW_PASSWORD": "Nueva contraseña",
|
||||
"PLACEHOLDER_NEW_PASSWORD": "Escribe una contraseña nueva",
|
||||
"FIELD_RETYPE_PASSWORD": "Reescribe la nueva contraseña",
|
||||
"PLACEHOLDER_RETYPE_PASSWORD": "Reescribe la nueva contraseña",
|
||||
"ERROR_PASSWORD_MATCH": "Las contraseñas no coinciden"
|
||||
},
|
||||
"CHANGE_PASSWORD_RECOVERY_FORM": {
|
||||
"TITLE": "Crear una nueva contraseña de Taiga",
|
||||
"SUBTITLE": "Y bueno, es posible que necesites comer más alimentos ricos en hierro, son buenos para tu cerebro :P",
|
||||
"PLACEHOLDER_RECOVER_PASSWORD_TOKEN": "token de recuperación de contraseña",
|
||||
"LINK_NEED_TOKEN": "¿Necesitas una?",
|
||||
"TITLE_LINK_NEED_TOKEN": "¿Necesitas un token para recuperar tu contraseña porque la has olvidado?",
|
||||
"PLACEHOLDER_NEW_PASSWORD": "Nueva contraseña",
|
||||
"PLACEHOLDER_RE_TYPE_NEW_PASSWORD": "Reescriba la nueva contraseña",
|
||||
"ACTION_RESET_PASSWORD": "Restablecer contraseña",
|
||||
"SUCCESS": "Nuestro Oompa Loopas guardaron tu nueva contraseña.<br /> Intenta <strong>registrarte</strong> con ella"
|
||||
},
|
||||
"INVITATION": {
|
||||
"PAGE_TITLE": "Acepta la invitación - Taiga",
|
||||
"PAGE_DESCRIPTION": "Acepta la invitación para unirte a un proyecto en Taiga, una plataforma de gestión de proyectos orientada a startups y equipos ágiles que buscan una herramienta sencilla, elegante y que les haga disfrutar trabajando."
|
||||
},
|
||||
"INVITATION_LOGIN_FORM": {
|
||||
"NOT_FOUND": "<strong>Ooops, tenemos un problema</strong><br /> Nuestros Oompa Loompas no pueden encontrar tu invitación.",
|
||||
"SUCCESS": "¡Acabas de unirte al proyecto! Bienvenido a {{project_name}}",
|
||||
"ERROR": "Según nuestros Oompa Loompas tú no estás registrado o has escrito mal tu contraseña."
|
||||
},
|
||||
"HOME": {
|
||||
"PAGE_TITLE": "Inicio - Taiga",
|
||||
"PAGE_DESCRIPTION": "Página de inicio de Taiga, con tus proyectos principales y tus historias de usuario, tareas y peticiones en progreso asignadas y las que observas.",
|
||||
"EMPTY_WATCHING": "<strong>Sigue</strong> aquellos proyectos, historias de usuario, tareas, peticiones... sobre los que quieras estar al tanto :)",
|
||||
"EMPTY_PROJECT_LIST": "Todavía no tienes ningún proyecto",
|
||||
"WORKING_ON_SECTION": "Trabajando en",
|
||||
"WATCHING_SECTION": "Observando"
|
||||
},
|
||||
"PROJECTS": {
|
||||
"PAGE_TITLE": "Mis proyectos - Taiga",
|
||||
"PAGE_DESCRIPTION": "Una lista con todos tus proyectos, puedes reordenarla o crear un proyecto nuevo.",
|
||||
"MY_PROJECTS": "Mis proyectos"
|
||||
},
|
||||
"ATTACHMENT": {
|
||||
"SECTION_NAME": "adjuntos",
|
||||
"TITLE": "{{ fileName }} subido el {{ date }}",
|
||||
|
@ -276,6 +374,7 @@
|
|||
},
|
||||
"MEMBERSHIPS": {
|
||||
"TITLE": "Administrar miembros",
|
||||
"PAGE_TITLE": "Miembros - {{projectName}}",
|
||||
"ADD_BUTTON": "+ Nuevo miembro",
|
||||
"ADD_BUTTON_TITLE": "Añadir un nuevo miembro"
|
||||
},
|
||||
|
@ -311,7 +410,7 @@
|
|||
"SALT_CHAT_ROOM": "Puedes añadirle un código salt al nombre del chat room"
|
||||
},
|
||||
"PROJECT_PROFILE": {
|
||||
"PAGE_TITLE": "Perfil del proyecto - {{sectionName}} - {{projectName}}",
|
||||
"PAGE_TITLE": "{{sectionName}} - Perfil de Proyecto - {{projectName}}\n",
|
||||
"PROJECT_DETAILS": "Info del proyecto",
|
||||
"PROJECT_NAME": "Nombre del proyecto",
|
||||
"PROJECT_SLUG": "Slug de proyecto",
|
||||
|
@ -352,23 +451,26 @@
|
|||
"ISSUE_ADD": "Añadir un atributo personalizado en las peticiones"
|
||||
},
|
||||
"PROJECT_VALUES": {
|
||||
"APP_TITLE": "Valores del proyecto - {{sectionName}} - {{projectName}}",
|
||||
"PAGE_TITLE": "{{sectionName}} - Valores del Proyectos - {{projectName}}",
|
||||
"REPLACEMENT": "Todos los elementos con este valor cambiarán a",
|
||||
"ERROR_DELETE_ALL": "No puedes eliminar todos los valores."
|
||||
},
|
||||
"PROJECT_VALUES_POINTS": {
|
||||
"TITLE": "Puntos de historia",
|
||||
"TITLE": "Puntos",
|
||||
"SUBTITLE": "Especifica los puntos a los que se podrían estimar tus historias de usuario",
|
||||
"US_TITLE": "Puntos de historia de usuario",
|
||||
"ACTION_ADD": "Añadir nuevo punto"
|
||||
},
|
||||
"PROJECT_VALUES_PRIORITIES": {
|
||||
"TITLE": "Prioridades de las peticiones",
|
||||
"TITLE": "Prioridades",
|
||||
"SUBTITLE": "Especifica las prioridades que podrán tener tus peticiones",
|
||||
"ISSUE_TITLE": "Prioridades de peticion",
|
||||
"ACTION_ADD": "Añadir nueva prioridad"
|
||||
},
|
||||
"PROJECT_VALUES_SEVERITIES": {
|
||||
"TITLE": "Gravedad de las peticiones",
|
||||
"TITLE": "Gravedades",
|
||||
"SUBTITLE": "Especifica la gravedad que tendrán tus peticiones",
|
||||
"ISSUE_TITLE": "Gravedades de petición",
|
||||
"ACTION_ADD": "Añadir nueva gravedad"
|
||||
},
|
||||
"PROJECT_VALUES_STATUS": {
|
||||
|
@ -382,10 +484,10 @@
|
|||
"TITLE": "Tipos",
|
||||
"SUBTITLE": "Especifica los deferentes tipos posibles de peticiones que pueden existir.",
|
||||
"ISSUE_TITLE": "Tipos de la petición",
|
||||
"ACTION_ADD": "Añadir nuevo tipo"
|
||||
"ACTION_ADD": "Añadir nuevo {{objName}}"
|
||||
},
|
||||
"ROLES": {
|
||||
"SECTION_NAME": "Roles - {{projectName}}",
|
||||
"PAGE_TITLE": "Roles - {{projectName}}",
|
||||
"WARNING_NO_ROLE": "Ojo, ningún rol en tu proyecto podrá estimar historias de usuario",
|
||||
"HELP_ROLE_ENABLED": "Si lo activas, los miembros que posean este rol serán capaces de estimar las histórias de usuario",
|
||||
"COUNT_MEMBERS": "{{ role.members_count }} miembros con este rol",
|
||||
|
@ -402,20 +504,20 @@
|
|||
},
|
||||
"BITBUCKET": {
|
||||
"SECTION_NAME": "Bitbucket",
|
||||
"APP_TITLE": "Bitbucket - {{projectName}}",
|
||||
"PAGE_TITLE": "Bitbucket - {{projectName}}",
|
||||
"INFO_VERIFYING_IP": "Las peticiones de Bitbucket no van firmadas, con la IP de origen verificamos su procedencia. Déjalo vacío y no se verificarán."
|
||||
},
|
||||
"GITLAB": {
|
||||
"SECTION_NAME": "Gitlab",
|
||||
"APP_TITLE": "Gitlab - {{projectName}}",
|
||||
"PAGE_TITLE": "Gitlab - {{projectName}}",
|
||||
"INFO_VERIFYING_IP": "Las peticiones de Gitlab no van firmadas, con la IP de origen verificamos su procedencia. Déjalo vacío y no se verificarán."
|
||||
},
|
||||
"GITHUB": {
|
||||
"SECTION_NAME": "Github",
|
||||
"APP_TITLE": "Github - {{projectName}}"
|
||||
"PAGE_TITLE": "Github - {{projectName}}"
|
||||
},
|
||||
"WEBHOOKS": {
|
||||
"APP_TITLE": "Webhooks - {{projectName}}",
|
||||
"PAGE_TITLE": "Webhooks - {{projectName}}",
|
||||
"SECTION_NAME": "Webhooks",
|
||||
"SUBTITLE": "Los Webhooks notificarán a servicios externos sobre todos los eventos que ocurren en Taiga como comentarios, historias de usuario...",
|
||||
"ADD_NEW": "Añadir un Nuevo Webhook",
|
||||
|
@ -441,6 +543,7 @@
|
|||
"WEBHOOK_NAME": "Webhook '{{name}}'"
|
||||
},
|
||||
"CUSTOM_ATTRIBUTES": {
|
||||
"PAGE_TITLE": "{{sectionName}} - Atributos Personalizados - {{projectName}}",
|
||||
"ADD": "Añadir atributo personalizado",
|
||||
"EDIT": "Editar atributo personalizado",
|
||||
"DELETE": "Eliminar atributo personalizado",
|
||||
|
@ -518,9 +621,36 @@
|
|||
"TITLE": "Servicios"
|
||||
}
|
||||
},
|
||||
"USER": {
|
||||
"PROFILE": {
|
||||
"PAGE_TITLE": "{{userFullName}} (@{{userUsername}})",
|
||||
"EDIT": "Editar perfil",
|
||||
"FOLLOW": "Seguir",
|
||||
"PROJECTS": "Proyectos",
|
||||
"CLOSED_US": "Historias cerradas",
|
||||
"CONTACTS": "Contactos",
|
||||
"REPORT": "Reportar Abuso",
|
||||
"ACTIVITY_TAB": "Pestaña de Actividad",
|
||||
"PROJECTS_TAB": "Pestaña de Proyectos",
|
||||
"CONTACTS_TAB": "Pestaña de Contactos",
|
||||
"FAVORITES_TAB": "Pestaña de Favoritos",
|
||||
"CONTACTS_EMPTY": "{{username}} no tiene contactos todavía",
|
||||
"CURRENT_USER_CONTACTS_EMPTY": "No tienes contactos todavía",
|
||||
"CURRENT_USER_CONTACTS_EMPTY_EXPLAIN": "Las personas con las que trabajas en Taiga serán tus contactos automáticamente",
|
||||
"PROJECTS_EMPTY": "{{username}} no tiene proyectos todavía"
|
||||
},
|
||||
"PROFILE_SIDEBAR": {
|
||||
"TITLE": "Tu perfil",
|
||||
"DESCRIPTION": "La gente puede ver aquello que haces y en qué estás trabajando. Añade una buena bio para que puedan ver la mejor versión de tu perfil.",
|
||||
"ADD_INFO": "Edita tu bio"
|
||||
}
|
||||
},
|
||||
"PROJECT": {
|
||||
"PAGE_TITLE": "{{projectName}}",
|
||||
"WELCOME": "Bienvenido",
|
||||
"SECTION_PROJECTS": "Proyectos",
|
||||
"HELP": "Reordena tus proyectos para ver arriba los que más utilizas.<br/> Los 10 primeros aparecerán en la lista de proyectos de la barra de navegación de arriba.",
|
||||
"PRIVATE": "Proyecto privado",
|
||||
"STATS": {
|
||||
"PROJECT": "puntos<br/> proyecto",
|
||||
"DEFINED": "puntos<br/> definidos",
|
||||
|
@ -529,6 +659,7 @@
|
|||
},
|
||||
"SECTION": {
|
||||
"SEARCH": "Buscar",
|
||||
"TIMELINE": "Timeline",
|
||||
"BACKLOG": "Backlog",
|
||||
"KANBAN": "Kanban",
|
||||
"ISSUES": "Peticiones",
|
||||
|
@ -541,9 +672,32 @@
|
|||
"SECTION_TITLE": "Tus proyectos",
|
||||
"PLACEHOLDER_SEARCH": "Buscar en...",
|
||||
"ACTION_CREATE_PROJECT": "Crear proyecto",
|
||||
"TITLE_ACTION_IMPORT": "Importar proyecto",
|
||||
"ACTION_IMPORT_PROJECT": "Importar proyecto",
|
||||
"SEE_MORE_PROJECTS": "Ver más proyectos",
|
||||
"TITLE_CREATE_PROJECT": "Crear proyecto",
|
||||
"TITLE_IMPORT_PROJECT": "Importar proyecto",
|
||||
"TITLE_PRVIOUS_PROJECT": "Mostrar proyectos anteriores",
|
||||
"TITLE_NEXT_PROJECT": "Mostrar siguientes proyectos"
|
||||
"TITLE_NEXT_PROJECT": "Mostrar siguientes proyectos",
|
||||
"HELP_TITLE": "Página de Soporte de Taiga",
|
||||
"HELP": "Ayuda",
|
||||
"FEEDBACK_TITLE": "Envíanos tu feedback",
|
||||
"FEEDBACK": "Feedback",
|
||||
"NOTIFICATIONS_TITLE": "Edita la configuración de tus notificaciones",
|
||||
"NOTIFICATIONS": "Notificaciones",
|
||||
"ORGANIZATIONS_TITLE": "Edita tus organizaciónes",
|
||||
"ORGANIZATIONS": "Editar organizaciones",
|
||||
"SETTINGS_TITLE": "Editar tus configuraciones",
|
||||
"SETTINGS": "Configuraciones",
|
||||
"VIEW_PROFILE_TITLE": "Ver perfil",
|
||||
"VIEW_PROFILE": "Ver perfil",
|
||||
"EDIT_PROFILE_TITLE": "Editar tu perfil",
|
||||
"EDIT_PROFILE": "Editar Perfil",
|
||||
"CHANGE_PASSWORD_TITLE": "Cambiar contraseña",
|
||||
"CHANGE_PASSWORD": "Cambiar contraseña",
|
||||
"DASHBOARD_TITLE": "Dashboard",
|
||||
"DISCOVER_TITLE": "Descubre los proyectos más relevantes",
|
||||
"DISCOVER": "Descubrir",
|
||||
"ACTION_REORDER": "Arrastrar y soltar para reordenar"
|
||||
},
|
||||
"IMPORT": {
|
||||
"TITLE": "Importando Proyecto",
|
||||
|
@ -624,6 +778,8 @@
|
|||
}
|
||||
},
|
||||
"US": {
|
||||
"PAGE_TITLE": "{{userStorySubject}} - Historia de Usuario {{userStoryRef}} - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "Estado: {{userStoryStatus }}. Completado el {{userStoryProgressPercentage}}% ({{userStoryClosedTasks}} de {{userStoryTotalTasks}} tareas cerradas). Puntos: {{userStoryPoints}}. Descripción: {{userStoryDescription}}",
|
||||
"SECTION_NAME": "Detalles de historia de usuario",
|
||||
"LINK_TASKBOARD": "Panel de tareas",
|
||||
"TITLE_LINK_TASKBOARD": "Ir al panel de tareas",
|
||||
|
@ -711,6 +867,8 @@
|
|||
}
|
||||
},
|
||||
"BACKLOG": {
|
||||
"PAGE_TITLE": "Backlog - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "El panel del backlog, con las historias de usuario y sprints del proyecto {{projectName}}: {{projectDescription}}",
|
||||
"SECTION_NAME": "Backlog",
|
||||
"MOVE_US_TO_CURRENT_SPRINT": "Mover al Sprint en curso",
|
||||
"SHOW_FILTERS": "Mostrar filtros",
|
||||
|
@ -790,6 +948,8 @@
|
|||
"VERSION_ERROR": "Algún compañero se te ha adelantado y ha actualizado esto, nuestros Oompa Loompas no pueden aplicar tus cambios. Por favor, recarga la página y aplícalos nuevamente (se perderán)."
|
||||
},
|
||||
"TASKBOARD": {
|
||||
"PAGE_TITLE": "{{sprintName}} - Sprint - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "Sprint {{sprintName}} (desde el {{startDate}} al {{endDate}}) de {{projectName}}. Completado el {{completedPercentage}}% ({{completedPoints}} de {{totalPoints}} puntos). {{openTasks}} de {{totalTasks}} tareas abiertas.",
|
||||
"SECTION_NAME": "Panel de Tareas",
|
||||
"TITLE_ACTION_ADD": "Añade una nueva tarea",
|
||||
"TITLE_ACTION_ADD_BULK": "Añadir nuevas tareas en bloque",
|
||||
|
@ -813,6 +973,8 @@
|
|||
}
|
||||
},
|
||||
"TASK": {
|
||||
"PAGE_TITLE": "{{taskSubject}} - Tarea {{taskRef}} - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "Estado: {{taskStatus }}. Descripción: {{taskDescription}}",
|
||||
"SECTION_NAME": "Detalles de tarea",
|
||||
"LINK_TASKBOARD": "Panel de tareas",
|
||||
"TITLE_LINK_TASKBOARD": "Ir al panel de tareas",
|
||||
|
@ -846,7 +1008,7 @@
|
|||
},
|
||||
"CANCEL_ACCOUNT": {
|
||||
"TITLE": "Cancelar tu cuenta de usuario",
|
||||
"SUBTITLE": "Sentimos que estés abandonando la taiga, esperamos que hayas disfrutado de tu estancia :)",
|
||||
"SUBTITLE": "Sentimos mucho que abandones nuestra taiga, esperamos que hayas disfrutado de tu estancia :)",
|
||||
"PLACEHOLDER_INPUT_TOKEN": "token de cancelación de cuenta",
|
||||
"ACTION_LEAVING": "¡Sí, me largo!",
|
||||
"SUCCESS": "Nuestros Oompa Loompas eliminaron tu cuenta"
|
||||
|
@ -858,56 +1020,9 @@
|
|||
"ACTION_CHANGE_EMAIL": "Cambiar email",
|
||||
"SUCCESS": "Nuestros Oompa Loompas actualizaron tu correo"
|
||||
},
|
||||
"CHANGE_PASSWORD_RECOVERY_FORM": {
|
||||
"TITLE": "Crear una nueva contraseña de Taiga",
|
||||
"SUBTITLE": "Y bueno, es posible que quieras comer un poco más de alimentos ricos en hierro, son buenos para tu cerebro :P",
|
||||
"PLACEHOLDER_RECOVER_PASSWORD_TOKEN": "token de recuperación de contraseña",
|
||||
"LINK_NEED_TOKEN": "¿Necesitas una?",
|
||||
"TITLE_LINK_NEED_TOKEN": "¿Necesitas un token para recuperar tu contraseña porque la has olvidado?",
|
||||
"PLACEHOLDER_NEW_PASSWORD": "Nueva contraseña",
|
||||
"PLACEHOLDER_RE_TYPE_NEW_PASSWORD": "Reescriba la nueva contraseña",
|
||||
"ACTION_RESET_PASSWORD": "Restablecer contraseña",
|
||||
"SUCCESS": "Nuestro Oompa Loopas guardaron tu nueva contraseña.<br /> Intenta <strong>registrarte</strong> con ella"
|
||||
},
|
||||
"FORGOT_PASSWORD_FORM": {
|
||||
"TITLE": "Vaya, ¿has olvidado tu contraseña?",
|
||||
"SUBTITLE": "Escribe tu nombre de usuario o email para obtener una nueva",
|
||||
"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": "<strong>¡Revisa tu bandeja de entrada!</strong><br />Te hemos enviado un mail con las instrucciones necesarias para restablecer tu contraseña\n",
|
||||
"ERROR": "Según nuestros Oompa Loompas tú no estás registrado"
|
||||
},
|
||||
"LOGIN_COMMON": {
|
||||
"HEADER": "Ya tengo una cuenta en Taiga",
|
||||
"PLACEHOLDER_AUTH_NAME": "Nombre de usuario o email (distingue mayúsculas y minúsculas)",
|
||||
"LINK_FORGOT_PASSWORD": "¿La olvidaste?",
|
||||
"TITLE_LINK_FORGOT_PASSWORD": "¿Has olvidado tu contraseña?",
|
||||
"ACTION_ENTER": "Entrar",
|
||||
"ACTION_SIGN_IN": "Ingresar",
|
||||
"PLACEHOLDER_AUTH_PASSWORD": "Contraseña (distingue mayúsculas y minúsculas)"
|
||||
},
|
||||
"LOGIN_FORM": {
|
||||
"ERROR_AUTH_INCORRECT": "Nuestros Oompa Loompas indican que tu nombre de usuario/correo o contraseña son incorrectos",
|
||||
"ERROR_GENERIC": "Nuestros Oompa Loompas indican que ha habido un error.",
|
||||
"SUCCESS": "Nuestros Oompa Loompas están felices, bienvenido a Taiga."
|
||||
},
|
||||
"INVITATION_LOGIN_FORM": {
|
||||
"NOT_FOUND": "<strong>Ooops, tenemos un problema</strong><br /> Nuestros Oompa Loompas no pueden encontrar tu invitación.",
|
||||
"SUCCESS": "¡Acabas de unirte al proyecto! Bienvenido a {{project_name}}",
|
||||
"ERROR": "Según nuestros Oompa Loompas tú no estás registrado o has escrito mal tu contraseña."
|
||||
},
|
||||
"REGISTER_FORM": {
|
||||
"TITLE": "Crea tu nueva cuenta en Taiga, ¡es gratis!",
|
||||
"PLACEHOLDER_NAME": "Escribe un nombre de usuario (distingue mayúsculas y minúsculas)",
|
||||
"PLACEHOLDER_FULL_NAME": "Escribe tu nombre completo",
|
||||
"PLACEHOLDER_EMAIL": "Tu email",
|
||||
"PLACEHOLDER_PASSWORD": "Establece una contraseña (distingue mayúsculas y minúsculas)",
|
||||
"ACTION_SIGN_UP": "Registrarme",
|
||||
"TITLE_LINK_LOGIN": "Iniciar sesión",
|
||||
"LINK_LOGIN": "¿Ya te has registrado? Inicia sesión"
|
||||
},
|
||||
"ISSUES": {
|
||||
"PAGE_TITLE": "Peticiones - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "El panel de peticiones del proyecto {{projectName}}: {{projectDescription}}\n",
|
||||
"LIST_SECTION_NAME": "Peticiones",
|
||||
"SECTION_NAME": "Detalles de petición",
|
||||
"ACTION_NEW_ISSUE": "+ NUEVA PETICIÓN",
|
||||
|
@ -921,6 +1036,11 @@
|
|||
"TITLE_NEXT_ISSUE": "petición siguiente",
|
||||
"ACTION_DELETE": "Borrar petición",
|
||||
"LIGHTBOX_TITLE_BLOKING_ISSUE": "Petición bloqueada",
|
||||
"FIELDS": {
|
||||
"PRIORITY": "Prioridad",
|
||||
"SEVERITY": "Gravedad",
|
||||
"TYPE": "Tipo"
|
||||
},
|
||||
"CONFIRM_PROMOTE": {
|
||||
"TITLE": "Promover esta petición a una nueva historia de usuario",
|
||||
"MESSAGE": "¿Está seguro de que desea crear una nueva Historia de Usuario a partir de esta Petición?"
|
||||
|
@ -966,7 +1086,13 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"ISSUE": {
|
||||
"PAGE_TITLE": "{{issueSubject}} - Petición {{issueRef}} - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "Estado: {{issueStatus }}. Tipo: {{issueType}}, Prioridad: {{issuePriority}}. Gravedad: {{issueSeverity}}. Descripción: {{issueDescription}}"
|
||||
},
|
||||
"KANBAN": {
|
||||
"PAGE_TITLE": "Kanban - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "El panel Kanban, con las historias de usuario del proyecto {{projectName}}: {{projectDescription}}",
|
||||
"SECTION_NAME": "Kanban",
|
||||
"TITLE_ACTION_FOLD": "Plegar columna",
|
||||
"TITLE_ACTION_UNFOLD": "Desplegar columna",
|
||||
|
@ -981,6 +1107,8 @@
|
|||
"UNDO_ARCHIVED": "Arrástrala y suéltala de nuevo para deshacer el cambio"
|
||||
},
|
||||
"SEARCH": {
|
||||
"PAGE_TITLE": "Buscar - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "Busca cualquier cosa: historias de usuario, peticiones, tareas o páginas del wiki en el proyecto {{projectName}}: {{projectDescription}}",
|
||||
"FILTER_USER_STORIES": "Historias de Usuario",
|
||||
"FILTER_ISSUES": "Peticiones",
|
||||
"FILTER_TASKS": "Tareas",
|
||||
|
@ -991,6 +1119,8 @@
|
|||
"EMPTY_DESCRIPTION": "Prueba con otra pestaña de las de arriba o busca de nuevo"
|
||||
},
|
||||
"TEAM": {
|
||||
"PAGE_TITLE": "Equipo - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "EL panel de equipo, para mostrar a todos los miembros del proyecto {{projectName}}: {{projectDescription}}",
|
||||
"SECTION_NAME": "Equipo",
|
||||
"APP_TITLE": "EQUIPO - {{projectName}}",
|
||||
"PLACEHOLDER_INPUT_SEARCH": "Buscar por nombre completo...",
|
||||
|
@ -1011,16 +1141,6 @@
|
|||
"CONFIRM_LEAVE_PROJECT": "¿Esta seguro que desea dejar el proyecto?",
|
||||
"ACTION_LEAVE_PROJECT": "Abandonar este proyecto"
|
||||
},
|
||||
"CHANGE_PASSWORD": {
|
||||
"SECTION_NAME": "Cambiar contraseña",
|
||||
"FIELD_CURRENT_PASSWORD": "Contraseña actual",
|
||||
"PLACEHOLDER_CURRENT_PASSWORD": "Tu contraseña actual (o déjalo vacío si todavía no tienes contraseña)",
|
||||
"FIELD_NEW_PASSWORD": "Nueva contraseña",
|
||||
"PLACEHOLDER_NEW_PASSWORD": "Escribe una contraseña nueva",
|
||||
"FIELD_RETYPE_PASSWORD": "Reescribe la nueva contraseña",
|
||||
"PLACEHOLDER_RETYPE_PASSWORD": "Reescribe la nueva contraseña",
|
||||
"ERROR_PASSWORD_MATCH": "Las contraseñas no coinciden"
|
||||
},
|
||||
"USER_SETTINGS": {
|
||||
"AVATAR_MAX_SIZE": "[Tamaño Max.: {{maxFileSize}}]",
|
||||
"MENU": {
|
||||
|
@ -1059,7 +1179,7 @@
|
|||
"EMAIL": "Correo",
|
||||
"FULL_NAME": "Nombre completo",
|
||||
"PLACEHOLDER_FULL_NAME": "Indica tu nombre completo (p. e. Íñigo Montoya)",
|
||||
"BIO": "Bio",
|
||||
"BIO": "Bio (max. 210 caracteres)",
|
||||
"PLACEHOLDER_BIO": "Dinos algo acerca de ti",
|
||||
"LANGUAGE": "Idioma",
|
||||
"LANGUAGE_DEFAULT": "- usar idioma por defecto -"
|
||||
|
@ -1074,6 +1194,8 @@
|
|||
"PROGRESS_NAME_DESCRIPTION": "Nombre y descripción"
|
||||
},
|
||||
"WIKI": {
|
||||
"PAGE_TITLE": "{{wikiPageName}} - Wiki - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "última edición el {{lastModifiedDate}} ({{totalEditions}} ediciones en total) Contenido: {{ wikiPageContent }}",
|
||||
"DATETIME": "DD MMM YYYY HH:mm",
|
||||
"PLACEHOLDER_PAGE": "Escribe el contenido de tu página",
|
||||
"REMOVE": "Eliminar esta página del wiki",
|
||||
|
@ -1087,5 +1209,43 @@
|
|||
"LAST_EDIT": "última <br />edición",
|
||||
"LAST_MODIFICATION": "ultima modificación"
|
||||
}
|
||||
},
|
||||
"HINTS": {
|
||||
"SECTION_NAME": "Consejo",
|
||||
"LINK": "Si quieres saber como funciona visita nuestra página de soporte",
|
||||
"LINK_TITLE": "Visita nuestra página de soporte",
|
||||
"HINT1_TITLE": "¿Sabes que puedes importar y exportar proyectos?",
|
||||
"HINT1_TEXT": "Esto permite extraer todos tus datos para moverlos de una instancia de Taiga a otra.\n",
|
||||
"HINT2_TITLE": "¿Sabías que puedes crear atributos personalizados?",
|
||||
"HINT2_TEXT": "Los equipos ahora pueden crear atributos personalizados como un medio flexible para introducir datos específicos útiles para su flujo de trabajo particular",
|
||||
"HINT3_TITLE": "Reordenar tus proyectos para facilitar el acceso a los más relevantes para ti",
|
||||
"HINT3_TEXT": "Los 10 primeros proyectos aparecerán en el listado del acceso directo de la barra superior.",
|
||||
"HINT4_TITLE": "Has olvidado en qué estabas trabajando?",
|
||||
"HINT4_TEXT": "No te preocupes, en el dashboard encontrarás las tareas, peticiones e historias de usuario abiertas en el orden en el que trabajste en ellas."
|
||||
},
|
||||
"TIMELINE": {
|
||||
"UPLOAD_ATTACHMENT": "{{username}} ha subido un nuevo adjunto en {{obj_name}}\n",
|
||||
"US_CREATED": "{{username}} ha creado una nueva historia {{obj_name}} en {{project_name}}",
|
||||
"ISSUE_CREATED": "{{username}} ha creado una nueva petición {{obj_name}} en {{project_name}}",
|
||||
"TASK_CREATED": "{{username}} ha creado una nueva tarea {{obj_name}} en {{project_name}}",
|
||||
"TASK_CREATED_WITH_US": "{{username}} ha creado una nueva tarea {{obj_name}} en {{project_name}} que proviene de la historia {{us_name}}",
|
||||
"WIKI_CREATED": "{{username}} ha creado una nueva página de wiki {{obj_name}} en {{project_name}}\n",
|
||||
"MILESTONE_CREATED": "{{username}} ha creado un nuevo sprint {{obj_name}} en {{project_name}}",
|
||||
"NEW_PROJECT": "{{username}} creó el proyecto {{project_name}}",
|
||||
"MILESTONE_UPDATED": "{{username}} ha actualizado el sprint {{obj_name}}",
|
||||
"US_UPDATED": "{{username}} ha actualizado el atributo \"{{field_name}}\" de la historia {{obj_name}}",
|
||||
"ISSUE_UPDATED": "{{username}} ha actualizado el atributo \"{{field_name}}\" de la petición {{obj_name}}",
|
||||
"TASK_UPDATED": "{{username}} ha actualizado el atributo \"{{field_name}}\" de la tarea {{obj_name}}",
|
||||
"TASK_UPDATED_WITH_US": "{{username}} ha actualizado el atributo \"{{field_name}}\" de la tarea {{obj_name}} que proviene de la historia {{us_name}}",
|
||||
"WIKI_UPDATED": "{{username}} ha actualizado la página del wiki {{obj_name}}",
|
||||
"NEW_COMMENT_US": "{{username}} ha añadido un comentado en la historia {{obj_name}}",
|
||||
"NEW_COMMENT_ISSUE": "{{username}} ha añadido un comentado en la petición {{obj_name}}",
|
||||
"NEW_COMMENT_TASK": "{{username}} ha añadido un comentado en la tarea {{obj_name}}",
|
||||
"NEW_MEMBER": "{{project_name}} tiene un nuevo miembro",
|
||||
"US_ADDED_MILESTONE": "{{username}} ha añadido la historia {{obj_name}} a {{sprint_name}}",
|
||||
"US_REMOVED_FROM_MILESTONE": "{{username}} ha añadido la historia {{obj_name}} al backlog",
|
||||
"BLOCKED": "{{username}} ha bloqueado {{obj_name}}",
|
||||
"UNBLOCKED": "{{username}} ha desbloqueado {{obj_name}}",
|
||||
"NEW_USER": "{{username}} se ha unido a Taiga"
|
||||
}
|
||||
}
|
|
@ -100,6 +100,10 @@
|
|||
"SAT": "Lau"
|
||||
}
|
||||
},
|
||||
"SEE_USER_PROFILE": "See {{username }} profile",
|
||||
"USER_STORY": "Käyttäjätarina",
|
||||
"TASK": "Task",
|
||||
"ISSUE": "Issue",
|
||||
"TAGS": {
|
||||
"PLACEHOLDER": "Anna avainsana...",
|
||||
"DELETE": "Poista avainsana",
|
||||
|
@ -125,7 +129,8 @@
|
|||
"ASSIGNED_TO": "Tekijä",
|
||||
"POINTS": "Pisteet",
|
||||
"BLOCKED_NOTE": "estetty muistiinpano",
|
||||
"IS_BLOCKED": "on estetty"
|
||||
"IS_BLOCKED": "on estetty",
|
||||
"REF": "Ref"
|
||||
},
|
||||
"ROLES": {
|
||||
"ALL": "Kaikki"
|
||||
|
@ -231,14 +236,107 @@
|
|||
"ADD_WIKI_LINKS": "Lisää wiki-linkkejä",
|
||||
"DELETE_WIKI_LINKS": "Poista wiki-linkkejä"
|
||||
}
|
||||
},
|
||||
"META": {
|
||||
"PAGE_TITLE": "Taiga",
|
||||
"PAGE_DESCRIPTION": "Taiga is a project management platform for startups and agile developers & designers who want a simple, beautiful tool that makes work truly enjoyable."
|
||||
}
|
||||
},
|
||||
"LOGIN": {
|
||||
"PAGE_TITLE": "Login - Taiga",
|
||||
"PAGE_DESCRIPTION": "Logging in to Taiga, a project management platform for startups and agile developers & designers who want a simple, beautiful tool that makes work truly enjoyable."
|
||||
},
|
||||
"AUTH": {
|
||||
"INVITED_YOU": "on kutsunut sinut projektiin",
|
||||
"NOT_REGISTERED_YET": "Etkö ole vielä rekisteröitynyt?",
|
||||
"REGISTER": "Rekisteröidy",
|
||||
"CREATE_ACCOUNT": "luo ilmainen tunnuksesi täällä"
|
||||
},
|
||||
"LOGIN_COMMON": {
|
||||
"HEADER": "Minulla on jo Taiga tunnus",
|
||||
"PLACEHOLDER_AUTH_NAME": "Käyttäjänimi tai sähköposti (kirjainkoko merkitsevä)",
|
||||
"LINK_FORGOT_PASSWORD": "Unohditko?",
|
||||
"TITLE_LINK_FORGOT_PASSWORD": "Unohditko salasanasi?",
|
||||
"ACTION_ENTER": "Sisään",
|
||||
"ACTION_SIGN_IN": "Kirjaudu sisään",
|
||||
"PLACEHOLDER_AUTH_PASSWORD": "Salasana (kirjainkoko merkitsevä)"
|
||||
},
|
||||
"LOGIN_FORM": {
|
||||
"ERROR_AUTH_INCORRECT": "Oompa Loompas sanovat että käyttäjänimesi tai sähköpostisi tai salasanasi on väärä.",
|
||||
"SUCCESS": "Oompa Loompas ovat onnellisia, tervetuloa Taigaan."
|
||||
},
|
||||
"REGISTER": {
|
||||
"PAGE_TITLE": "Register - Taiga",
|
||||
"PAGE_DESCRIPTION": "Create your account in Taiga, a project management platform for startups and agile developers & designers who want a simple, beautiful tool that makes work truly enjoyable."
|
||||
},
|
||||
"REGISTER_FORM": {
|
||||
"TITLE": "Rekisteröi uusi Taiga tunnus (ilmainen)",
|
||||
"PLACEHOLDER_NAME": "Anna käyttäjänimi (kirjainkoko on merkitsevä)",
|
||||
"PLACEHOLDER_FULL_NAME": "Anna koko nimesi",
|
||||
"PLACEHOLDER_EMAIL": "Sähköpostisi",
|
||||
"PLACEHOLDER_PASSWORD": "Anna salasana (kirjainkoko merkitsevä)",
|
||||
"ACTION_SIGN_UP": "Kirjaudu sisään",
|
||||
"TITLE_LINK_LOGIN": "Kirjaudu sisään",
|
||||
"LINK_LOGIN": "Oletko jo rekisteröitynyt? Kirjaudu sisään"
|
||||
},
|
||||
"FORGOT_PASSWORD": {
|
||||
"PAGE_TITLE": "Forgot password - Taiga",
|
||||
"PAGE_DESCRIPTION": "Enter your username or email to get a new password and you can access to Taiga again."
|
||||
},
|
||||
"FORGOT_PASSWORD_FORM": {
|
||||
"TITLE": "Oops, unohditko salasanasi?",
|
||||
"SUBTITLE": "Anna käyttäjänimesi tai sähköpostisi saadaksesi uuden",
|
||||
"PLACEHOLDER_FIELD": "Käyttäjänimi tai sähköposti",
|
||||
"ACTION_RESET_PASSWORD": "Uusi salsanasi",
|
||||
"LINK_CANCEL": "Vie minut takaisin, muistan sen.",
|
||||
"SUCCESS": "<strong>Tarkista sähköpostisi!</strong><br />Olemme lähettäneet sinulle sähköpostissa kirjautumisohjeet",
|
||||
"ERROR": "Oompa Loompas sanovat että käyttäjänimesi tai sähköpostisi tai salasanasi on väärä."
|
||||
},
|
||||
"CHANGE_PASSWORD": {
|
||||
"PAGE_TITLE": "Change you password - Taiga",
|
||||
"PAGE_DESCRIPTION": "Set a new passoword for your Taiga account and hey!, you may want to eat some more iron-rich food, it's good for your brain :P",
|
||||
"SECTION_NAME": "Muuta salasanaa",
|
||||
"FIELD_CURRENT_PASSWORD": "Nykyinen salasana",
|
||||
"PLACEHOLDER_CURRENT_PASSWORD": "Nykyinen salasanasi (tai on tyhjä jos sinulla ei vielä ole)",
|
||||
"FIELD_NEW_PASSWORD": "Uusi salasana",
|
||||
"PLACEHOLDER_NEW_PASSWORD": "Anna uusi salasana",
|
||||
"FIELD_RETYPE_PASSWORD": "Anna salasana uudelleen",
|
||||
"PLACEHOLDER_RETYPE_PASSWORD": "Anna salasana uudelleen",
|
||||
"ERROR_PASSWORD_MATCH": "Salasanat eivät täsmää"
|
||||
},
|
||||
"CHANGE_PASSWORD_RECOVERY_FORM": {
|
||||
"TITLE": "Luo uusi pääsy Taigaan",
|
||||
"SUBTITLE": "Rautapitoinen ruoka on hyväksi aivoille :P",
|
||||
"PLACEHOLDER_RECOVER_PASSWORD_TOKEN": "Palauta sähköposti-tokeni",
|
||||
"LINK_NEED_TOKEN": "Tarvitsetko yhden?",
|
||||
"TITLE_LINK_NEED_TOKEN": "Tarvitsitko tokenia palauttaakseni salasanan koska unohdit sen?",
|
||||
"PLACEHOLDER_NEW_PASSWORD": "Uusi salasana",
|
||||
"PLACEHOLDER_RE_TYPE_NEW_PASSWORD": "Anna salasana uudelleen",
|
||||
"ACTION_RESET_PASSWORD": "Uusi salsanasi",
|
||||
"SUCCESS": "Oompa Loompas tallensivat uuden salasanasi.<br /> Yritä <strong>kirjautua sisään</strong> sillä."
|
||||
},
|
||||
"INVITATION": {
|
||||
"PAGE_TITLE": "Invitation acceptance - Taiga",
|
||||
"PAGE_DESCRIPTION": "Accept the invitation to join a project in Taiga, a project management platform for startups and agile developers & designers who want a simple, beautiful tool that makes work truly enjoyable."
|
||||
},
|
||||
"INVITATION_LOGIN_FORM": {
|
||||
"NOT_FOUND": "<strong>Ooops, meillä on ongelma</strong><br />Our Oompa Loompas eivät löydä kutsuasi.",
|
||||
"SUCCESS": "Olet onnistuneesti liittynyt projektiin {{project_name}}. Tervetuloa!",
|
||||
"ERROR": "Oompa Loompas sanovat että käyttäjänimesi tai sähköpostisi tai salasanasi on väärä."
|
||||
},
|
||||
"HOME": {
|
||||
"PAGE_TITLE": "Home - Taiga",
|
||||
"PAGE_DESCRIPTION": "The Taiga home page with your main projects and all your assigned and watched user stories, tasks and issues",
|
||||
"EMPTY_WATCHING": "<strong>Follow</strong> the projects, User Stories, Tasks, Issues... that you want to know about :)",
|
||||
"EMPTY_PROJECT_LIST": "You don't have any projects yet",
|
||||
"WORKING_ON_SECTION": "Working on",
|
||||
"WATCHING_SECTION": "Watching"
|
||||
},
|
||||
"PROJECTS": {
|
||||
"PAGE_TITLE": "My projects - Taiga",
|
||||
"PAGE_DESCRIPTION": "A list with all your projects, you can reorder or create a new one.",
|
||||
"MY_PROJECTS": "My projects"
|
||||
},
|
||||
"ATTACHMENT": {
|
||||
"SECTION_NAME": "liitteet",
|
||||
"TITLE": "{{ fileName }} ladattu {{ date }}\n",
|
||||
|
@ -276,6 +374,7 @@
|
|||
},
|
||||
"MEMBERSHIPS": {
|
||||
"TITLE": "Hallinnoi jäseniä",
|
||||
"PAGE_TITLE": "Memberships - {{projectName}}",
|
||||
"ADD_BUTTON": "+ Uusi jäsen",
|
||||
"ADD_BUTTON_TITLE": "Lisää jäsen"
|
||||
},
|
||||
|
@ -311,7 +410,7 @@
|
|||
"SALT_CHAT_ROOM": "Voit halutessasi lisätä suolaan chat-huoneen nimeen"
|
||||
},
|
||||
"PROJECT_PROFILE": {
|
||||
"PAGE_TITLE": "Projektin profiili - {{sectionName}} - {{projectName}}",
|
||||
"PAGE_TITLE": "{{sectionName}} - Projektin profiili - {{projectName}}",
|
||||
"PROJECT_DETAILS": "Projektin tiedot",
|
||||
"PROJECT_NAME": "Projektin nimi",
|
||||
"PROJECT_SLUG": "Projektin hukka-aika",
|
||||
|
@ -352,23 +451,26 @@
|
|||
"ISSUE_ADD": "Lisää oma kenttä pyynnöille"
|
||||
},
|
||||
"PROJECT_VALUES": {
|
||||
"APP_TITLE": "Projektin arvot - {{sectionName}} - {{projectName}}",
|
||||
"PAGE_TITLE": "{{sectionName}} - Project values - {{projectName}}",
|
||||
"REPLACEMENT": "Kaikkii riveihin joissa on tämä arvo muutetaan ",
|
||||
"ERROR_DELETE_ALL": "Et voi poistaa kaikkia arvoja."
|
||||
},
|
||||
"PROJECT_VALUES_POINTS": {
|
||||
"TITLE": "Kt pisteet",
|
||||
"TITLE": "Points",
|
||||
"SUBTITLE": "Määrittele pisteet joihin käyttäjätarinat voidaan arvioida",
|
||||
"US_TITLE": "US points",
|
||||
"ACTION_ADD": "Lisää uusi piste"
|
||||
},
|
||||
"PROJECT_VALUES_PRIORITIES": {
|
||||
"TITLE": "Pyyntöjen tärkeydet",
|
||||
"TITLE": "Priorities",
|
||||
"SUBTITLE": "Määrittele tärkeydet pyynnöille",
|
||||
"ISSUE_TITLE": "Issue priorities",
|
||||
"ACTION_ADD": "Lisää uusi tärkeys"
|
||||
},
|
||||
"PROJECT_VALUES_SEVERITIES": {
|
||||
"TITLE": "Pyyntöjen vakavuudet",
|
||||
"TITLE": "Severities",
|
||||
"SUBTITLE": "Määrittele pyyntöjen vakavuudet",
|
||||
"ISSUE_TITLE": "Issue severities",
|
||||
"ACTION_ADD": "Lisää uusi vakavuus"
|
||||
},
|
||||
"PROJECT_VALUES_STATUS": {
|
||||
|
@ -382,10 +484,10 @@
|
|||
"TITLE": "Tyypit",
|
||||
"SUBTITLE": "Määrittele pyyntöjen tyypit",
|
||||
"ISSUE_TITLE": "Pyyntöjen tyypit",
|
||||
"ACTION_ADD": "Lisää uusi tyyppi"
|
||||
"ACTION_ADD": "Lisää uusi {{objName}}"
|
||||
},
|
||||
"ROLES": {
|
||||
"SECTION_NAME": "Roolit - {{projectName}}",
|
||||
"PAGE_TITLE": "Roles - {{projectName}}",
|
||||
"WARNING_NO_ROLE": "Ole varovainen, yksikään rooli projektissasi ei voi arvioida käyttäjätarinoidesi kokoa",
|
||||
"HELP_ROLE_ENABLED": "Tämän roolin omaavat jäsenet voivat arvioida käyttäjätarinoiden kokoja",
|
||||
"COUNT_MEMBERS": "{{ role.members_count }} jäsentä joilla tämä rooli",
|
||||
|
@ -402,20 +504,20 @@
|
|||
},
|
||||
"BITBUCKET": {
|
||||
"SECTION_NAME": "Bitbucket",
|
||||
"APP_TITLE": "Bitbucket - {{projectName}}",
|
||||
"PAGE_TITLE": "Bitbucket - {{projectName}}",
|
||||
"INFO_VERIFYING_IP": "Bitbucket pyynnöt eivät ole allekirjoitettuja joten tarkista IP. Jos IP on tyhjä, ei sitä tarkisteta."
|
||||
},
|
||||
"GITLAB": {
|
||||
"SECTION_NAME": "Gitlab",
|
||||
"APP_TITLE": "Gitlab - {{projectName}}",
|
||||
"PAGE_TITLE": "Gitlab - {{projectName}}",
|
||||
"INFO_VERIFYING_IP": "Gitlab pyynnöt eivät ole allekirjoitettuja joten tarkista IP. Jos IP on tyhjä, ei sitä tarkisteta."
|
||||
},
|
||||
"GITHUB": {
|
||||
"SECTION_NAME": "Github",
|
||||
"APP_TITLE": "Github - {{projectName}}"
|
||||
"PAGE_TITLE": "Github - {{projectName}}"
|
||||
},
|
||||
"WEBHOOKS": {
|
||||
"APP_TITLE": "Webhooks - {{projectName}}",
|
||||
"PAGE_TITLE": "Webhooks - {{projectName}}",
|
||||
"SECTION_NAME": "Webhookit",
|
||||
"SUBTITLE": "Webhookit ilmoittvat ulkoisille palveluille Taigan kommenteista, käyttäjätarinoista ...",
|
||||
"ADD_NEW": "Lisää webhook",
|
||||
|
@ -441,6 +543,7 @@
|
|||
"WEBHOOK_NAME": "Webhook '{{name}}'"
|
||||
},
|
||||
"CUSTOM_ATTRIBUTES": {
|
||||
"PAGE_TITLE": "{{sectionName}} - Custom Attributes - {{projectName}}",
|
||||
"ADD": "Anna oma kenttä",
|
||||
"EDIT": "Muokkaa omaa kenttää",
|
||||
"DELETE": "Poista oma kenttä",
|
||||
|
@ -518,9 +621,36 @@
|
|||
"TITLE": "Palvelut"
|
||||
}
|
||||
},
|
||||
"USER": {
|
||||
"PROFILE": {
|
||||
"PAGE_TITLE": "{{userFullName}} (@{{userUsername}})",
|
||||
"EDIT": "Edit profile",
|
||||
"FOLLOW": "Follow",
|
||||
"PROJECTS": "Projektit",
|
||||
"CLOSED_US": "Closed US",
|
||||
"CONTACTS": "Contacts",
|
||||
"REPORT": "Report Abuse",
|
||||
"ACTIVITY_TAB": "Activity Tab",
|
||||
"PROJECTS_TAB": "Projects Tab",
|
||||
"CONTACTS_TAB": "Contacts Tab",
|
||||
"FAVORITES_TAB": "Favorites Tab",
|
||||
"CONTACTS_EMPTY": "{{username}} doesn't have contacts yet",
|
||||
"CURRENT_USER_CONTACTS_EMPTY": "You don't have contacts yet",
|
||||
"CURRENT_USER_CONTACTS_EMPTY_EXPLAIN": "The people with whom you work at Taiga will be your contacts automatically",
|
||||
"PROJECTS_EMPTY": "{{username}} doesn't' have projects yet"
|
||||
},
|
||||
"PROFILE_SIDEBAR": {
|
||||
"TITLE": "Your profile",
|
||||
"DESCRIPTION": "People can see everything you do and what are you working on. Add a nice bio to give an enhanced version of your information.",
|
||||
"ADD_INFO": "Edit your bio"
|
||||
}
|
||||
},
|
||||
"PROJECT": {
|
||||
"PAGE_TITLE": "{{projectName}}",
|
||||
"WELCOME": "Tervetuloa",
|
||||
"SECTION_PROJECTS": "Projektit",
|
||||
"HELP": "Reorder your projects to set in the top the most used ones.<br/> The top 10 projects will appear in the top navigation bar project list",
|
||||
"PRIVATE": "Yksityinen projekti",
|
||||
"STATS": {
|
||||
"PROJECT": "projekti<br/> pisteet",
|
||||
"DEFINED": "määritely<br/> pistettä",
|
||||
|
@ -529,6 +659,7 @@
|
|||
},
|
||||
"SECTION": {
|
||||
"SEARCH": "Hae",
|
||||
"TIMELINE": "Timeline",
|
||||
"BACKLOG": "Odottavat",
|
||||
"KANBAN": "Kanban",
|
||||
"ISSUES": "Pyynnöt",
|
||||
|
@ -541,9 +672,32 @@
|
|||
"SECTION_TITLE": "Projektisi",
|
||||
"PLACEHOLDER_SEARCH": "Hae täältä...",
|
||||
"ACTION_CREATE_PROJECT": "Luo projekti",
|
||||
"TITLE_ACTION_IMPORT": "Luo projekti tiedostosta",
|
||||
"ACTION_IMPORT_PROJECT": "Import project",
|
||||
"SEE_MORE_PROJECTS": "See more projects",
|
||||
"TITLE_CREATE_PROJECT": "Create project",
|
||||
"TITLE_IMPORT_PROJECT": "Import project",
|
||||
"TITLE_PRVIOUS_PROJECT": "Näytä aikaisemmat projektit",
|
||||
"TITLE_NEXT_PROJECT": "Näytä seuraavat projektit"
|
||||
"TITLE_NEXT_PROJECT": "Näytä seuraavat projektit",
|
||||
"HELP_TITLE": "Taiga Support Page",
|
||||
"HELP": "Help",
|
||||
"FEEDBACK_TITLE": "Lähetä palautetta",
|
||||
"FEEDBACK": "Palaute",
|
||||
"NOTIFICATIONS_TITLE": "Edit your notification settings",
|
||||
"NOTIFICATIONS": "Ilmoitukset",
|
||||
"ORGANIZATIONS_TITLE": "Edit your organizations",
|
||||
"ORGANIZATIONS": "Edit organizations",
|
||||
"SETTINGS_TITLE": "Edit your settings",
|
||||
"SETTINGS": "Settings",
|
||||
"VIEW_PROFILE_TITLE": "View Profile",
|
||||
"VIEW_PROFILE": "View Profile",
|
||||
"EDIT_PROFILE_TITLE": "Edit your profile",
|
||||
"EDIT_PROFILE": "Edit Profile",
|
||||
"CHANGE_PASSWORD_TITLE": "Muuta salasanaa",
|
||||
"CHANGE_PASSWORD": "Muuta salasanaa",
|
||||
"DASHBOARD_TITLE": "Dashboard",
|
||||
"DISCOVER_TITLE": "Discover trending projects",
|
||||
"DISCOVER": "Discover",
|
||||
"ACTION_REORDER": "Drag & drop to reorder"
|
||||
},
|
||||
"IMPORT": {
|
||||
"TITLE": "Luetaan sisään projektia",
|
||||
|
@ -624,6 +778,8 @@
|
|||
}
|
||||
},
|
||||
"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": "Käyttäjätarinan tiedot",
|
||||
"LINK_TASKBOARD": "Tehtävätaulu",
|
||||
"TITLE_LINK_TASKBOARD": "Siirry tehtävätauluun",
|
||||
|
@ -711,6 +867,8 @@
|
|||
}
|
||||
},
|
||||
"BACKLOG": {
|
||||
"PAGE_TITLE": "Backlog - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "The backlog panel, with user stories and sprints of the project {{projectName}}: {{projectDescription}}",
|
||||
"SECTION_NAME": "Odottavat",
|
||||
"MOVE_US_TO_CURRENT_SPRINT": "Siirrä nykyiseen kierrokseen",
|
||||
"SHOW_FILTERS": "Näytä suodattimet",
|
||||
|
@ -790,6 +948,8 @@
|
|||
"VERSION_ERROR": "Joku Taigassa on päivittänyt tätä ennen sinua. Muutoksiasi ei voida tallentaa. Lataa sivu uudestaan ja korjaa tilanne."
|
||||
},
|
||||
"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}}.",
|
||||
"SECTION_NAME": "Tehtävätaulu",
|
||||
"TITLE_ACTION_ADD": "Lisää uusi tehtävä",
|
||||
"TITLE_ACTION_ADD_BULK": "Lisää monta tehtävää",
|
||||
|
@ -813,6 +973,8 @@
|
|||
}
|
||||
},
|
||||
"TASK": {
|
||||
"PAGE_TITLE": "{{taskSubject}} - Task {{taskRef}} - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "Status: {{taskStatus }}. Description: {{taskDescription}}",
|
||||
"SECTION_NAME": "Tehtävän tiedot",
|
||||
"LINK_TASKBOARD": "Tehtävätaulu",
|
||||
"TITLE_LINK_TASKBOARD": "Siirry tehtävätauluun",
|
||||
|
@ -858,56 +1020,9 @@
|
|||
"ACTION_CHANGE_EMAIL": "Muuta sähköpostisi",
|
||||
"SUCCESS": "Oompa Loompas päivittivät sähköpostisi"
|
||||
},
|
||||
"CHANGE_PASSWORD_RECOVERY_FORM": {
|
||||
"TITLE": "Luo uusi pääsy Taigaan",
|
||||
"SUBTITLE": "Rautapitoinen ruoka on hyväksi aivoille :P",
|
||||
"PLACEHOLDER_RECOVER_PASSWORD_TOKEN": "Palauta sähköposti-tokeni",
|
||||
"LINK_NEED_TOKEN": "Tarvitsetko yhden?",
|
||||
"TITLE_LINK_NEED_TOKEN": "Tarvitsitko tokenia palauttaakseni salasanan koska unohdit sen?",
|
||||
"PLACEHOLDER_NEW_PASSWORD": "Uusi salasana",
|
||||
"PLACEHOLDER_RE_TYPE_NEW_PASSWORD": "Anna salasana uudelleen",
|
||||
"ACTION_RESET_PASSWORD": "Uusi salsanasi",
|
||||
"SUCCESS": "Oompa Loompas tallensivat uuden salasanasi.<br /> Yritä <strong>kirjautua sisään</strong> sillä."
|
||||
},
|
||||
"FORGOT_PASSWORD_FORM": {
|
||||
"TITLE": "Oops, unohditko salasanasi?",
|
||||
"SUBTITLE": "Anna käyttäjänimesi tai sähköpostisi saadaksesi uuden",
|
||||
"PLACEHOLDER_FIELD": "Käyttäjänimi tai sähköposti",
|
||||
"ACTION_RESET_PASSWORD": "Uusi salsanasi",
|
||||
"LINK_CANCEL": "Vie minut takaisin, muistan sen.",
|
||||
"SUCCESS": "<strong>Tarkista sähköpostisi!</strong><br />Olemme lähettäneet sinulle sähköpostissa kirjautumisohjeet",
|
||||
"ERROR": "Oompa Loompas sanovat että käyttäjänimesi tai sähköpostisi tai salasanasi on väärä."
|
||||
},
|
||||
"LOGIN_COMMON": {
|
||||
"HEADER": "Minulla on jo Taiga tunnus",
|
||||
"PLACEHOLDER_AUTH_NAME": "Käyttäjänimi tai sähköposti (kirjainkoko merkitsevä)",
|
||||
"LINK_FORGOT_PASSWORD": "Unohditko?",
|
||||
"TITLE_LINK_FORGOT_PASSWORD": "Unohditko salasanasi?",
|
||||
"ACTION_ENTER": "Sisään",
|
||||
"ACTION_SIGN_IN": "Kirjaudu sisään",
|
||||
"PLACEHOLDER_AUTH_PASSWORD": "Salasana (kirjainkoko merkitsevä)"
|
||||
},
|
||||
"LOGIN_FORM": {
|
||||
"ERROR_AUTH_INCORRECT": "Oompa Loompas sanovat että käyttäjänimesi tai sähköpostisi tai salasanasi on väärä.",
|
||||
"ERROR_GENERIC": "Oompa Loompas havaitsivat virheen",
|
||||
"SUCCESS": "Oompa Loompas ovat onnellisia, tervetuloa Taigaan."
|
||||
},
|
||||
"INVITATION_LOGIN_FORM": {
|
||||
"NOT_FOUND": "<strong>Ooops, meillä on ongelma</strong><br />Our Oompa Loompas eivät löydä kutsuasi.",
|
||||
"SUCCESS": "Olet onnistuneesti liittynyt projektiin {{project_name}}. Tervetuloa!",
|
||||
"ERROR": "Oompa Loompas sanovat että käyttäjänimesi tai sähköpostisi tai salasanasi on väärä."
|
||||
},
|
||||
"REGISTER_FORM": {
|
||||
"TITLE": "Rekisteröi uusi Taiga tunnus (ilmainen)",
|
||||
"PLACEHOLDER_NAME": "Anna käyttäjänimi (kirjainkoko on merkitsevä)",
|
||||
"PLACEHOLDER_FULL_NAME": "Anna koko nimesi",
|
||||
"PLACEHOLDER_EMAIL": "Sähköpostisi",
|
||||
"PLACEHOLDER_PASSWORD": "Anna salasana (kirjainkoko merkitsevä)",
|
||||
"ACTION_SIGN_UP": "Kirjaudu sisään",
|
||||
"TITLE_LINK_LOGIN": "Kirjaudu sisään",
|
||||
"LINK_LOGIN": "Oletko jo rekisteröitynyt? Kirjaudu sisään"
|
||||
},
|
||||
"ISSUES": {
|
||||
"PAGE_TITLE": "Issues - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "The issues list panel of the project {{projectName}}: {{projectDescription}}",
|
||||
"LIST_SECTION_NAME": "Pyynnöt",
|
||||
"SECTION_NAME": "Pyynnön tiedot",
|
||||
"ACTION_NEW_ISSUE": "+ UUSI PYYNTÖ",
|
||||
|
@ -921,6 +1036,11 @@
|
|||
"TITLE_NEXT_ISSUE": "seuraava pyyntö",
|
||||
"ACTION_DELETE": "Poista pyyntö",
|
||||
"LIGHTBOX_TITLE_BLOKING_ISSUE": "Estävä pyyntö",
|
||||
"FIELDS": {
|
||||
"PRIORITY": "Tärkeys",
|
||||
"SEVERITY": "Vakavuus",
|
||||
"TYPE": "Tyyppi"
|
||||
},
|
||||
"CONFIRM_PROMOTE": {
|
||||
"TITLE": "Liitä tämä pyyntö uuteen käyttäjätarinaan",
|
||||
"MESSAGE": "Haluatko varmasti lisätä uuden käyttäjätarinan tästä pyynnöstä?"
|
||||
|
@ -966,7 +1086,13 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"ISSUE": {
|
||||
"PAGE_TITLE": "{{issueSubject}} - Issue {{issueRef}} - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "Status: {{issueStatus }}. Type: {{issueType}}, Priority: {{issuePriority}}. Severity: {{issueSeverity}}. Description: {{issueDescription}}"
|
||||
},
|
||||
"KANBAN": {
|
||||
"PAGE_TITLE": "Kanban - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "The kanban panel, with user stories of the project {{projectName}}: {{projectDescription}}",
|
||||
"SECTION_NAME": "Kanban",
|
||||
"TITLE_ACTION_FOLD": "Kavenna sarake",
|
||||
"TITLE_ACTION_UNFOLD": "Laajenna sarake",
|
||||
|
@ -981,6 +1107,8 @@
|
|||
"UNDO_ARCHIVED": "Raahaa ja pudota uudelleen peruaksesi"
|
||||
},
|
||||
"SEARCH": {
|
||||
"PAGE_TITLE": "Search - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "Search anything, user stories, issues, tasks or wiki pages, in the project {{projectName}}: {{projectDescription}}",
|
||||
"FILTER_USER_STORIES": "Käyttäjätarinat",
|
||||
"FILTER_ISSUES": "Pyynnöt",
|
||||
"FILTER_TASKS": "Tehtävät",
|
||||
|
@ -991,6 +1119,8 @@
|
|||
"EMPTY_DESCRIPTION": "Kokeile ylempiä välilehtiä ja hae uudestaan"
|
||||
},
|
||||
"TEAM": {
|
||||
"PAGE_TITLE": "Team - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "The team panel to show all the members of the project {{projectName}}: {{projectDescription}}",
|
||||
"SECTION_NAME": "Tiimi",
|
||||
"APP_TITLE": "TIIMI - {{projectName}}",
|
||||
"PLACEHOLDER_INPUT_SEARCH": "Etsi koko nimellä...",
|
||||
|
@ -1011,16 +1141,6 @@
|
|||
"CONFIRM_LEAVE_PROJECT": "Oletko varma että haluat poistua projektista?",
|
||||
"ACTION_LEAVE_PROJECT": "Poistu projektista"
|
||||
},
|
||||
"CHANGE_PASSWORD": {
|
||||
"SECTION_NAME": "Muuta salasanaa",
|
||||
"FIELD_CURRENT_PASSWORD": "Nykyinen salasana",
|
||||
"PLACEHOLDER_CURRENT_PASSWORD": "Nykyinen salasanasi (tai on tyhjä jos sinulla ei vielä ole)",
|
||||
"FIELD_NEW_PASSWORD": "Uusi salasana",
|
||||
"PLACEHOLDER_NEW_PASSWORD": "Anna uusi salasana",
|
||||
"FIELD_RETYPE_PASSWORD": "Anna salasana uudelleen",
|
||||
"PLACEHOLDER_RETYPE_PASSWORD": "Anna salasana uudelleen",
|
||||
"ERROR_PASSWORD_MATCH": "Salasanat eivät täsmää"
|
||||
},
|
||||
"USER_SETTINGS": {
|
||||
"AVATAR_MAX_SIZE": "Maksimi koko {{maxFileSize}}",
|
||||
"MENU": {
|
||||
|
@ -1059,7 +1179,7 @@
|
|||
"EMAIL": "Sähköposti",
|
||||
"FULL_NAME": "Koko nimi",
|
||||
"PLACEHOLDER_FULL_NAME": "Anna koko nimesi",
|
||||
"BIO": "Bio",
|
||||
"BIO": "Bio (max. 210 chars)",
|
||||
"PLACEHOLDER_BIO": "Kerro jotain itsestäsi",
|
||||
"LANGUAGE": "Kieli",
|
||||
"LANGUAGE_DEFAULT": "-- käytä oletuskieltä --"
|
||||
|
@ -1074,6 +1194,8 @@
|
|||
"PROGRESS_NAME_DESCRIPTION": "Nimi ja kuvaus"
|
||||
},
|
||||
"WIKI": {
|
||||
"PAGE_TITLE": "{{wikiPageName}} - Wiki - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "Last edition on {{lastModifiedDate}} ({{totalEditions}} editions in total) Content: {{ wikiPageContent }}",
|
||||
"DATETIME": "DD.MM.YY - HH:mm",
|
||||
"PLACEHOLDER_PAGE": "Kirjoita wiki-sivu",
|
||||
"REMOVE": "Poista tämä wiki-sivu",
|
||||
|
@ -1087,5 +1209,43 @@
|
|||
"LAST_EDIT": "viimeinen<br/>muokkaus",
|
||||
"LAST_MODIFICATION": "viimeinen muokkaus"
|
||||
}
|
||||
},
|
||||
"HINTS": {
|
||||
"SECTION_NAME": "Hint",
|
||||
"LINK": "If you want to know how to use it visit our support page",
|
||||
"LINK_TITLE": "Visit our support page",
|
||||
"HINT1_TITLE": "Did you know you can import and export projects?",
|
||||
"HINT1_TEXT": "This allow you to extract all your data from one Taiga and move it to another one.",
|
||||
"HINT2_TITLE": "Did you know you can create custom fields?",
|
||||
"HINT2_TEXT": "Teams can now create custom fields as a flexible means to enter specific data useful for their particular workflow",
|
||||
"HINT3_TITLE": "Reorder your projects to feature those most relevant to you",
|
||||
"HINT3_TEXT": "The top 10 project will be in your top bar direct access",
|
||||
"HINT4_TITLE": "Did you forgot what were you working on?",
|
||||
"HINT4_TEXT": "Don't worry, on your dashboard you'll find your open tasks, issues, and user stories in the order you worked on them."
|
||||
},
|
||||
"TIMELINE": {
|
||||
"UPLOAD_ATTACHMENT": "{{username}} has uploaded a new attachment in {{obj_name}}",
|
||||
"US_CREATED": "{{username}} has created a new US {{obj_name}} in {{project_name}}",
|
||||
"ISSUE_CREATED": "{{username}} has created a new issue {{obj_name}} in {{project_name}}",
|
||||
"TASK_CREATED": "{{username}} has created a new task {{obj_name}} in {{project_name}}",
|
||||
"TASK_CREATED_WITH_US": "{{username}} has created a new task {{obj_name}} in {{project_name}} which belongs to the US {{us_name}}",
|
||||
"WIKI_CREATED": "{{username}} has created a new wiki page {{obj_name}} in {{project_name}}",
|
||||
"MILESTONE_CREATED": "{{username}} has created a new sprint {{obj_name}} in {{project_name}}",
|
||||
"NEW_PROJECT": "{{username}} created the project {{project_name}}",
|
||||
"MILESTONE_UPDATED": "{{username}} has updated the sprint {{obj_name}}",
|
||||
"US_UPDATED": "{{username}} has updated the attribute \"{{field_name}}\" of the US {{obj_name}}",
|
||||
"ISSUE_UPDATED": "{{username}} has updated the attribute \"{{field_name}}\" of the issue {{obj_name}}",
|
||||
"TASK_UPDATED": "{{username}} has updated the attribute \"{{field_name}}\" of the task {{obj_name}}",
|
||||
"TASK_UPDATED_WITH_US": "{{username}} has updated the attribute \"{{field_name}}\" of the task {{obj_name}} which belongs to the US {{us_name}}",
|
||||
"WIKI_UPDATED": "{{username}} has updated the wiki page {{obj_name}}",
|
||||
"NEW_COMMENT_US": "{{username}} has commented in the US {{obj_name}}",
|
||||
"NEW_COMMENT_ISSUE": "{{username}} has commented in the issue {{obj_name}}",
|
||||
"NEW_COMMENT_TASK": "{{username}} has commented in the task {{obj_name}}",
|
||||
"NEW_MEMBER": "{{project_name}} has a new member",
|
||||
"US_ADDED_MILESTONE": "{{username}} has added the US {{obj_name}} to {{sprint_name}}",
|
||||
"US_REMOVED_FROM_MILESTONE": "{{username}} has added the US {{obj_name}} to the backlog",
|
||||
"BLOCKED": "{{username}} has blocked {{obj_name}}",
|
||||
"UNBLOCKED": "{{username}} has unblocked {{obj_name}}",
|
||||
"NEW_USER": "{{username}} has joined Taiga"
|
||||
}
|
||||
}
|
|
@ -100,6 +100,10 @@
|
|||
"SAT": "週六"
|
||||
}
|
||||
},
|
||||
"SEE_USER_PROFILE": "See {{username }} profile",
|
||||
"USER_STORY": "使用者故事",
|
||||
"TASK": "Task",
|
||||
"ISSUE": "Issue",
|
||||
"TAGS": {
|
||||
"PLACEHOLDER": "我在這裏,請標注我",
|
||||
"DELETE": "刪除Tag",
|
||||
|
@ -125,7 +129,8 @@
|
|||
"ASSIGNED_TO": "指派給 ",
|
||||
"POINTS": "點數",
|
||||
"BLOCKED_NOTE": "已封鎖之筆記",
|
||||
"IS_BLOCKED": "封鎖"
|
||||
"IS_BLOCKED": "封鎖",
|
||||
"REF": "Ref"
|
||||
},
|
||||
"ROLES": {
|
||||
"ALL": "所有"
|
||||
|
@ -231,14 +236,107 @@
|
|||
"ADD_WIKI_LINKS": "新增維基連結",
|
||||
"DELETE_WIKI_LINKS": "刪除維基連結"
|
||||
}
|
||||
},
|
||||
"META": {
|
||||
"PAGE_TITLE": "Taiga",
|
||||
"PAGE_DESCRIPTION": "Taiga is a project management platform for startups and agile developers & designers who want a simple, beautiful tool that makes work truly enjoyable."
|
||||
}
|
||||
},
|
||||
"LOGIN": {
|
||||
"PAGE_TITLE": "Login - Taiga",
|
||||
"PAGE_DESCRIPTION": "Logging in to Taiga, a project management platform for startups and agile developers & designers who want a simple, beautiful tool that makes work truly enjoyable."
|
||||
},
|
||||
"AUTH": {
|
||||
"INVITED_YOU": "已邀請您加入此專案",
|
||||
"NOT_REGISTERED_YET": "還沒註冊嗎?",
|
||||
"REGISTER": "註冊",
|
||||
"CREATE_ACCOUNT": "在此建立您的免費帳號"
|
||||
},
|
||||
"LOGIN_COMMON": {
|
||||
"HEADER": "我已登入Taiga",
|
||||
"PLACEHOLDER_AUTH_NAME": "使用者名稱或電子郵件(注意大小寫)",
|
||||
"LINK_FORGOT_PASSWORD": "忘記了?",
|
||||
"TITLE_LINK_FORGOT_PASSWORD": "你忘了密碼嗎",
|
||||
"ACTION_ENTER": "Enter",
|
||||
"ACTION_SIGN_IN": "登入",
|
||||
"PLACEHOLDER_AUTH_PASSWORD": "密碼(大小寫有別)"
|
||||
},
|
||||
"LOGIN_FORM": {
|
||||
"ERROR_AUTH_INCORRECT": "按我們的箹統記錄,你的帳戶名稱/電子郵件或密碼並不正確 ",
|
||||
"SUCCESS": "我們系統歡迎你加入Taiga"
|
||||
},
|
||||
"REGISTER": {
|
||||
"PAGE_TITLE": "Register - Taiga",
|
||||
"PAGE_DESCRIPTION": "Create your account in Taiga, a project management platform for startups and agile developers & designers who want a simple, beautiful tool that makes work truly enjoyable."
|
||||
},
|
||||
"REGISTER_FORM": {
|
||||
"TITLE": "註冊一個新的Taiga帳戶(免費 )",
|
||||
"PLACEHOLDER_NAME": "選一個用戶帳號(注意大小寫)",
|
||||
"PLACEHOLDER_FULL_NAME": "選取你的全名",
|
||||
"PLACEHOLDER_EMAIL": "你的電子郵件",
|
||||
"PLACEHOLDER_PASSWORD": "設定密碼(注意大小寫不同) ",
|
||||
"ACTION_SIGN_UP": "註冊",
|
||||
"TITLE_LINK_LOGIN": "登入",
|
||||
"LINK_LOGIN": "你是否已註冊? 登入"
|
||||
},
|
||||
"FORGOT_PASSWORD": {
|
||||
"PAGE_TITLE": "Forgot password - Taiga",
|
||||
"PAGE_DESCRIPTION": "Enter your username or email to get a new password and you can access to Taiga again."
|
||||
},
|
||||
"FORGOT_PASSWORD_FORM": {
|
||||
"TITLE": "你是否忘了密碼嗎",
|
||||
"SUBTITLE": "輸入你的帳戶名稱或電子郵件以進行註冊",
|
||||
"PLACEHOLDER_FIELD": "使用者名稱或電子郵件",
|
||||
"ACTION_RESET_PASSWORD": "重設密碼 ",
|
||||
"LINK_CANCEL": "不,請帶我回去,我記起來了",
|
||||
"SUCCESS": "<strong>檢查你的收信箱</strong><br />我們送出了一封信<br />裏面有設定你新電子郵件的相關指示",
|
||||
"ERROR": "按我們的記錄,你尚未註冊"
|
||||
},
|
||||
"CHANGE_PASSWORD": {
|
||||
"PAGE_TITLE": "Change you password - Taiga",
|
||||
"PAGE_DESCRIPTION": "Set a new passoword for your Taiga account and hey!, you may want to eat some more iron-rich food, it's good for your brain :P",
|
||||
"SECTION_NAME": "改變密碼 ",
|
||||
"FIELD_CURRENT_PASSWORD": "現用密碼 ",
|
||||
"PLACEHOLDER_CURRENT_PASSWORD": "你目前的密碼(如果你未有密碼,此處請空白)",
|
||||
"FIELD_NEW_PASSWORD": "新密碼 ",
|
||||
"PLACEHOLDER_NEW_PASSWORD": "輸入新密碼",
|
||||
"FIELD_RETYPE_PASSWORD": "重新輸入新密碼",
|
||||
"PLACEHOLDER_RETYPE_PASSWORD": "重新輸入新密碼",
|
||||
"ERROR_PASSWORD_MATCH": "密碼不符"
|
||||
},
|
||||
"CHANGE_PASSWORD_RECOVERY_FORM": {
|
||||
"TITLE": "創建新Taiga通過",
|
||||
"SUBTITLE": "你也許該吃點鐵質豐富的食物,它對你的大腦有益處:p",
|
||||
"PLACEHOLDER_RECOVER_PASSWORD_TOKEN": "回復密碼代碼 ",
|
||||
"LINK_NEED_TOKEN": "需要一個?",
|
||||
"TITLE_LINK_NEED_TOKEN": "你是否需要代碼來恢復你所忘記的密碼?",
|
||||
"PLACEHOLDER_NEW_PASSWORD": "新密碼 ",
|
||||
"PLACEHOLDER_RE_TYPE_NEW_PASSWORD": "重新輸入新密碼",
|
||||
"ACTION_RESET_PASSWORD": "重設密碼 ",
|
||||
"SUCCESS": "系統已儲存你的新密碼<br />試試 <strong>用它登入</strong> "
|
||||
},
|
||||
"INVITATION": {
|
||||
"PAGE_TITLE": "Invitation acceptance - Taiga",
|
||||
"PAGE_DESCRIPTION": "Accept the invitation to join a project in Taiga, a project management platform for startups and agile developers & designers who want a simple, beautiful tool that makes work truly enjoyable."
|
||||
},
|
||||
"INVITATION_LOGIN_FORM": {
|
||||
"NOT_FOUND": "<strong>Ooops, 有點問題</strong><br />我們的系統無法找到你的邀請信",
|
||||
"SUCCESS": "你成功地加入此專案,歡迎來到 {{project_name}}",
|
||||
"ERROR": "按我們的記錄,你尚未註冊或是未輸入有效的密碼 "
|
||||
},
|
||||
"HOME": {
|
||||
"PAGE_TITLE": "Home - Taiga",
|
||||
"PAGE_DESCRIPTION": "The Taiga home page with your main projects and all your assigned and watched user stories, tasks and issues",
|
||||
"EMPTY_WATCHING": "<strong>Follow</strong> the projects, User Stories, Tasks, Issues... that you want to know about :)",
|
||||
"EMPTY_PROJECT_LIST": "You don't have any projects yet",
|
||||
"WORKING_ON_SECTION": "Working on",
|
||||
"WATCHING_SECTION": "Watching"
|
||||
},
|
||||
"PROJECTS": {
|
||||
"PAGE_TITLE": "My projects - Taiga",
|
||||
"PAGE_DESCRIPTION": "A list with all your projects, you can reorder or create a new one.",
|
||||
"MY_PROJECTS": "My projects"
|
||||
},
|
||||
"ATTACHMENT": {
|
||||
"SECTION_NAME": "附件",
|
||||
"TITLE": "{{ fileName }} 上傳於 {{ date }}",
|
||||
|
@ -276,6 +374,7 @@
|
|||
},
|
||||
"MEMBERSHIPS": {
|
||||
"TITLE": "管理成員",
|
||||
"PAGE_TITLE": "Memberships - {{projectName}}",
|
||||
"ADD_BUTTON": "+ 新成員",
|
||||
"ADD_BUTTON_TITLE": "增加新成員"
|
||||
},
|
||||
|
@ -311,7 +410,7 @@
|
|||
"SALT_CHAT_ROOM": "你可以把聊天室名稱加上salt code亂數密碼 "
|
||||
},
|
||||
"PROJECT_PROFILE": {
|
||||
"PAGE_TITLE": "專案檔案 - {{sectionName}} - {{projectName}}",
|
||||
"PAGE_TITLE": "{{sectionName}} - 專案檔案 - {{projectName}}",
|
||||
"PROJECT_DETAILS": "專案細節",
|
||||
"PROJECT_NAME": "專案名稱",
|
||||
"PROJECT_SLUG": "專案代稱",
|
||||
|
@ -352,23 +451,26 @@
|
|||
"ISSUE_ADD": "在問題中加入客制欄位"
|
||||
},
|
||||
"PROJECT_VALUES": {
|
||||
"APP_TITLE": "專案數值- {{sectionName}} - {{projectName}}",
|
||||
"PAGE_TITLE": "{{sectionName}} - Project values - {{projectName}}",
|
||||
"REPLACEMENT": "所有此數值物品將改成",
|
||||
"ERROR_DELETE_ALL": "你不能刪除所有數值"
|
||||
},
|
||||
"PROJECT_VALUES_POINTS": {
|
||||
"TITLE": "使用者故事點數",
|
||||
"TITLE": "點數",
|
||||
"SUBTITLE": "指定你的使用者故事點數可能預估為",
|
||||
"US_TITLE": "US points",
|
||||
"ACTION_ADD": "增加點數"
|
||||
},
|
||||
"PROJECT_VALUES_PRIORITIES": {
|
||||
"TITLE": "問題優先性",
|
||||
"TITLE": "優先性",
|
||||
"SUBTITLE": "指明你將遇到的問題優先程度",
|
||||
"ISSUE_TITLE": "問題優先性",
|
||||
"ACTION_ADD": "新增優先性"
|
||||
},
|
||||
"PROJECT_VALUES_SEVERITIES": {
|
||||
"TITLE": "問題急迫性",
|
||||
"TITLE": "急迫性",
|
||||
"SUBTITLE": "指明你將遇到問題的嚴重程度",
|
||||
"ISSUE_TITLE": "問題急迫性",
|
||||
"ACTION_ADD": "新增急迫性"
|
||||
},
|
||||
"PROJECT_VALUES_STATUS": {
|
||||
|
@ -382,10 +484,10 @@
|
|||
"TITLE": "類型",
|
||||
"SUBTITLE": "指定你的問題類型可能是",
|
||||
"ISSUE_TITLE": "問題類型",
|
||||
"ACTION_ADD": "新增類別"
|
||||
"ACTION_ADD": "新增{{objName}}"
|
||||
},
|
||||
"ROLES": {
|
||||
"SECTION_NAME": "角色- {{projectName}}",
|
||||
"PAGE_TITLE": "角色- {{projectName}}",
|
||||
"WARNING_NO_ROLE": "注意,你的專案中無角色可以評估使用者故事的點數",
|
||||
"HELP_ROLE_ENABLED": "當啟動時,被指派此角色的成員將可以評估使用者故事點數",
|
||||
"COUNT_MEMBERS": "{{ role.members_count }} 這類角色的成員",
|
||||
|
@ -402,20 +504,20 @@
|
|||
},
|
||||
"BITBUCKET": {
|
||||
"SECTION_NAME": "Bitbucket",
|
||||
"APP_TITLE": "Bitbucket - {{projectName}}",
|
||||
"PAGE_TITLE": "Bitbucket - {{projectName}}",
|
||||
"INFO_VERIFYING_IP": "Bitbucket要求不指派因此最佳確認方式為IP位置來源。如果此處空白,表示IP未有效確核。"
|
||||
},
|
||||
"GITLAB": {
|
||||
"SECTION_NAME": "Gitlob",
|
||||
"APP_TITLE": "Gitlab - {{projectName}}",
|
||||
"PAGE_TITLE": "Gitlab - {{projectName}}",
|
||||
"INFO_VERIFYING_IP": "GitHub要求不指派因此最佳確認方式為IP位置來源。如果此處空白,表示IP未有效確核。"
|
||||
},
|
||||
"GITHUB": {
|
||||
"SECTION_NAME": "Githun",
|
||||
"APP_TITLE": "Gitlab - {{projectName}}"
|
||||
"PAGE_TITLE": "Gitlab - {{projectName}}"
|
||||
},
|
||||
"WEBHOOKS": {
|
||||
"APP_TITLE": "Webhooks- {{projectName}}",
|
||||
"PAGE_TITLE": "Webhooks- {{projectName}}",
|
||||
"SECTION_NAME": "網頁觸發 ",
|
||||
"SUBTITLE": "網頁觸發通知關於Taiga事件的外部服務,例如評論,使用者故事等。 ",
|
||||
"ADD_NEW": "新增一個網頁觸發 ",
|
||||
|
@ -441,6 +543,7 @@
|
|||
"WEBHOOK_NAME": "網頁觸發 '{{name}}'"
|
||||
},
|
||||
"CUSTOM_ATTRIBUTES": {
|
||||
"PAGE_TITLE": "{{sectionName}} - Custom Attributes - {{projectName}}",
|
||||
"ADD": "加入客製化欄位",
|
||||
"EDIT": "編輯客製化欄位",
|
||||
"DELETE": "刪除客製欄位",
|
||||
|
@ -518,9 +621,36 @@
|
|||
"TITLE": "服務 "
|
||||
}
|
||||
},
|
||||
"USER": {
|
||||
"PROFILE": {
|
||||
"PAGE_TITLE": "{{userFullName}} (@{{userUsername}})",
|
||||
"EDIT": "Edit profile",
|
||||
"FOLLOW": "Follow",
|
||||
"PROJECTS": "專案",
|
||||
"CLOSED_US": "Closed US",
|
||||
"CONTACTS": "Contacts",
|
||||
"REPORT": "Report Abuse",
|
||||
"ACTIVITY_TAB": "Activity Tab",
|
||||
"PROJECTS_TAB": "Projects Tab",
|
||||
"CONTACTS_TAB": "Contacts Tab",
|
||||
"FAVORITES_TAB": "Favorites Tab",
|
||||
"CONTACTS_EMPTY": "{{username}} doesn't have contacts yet",
|
||||
"CURRENT_USER_CONTACTS_EMPTY": "You don't have contacts yet",
|
||||
"CURRENT_USER_CONTACTS_EMPTY_EXPLAIN": "The people with whom you work at Taiga will be your contacts automatically",
|
||||
"PROJECTS_EMPTY": "{{username}} doesn't' have projects yet"
|
||||
},
|
||||
"PROFILE_SIDEBAR": {
|
||||
"TITLE": "Your profile",
|
||||
"DESCRIPTION": "People can see everything you do and what are you working on. Add a nice bio to give an enhanced version of your information.",
|
||||
"ADD_INFO": "Edit your bio"
|
||||
}
|
||||
},
|
||||
"PROJECT": {
|
||||
"PAGE_TITLE": "{{projectName}}",
|
||||
"WELCOME": "歡迎",
|
||||
"SECTION_PROJECTS": "專案",
|
||||
"HELP": "Reorder your projects to set in the top the most used ones.<br/> The top 10 projects will appear in the top navigation bar project list",
|
||||
"PRIVATE": "不公開專案",
|
||||
"STATS": {
|
||||
"PROJECT": "專案<br/> 點數",
|
||||
"DEFINED": "已定義<br/> 點數",
|
||||
|
@ -529,6 +659,7 @@
|
|||
},
|
||||
"SECTION": {
|
||||
"SEARCH": "搜尋",
|
||||
"TIMELINE": "Timeline",
|
||||
"BACKLOG": "待辦任務優先表",
|
||||
"KANBAN": "Kanban(看板)",
|
||||
"ISSUES": "問題 ",
|
||||
|
@ -541,9 +672,32 @@
|
|||
"SECTION_TITLE": "你的專案",
|
||||
"PLACEHOLDER_SEARCH": "搜尋",
|
||||
"ACTION_CREATE_PROJECT": "創建專案",
|
||||
"TITLE_ACTION_IMPORT": "滙入專案",
|
||||
"ACTION_IMPORT_PROJECT": "滙入專案",
|
||||
"SEE_MORE_PROJECTS": "See more projects",
|
||||
"TITLE_CREATE_PROJECT": "創建專案",
|
||||
"TITLE_IMPORT_PROJECT": "滙入專案",
|
||||
"TITLE_PRVIOUS_PROJECT": "顯示過去專案",
|
||||
"TITLE_NEXT_PROJECT": "顯示下一個任務"
|
||||
"TITLE_NEXT_PROJECT": "顯示下一個任務",
|
||||
"HELP_TITLE": "Taiga Support Page",
|
||||
"HELP": "Help",
|
||||
"FEEDBACK_TITLE": "送出回饋 ",
|
||||
"FEEDBACK": "回饋 ",
|
||||
"NOTIFICATIONS_TITLE": "Edit your notification settings",
|
||||
"NOTIFICATIONS": "通知",
|
||||
"ORGANIZATIONS_TITLE": "Edit your organizations",
|
||||
"ORGANIZATIONS": "Edit organizations",
|
||||
"SETTINGS_TITLE": "Edit your settings",
|
||||
"SETTINGS": "Settings",
|
||||
"VIEW_PROFILE_TITLE": "View Profile",
|
||||
"VIEW_PROFILE": "View Profile",
|
||||
"EDIT_PROFILE_TITLE": "Edit your profile",
|
||||
"EDIT_PROFILE": "Edit Profile",
|
||||
"CHANGE_PASSWORD_TITLE": "更換密碼 ",
|
||||
"CHANGE_PASSWORD": "更換密碼 ",
|
||||
"DASHBOARD_TITLE": "Dashboard",
|
||||
"DISCOVER_TITLE": "Discover trending projects",
|
||||
"DISCOVER": "Discover",
|
||||
"ACTION_REORDER": "Drag & drop to reorder"
|
||||
},
|
||||
"IMPORT": {
|
||||
"TITLE": "滙入專案中",
|
||||
|
@ -624,6 +778,8 @@
|
|||
}
|
||||
},
|
||||
"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": "使用者故事細節",
|
||||
"LINK_TASKBOARD": "任務板",
|
||||
"TITLE_LINK_TASKBOARD": "到任務板去",
|
||||
|
@ -711,6 +867,8 @@
|
|||
}
|
||||
},
|
||||
"BACKLOG": {
|
||||
"PAGE_TITLE": "Backlog - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "The backlog panel, with user stories and sprints of the project {{projectName}}: {{projectDescription}}",
|
||||
"SECTION_NAME": "待辦任務優先表",
|
||||
"MOVE_US_TO_CURRENT_SPRINT": "移到目前的 Sprint",
|
||||
"SHOW_FILTERS": "顯示過濾器",
|
||||
|
@ -790,6 +948,8 @@
|
|||
"VERSION_ERROR": "Taiga某人之前更改了這個,而我們的工程師無法再做改變。請重新載入頁面來使用你的更新(之前設定將消失)"
|
||||
},
|
||||
"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}}.",
|
||||
"SECTION_NAME": "任務板",
|
||||
"TITLE_ACTION_ADD": "增加新任務 ",
|
||||
"TITLE_ACTION_ADD_BULK": "批次加入新任務 ",
|
||||
|
@ -813,6 +973,8 @@
|
|||
}
|
||||
},
|
||||
"TASK": {
|
||||
"PAGE_TITLE": "{{taskSubject}} - Task {{taskRef}} - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "Status: {{taskStatus }}. Description: {{taskDescription}}",
|
||||
"SECTION_NAME": "任務細節",
|
||||
"LINK_TASKBOARD": "任務板",
|
||||
"TITLE_LINK_TASKBOARD": "到任務板去",
|
||||
|
@ -858,56 +1020,9 @@
|
|||
"ACTION_CHANGE_EMAIL": "變更電郵地址",
|
||||
"SUCCESS": "我們系統已更新你的電子郵件"
|
||||
},
|
||||
"CHANGE_PASSWORD_RECOVERY_FORM": {
|
||||
"TITLE": "創建新Taiga通過",
|
||||
"SUBTITLE": "你也許該吃點鐵質豐富的食物,它對你的大腦有益處:p",
|
||||
"PLACEHOLDER_RECOVER_PASSWORD_TOKEN": "回復密碼代碼 ",
|
||||
"LINK_NEED_TOKEN": "需要一個?",
|
||||
"TITLE_LINK_NEED_TOKEN": "你是否需要代碼來恢復你所忘記的密碼?",
|
||||
"PLACEHOLDER_NEW_PASSWORD": "新密碼 ",
|
||||
"PLACEHOLDER_RE_TYPE_NEW_PASSWORD": "重新輸入新密碼",
|
||||
"ACTION_RESET_PASSWORD": "重設密碼 ",
|
||||
"SUCCESS": "系統已儲存你的新密碼<br />試試 <strong>用它登入</strong> "
|
||||
},
|
||||
"FORGOT_PASSWORD_FORM": {
|
||||
"TITLE": "你是否忘了密碼嗎",
|
||||
"SUBTITLE": "輸入你的帳戶名稱或電子郵件以進行註冊",
|
||||
"PLACEHOLDER_FIELD": "使用者名稱或電子郵件",
|
||||
"ACTION_RESET_PASSWORD": "重設密碼 ",
|
||||
"LINK_CANCEL": "不,請帶我回去,我記起來了",
|
||||
"SUCCESS": "<strong>檢查你的收信箱</strong><br />我們送出了一封信<br />裏面有設定你新電子郵件的相關指示",
|
||||
"ERROR": "按我們的記錄,你尚未註冊"
|
||||
},
|
||||
"LOGIN_COMMON": {
|
||||
"HEADER": "我已登入Taiga",
|
||||
"PLACEHOLDER_AUTH_NAME": "使用者名稱或電子郵件(注意大小寫)",
|
||||
"LINK_FORGOT_PASSWORD": "忘記了?",
|
||||
"TITLE_LINK_FORGOT_PASSWORD": "你忘了密碼嗎",
|
||||
"ACTION_ENTER": "Enter",
|
||||
"ACTION_SIGN_IN": "登入",
|
||||
"PLACEHOLDER_AUTH_PASSWORD": "密碼(大小寫有別)"
|
||||
},
|
||||
"LOGIN_FORM": {
|
||||
"ERROR_AUTH_INCORRECT": "按我們的箹統記錄,你的帳戶名稱/電子郵件或密碼並不正確 ",
|
||||
"ERROR_GENERIC": "根據系統,此處有錯誤",
|
||||
"SUCCESS": "我們系統歡迎你加入Taiga"
|
||||
},
|
||||
"INVITATION_LOGIN_FORM": {
|
||||
"NOT_FOUND": "<strong>Ooops, 有點問題</strong><br />我們的系統無法找到你的邀請信",
|
||||
"SUCCESS": "你成功地加入此專案,歡迎來到 {{project_name}}",
|
||||
"ERROR": "按我們的記錄,你尚未註冊或是未輸入有效的密碼 "
|
||||
},
|
||||
"REGISTER_FORM": {
|
||||
"TITLE": "註冊一個新的Taiga帳戶(免費 )",
|
||||
"PLACEHOLDER_NAME": "選一個用戶帳號(注意大小寫)",
|
||||
"PLACEHOLDER_FULL_NAME": "選取你的全名",
|
||||
"PLACEHOLDER_EMAIL": "你的電子郵件",
|
||||
"PLACEHOLDER_PASSWORD": "設定密碼(注意大小寫不同) ",
|
||||
"ACTION_SIGN_UP": "註冊",
|
||||
"TITLE_LINK_LOGIN": "登入",
|
||||
"LINK_LOGIN": "你是否已註冊? 登入"
|
||||
},
|
||||
"ISSUES": {
|
||||
"PAGE_TITLE": "Issues - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "The issues list panel of the project {{projectName}}: {{projectDescription}}",
|
||||
"LIST_SECTION_NAME": "問題 ",
|
||||
"SECTION_NAME": "問題細節",
|
||||
"ACTION_NEW_ISSUE": "+ 新問題 ",
|
||||
|
@ -921,6 +1036,11 @@
|
|||
"TITLE_NEXT_ISSUE": "下一個問題 ",
|
||||
"ACTION_DELETE": "删除議題 ",
|
||||
"LIGHTBOX_TITLE_BLOKING_ISSUE": "封鎖中的問題",
|
||||
"FIELDS": {
|
||||
"PRIORITY": "優先性",
|
||||
"SEVERITY": "急迫性",
|
||||
"TYPE": "類型"
|
||||
},
|
||||
"CONFIRM_PROMOTE": {
|
||||
"TITLE": "將此問題提到使用者故事",
|
||||
"MESSAGE": "你確定此問題要創建一個新的使用者故事?"
|
||||
|
@ -966,7 +1086,13 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"ISSUE": {
|
||||
"PAGE_TITLE": "{{issueSubject}} - Issue {{issueRef}} - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "Status: {{issueStatus }}. Type: {{issueType}}, Priority: {{issuePriority}}. Severity: {{issueSeverity}}. Description: {{issueDescription}}"
|
||||
},
|
||||
"KANBAN": {
|
||||
"PAGE_TITLE": "Kanban - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "The kanban panel, with user stories of the project {{projectName}}: {{projectDescription}}",
|
||||
"SECTION_NAME": "Kanban(看板)",
|
||||
"TITLE_ACTION_FOLD": "隱藏欄位",
|
||||
"TITLE_ACTION_UNFOLD": "未隱藏欄位",
|
||||
|
@ -981,6 +1107,8 @@
|
|||
"UNDO_ARCHIVED": "拖移 & 丟到未做"
|
||||
},
|
||||
"SEARCH": {
|
||||
"PAGE_TITLE": "Search - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "Search anything, user stories, issues, tasks or wiki pages, in the project {{projectName}}: {{projectDescription}}",
|
||||
"FILTER_USER_STORIES": "使用者故事",
|
||||
"FILTER_ISSUES": "問題 ",
|
||||
"FILTER_TASKS": "任務 ",
|
||||
|
@ -991,6 +1119,8 @@
|
|||
"EMPTY_DESCRIPTION": "請試試上方某一個分頁或再搜尋一次"
|
||||
},
|
||||
"TEAM": {
|
||||
"PAGE_TITLE": "Team - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "The team panel to show all the members of the project {{projectName}}: {{projectDescription}}",
|
||||
"SECTION_NAME": "團隊",
|
||||
"APP_TITLE": "團隊- {{projectName}}",
|
||||
"PLACEHOLDER_INPUT_SEARCH": "以全名搜尋",
|
||||
|
@ -1011,16 +1141,6 @@
|
|||
"CONFIRM_LEAVE_PROJECT": "你確定要退出這個專案嗎?",
|
||||
"ACTION_LEAVE_PROJECT": "退出此專案"
|
||||
},
|
||||
"CHANGE_PASSWORD": {
|
||||
"SECTION_NAME": "改變密碼 ",
|
||||
"FIELD_CURRENT_PASSWORD": "現用密碼 ",
|
||||
"PLACEHOLDER_CURRENT_PASSWORD": "你目前的密碼(如果你未有密碼,此處請空白)",
|
||||
"FIELD_NEW_PASSWORD": "新密碼 ",
|
||||
"PLACEHOLDER_NEW_PASSWORD": "輸入新密碼",
|
||||
"FIELD_RETYPE_PASSWORD": "重新輸入新密碼",
|
||||
"PLACEHOLDER_RETYPE_PASSWORD": "重新輸入新密碼",
|
||||
"ERROR_PASSWORD_MATCH": "密碼不符"
|
||||
},
|
||||
"USER_SETTINGS": {
|
||||
"AVATAR_MAX_SIZE": "[最大. 尺寸: {{maxFileSize}}] ",
|
||||
"MENU": {
|
||||
|
@ -1059,7 +1179,7 @@
|
|||
"EMAIL": "電子郵件",
|
||||
"FULL_NAME": "全名",
|
||||
"PLACEHOLDER_FULL_NAME": "你的全名",
|
||||
"BIO": "簡介",
|
||||
"BIO": "Bio (max. 210 chars)",
|
||||
"PLACEHOLDER_BIO": "請自我介紹",
|
||||
"LANGUAGE": "語言",
|
||||
"LANGUAGE_DEFAULT": "-- 使用設預語言 -- "
|
||||
|
@ -1074,6 +1194,8 @@
|
|||
"PROGRESS_NAME_DESCRIPTION": "名稱與描述"
|
||||
},
|
||||
"WIKI": {
|
||||
"PAGE_TITLE": "{{wikiPageName}} - Wiki - {{projectName}}",
|
||||
"PAGE_DESCRIPTION": "Last edition on {{lastModifiedDate}} ({{totalEditions}} editions in total) Content: {{ wikiPageContent }}",
|
||||
"DATETIME": "DD MMM YYYY HH:mm",
|
||||
"PLACEHOLDER_PAGE": "編寫你的維基頁",
|
||||
"REMOVE": "移除此維基頁 ",
|
||||
|
@ -1087,5 +1209,43 @@
|
|||
"LAST_EDIT": "上次 <br />編輯 ",
|
||||
"LAST_MODIFICATION": "上回修改"
|
||||
}
|
||||
},
|
||||
"HINTS": {
|
||||
"SECTION_NAME": "Hint",
|
||||
"LINK": "If you want to know how to use it visit our support page",
|
||||
"LINK_TITLE": "Visit our support page",
|
||||
"HINT1_TITLE": "Did you know you can import and export projects?",
|
||||
"HINT1_TEXT": "This allow you to extract all your data from one Taiga and move it to another one.",
|
||||
"HINT2_TITLE": "Did you know you can create custom fields?",
|
||||
"HINT2_TEXT": "Teams can now create custom fields as a flexible means to enter specific data useful for their particular workflow",
|
||||
"HINT3_TITLE": "Reorder your projects to feature those most relevant to you",
|
||||
"HINT3_TEXT": "The top 10 project will be in your top bar direct access",
|
||||
"HINT4_TITLE": "Did you forgot what were you working on?",
|
||||
"HINT4_TEXT": "Don't worry, on your dashboard you'll find your open tasks, issues, and user stories in the order you worked on them."
|
||||
},
|
||||
"TIMELINE": {
|
||||
"UPLOAD_ATTACHMENT": "{{username}} has uploaded a new attachment in {{obj_name}}",
|
||||
"US_CREATED": "{{username}} has created a new US {{obj_name}} in {{project_name}}",
|
||||
"ISSUE_CREATED": "{{username}} has created a new issue {{obj_name}} in {{project_name}}",
|
||||
"TASK_CREATED": "{{username}} has created a new task {{obj_name}} in {{project_name}}",
|
||||
"TASK_CREATED_WITH_US": "{{username}} has created a new task {{obj_name}} in {{project_name}} which belongs to the US {{us_name}}",
|
||||
"WIKI_CREATED": "{{username}} has created a new wiki page {{obj_name}} in {{project_name}}",
|
||||
"MILESTONE_CREATED": "{{username}} has created a new sprint {{obj_name}} in {{project_name}}",
|
||||
"NEW_PROJECT": "{{username}} created the project {{project_name}}",
|
||||
"MILESTONE_UPDATED": "{{username}} has updated the sprint {{obj_name}}",
|
||||
"US_UPDATED": "{{username}} has updated the attribute \"{{field_name}}\" of the US {{obj_name}}",
|
||||
"ISSUE_UPDATED": "{{username}} has updated the attribute \"{{field_name}}\" of the issue {{obj_name}}",
|
||||
"TASK_UPDATED": "{{username}} has updated the attribute \"{{field_name}}\" of the task {{obj_name}}",
|
||||
"TASK_UPDATED_WITH_US": "{{username}} has updated the attribute \"{{field_name}}\" of the task {{obj_name}} which belongs to the US {{us_name}}",
|
||||
"WIKI_UPDATED": "{{username}} has updated the wiki page {{obj_name}}",
|
||||
"NEW_COMMENT_US": "{{username}} has commented in the US {{obj_name}}",
|
||||
"NEW_COMMENT_ISSUE": "{{username}} has commented in the issue {{obj_name}}",
|
||||
"NEW_COMMENT_TASK": "{{username}} has commented in the task {{obj_name}}",
|
||||
"NEW_MEMBER": "{{project_name}} has a new member",
|
||||
"US_ADDED_MILESTONE": "{{username}} has added the US {{obj_name}} to {{sprint_name}}",
|
||||
"US_REMOVED_FROM_MILESTONE": "{{username}} has added the US {{obj_name}} to the backlog",
|
||||
"BLOCKED": "{{username}} has blocked {{obj_name}}",
|
||||
"UNBLOCKED": "{{username}} has unblocked {{obj_name}}",
|
||||
"NEW_USER": "{{username}} has joined Taiga"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
class ProjectMenuController
|
||||
@.$inject = [
|
||||
"tgProjectService",
|
||||
"tgLightboxFactory"
|
||||
]
|
||||
|
||||
constructor: (@projectService, @lightboxFactory) ->
|
||||
@.project = null
|
||||
@.menu = Immutable.Map()
|
||||
|
||||
show: () ->
|
||||
@.project = @projectService.project
|
||||
|
||||
@.active = @._getActiveSection()
|
||||
|
||||
@._setVideoConference()
|
||||
@._setMenuPermissions()
|
||||
|
||||
hide: () ->
|
||||
@.project = null
|
||||
@.menu = {}
|
||||
|
||||
search: () ->
|
||||
@lightboxFactory.create("tg-search-box", {
|
||||
"class": "lightbox lightbox-search"
|
||||
})
|
||||
|
||||
_setVideoConference: () ->
|
||||
videoconferenceUrl = @._videoConferenceUrl()
|
||||
|
||||
if videoconferenceUrl
|
||||
@.project = @.project.set("videoconferenceUrl", videoconferenceUrl)
|
||||
|
||||
_setMenuPermissions: () ->
|
||||
@.menu = Immutable.Map({
|
||||
backlog: false,
|
||||
kanban: false,
|
||||
issues: false,
|
||||
wiki: false
|
||||
})
|
||||
|
||||
if @.project.get("is_backlog_activated") && @.project.get("my_permissions").indexOf("view_us") != -1
|
||||
@.menu = @.menu.set("backlog", true)
|
||||
|
||||
if @.project.get("is_kanban_activated") && @.project.get("my_permissions").indexOf("view_us") != -1
|
||||
@.menu = @.menu.set("kanban", true)
|
||||
|
||||
if @.project.get("is_issues_activated") && @.project.get("my_permissions").indexOf("view_issues") != -1
|
||||
@.menu = @.menu.set("issues", true)
|
||||
|
||||
if @.project.get("is_wiki_activated") && @.project.get("my_permissions").indexOf("view_wiki_pages") != -1
|
||||
@.menu = @.menu.set("wiki", true)
|
||||
|
||||
_getActiveSection: () ->
|
||||
sectionName = @projectService.section
|
||||
sectionsBreadcrumb = @projectService.sectionsBreadcrumb
|
||||
|
||||
indexBacklog = sectionsBreadcrumb.lastIndexOf("backlog")
|
||||
indexKanban = sectionsBreadcrumb.lastIndexOf("kanban")
|
||||
|
||||
if indexBacklog != -1 || indexKanban != -1
|
||||
if indexKanban == -1 || indexBacklog < indexKanban
|
||||
oldSectionName = "backlog"
|
||||
else
|
||||
oldSectionName = "kanban"
|
||||
|
||||
if sectionName == "backlog-kanban"
|
||||
if oldSectionName in ["backlog", "kanban"]
|
||||
sectionName = oldSectionName
|
||||
else if @.project.get("is_backlog_activated") && !@.project.get("is_kanban_activated")
|
||||
sectionName = "backlog"
|
||||
else if !@.project.get("is_backlog_activated") && @.project.get("is_kanban_activated")
|
||||
sectionName = "kanban"
|
||||
|
||||
return sectionName
|
||||
|
||||
_videoConferenceUrl: () ->
|
||||
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/"
|
||||
else
|
||||
return ""
|
||||
|
||||
if @.project.get("videoconferences_salt")
|
||||
url = @.project.get("slug") + "-" + @.project.get("videoconferences_salt")
|
||||
else
|
||||
url = @.project.get("slug")
|
||||
|
||||
return baseUrl + url
|
||||
|
||||
angular.module("taigaComponents").controller("ProjectMenu", ProjectMenuController)
|
|
@ -0,0 +1,248 @@
|
|||
describe "ProjectMenu", ->
|
||||
$provide = null
|
||||
$controller = null
|
||||
mocks = {}
|
||||
|
||||
_mockProjectService = ->
|
||||
mocks.projectService = {}
|
||||
|
||||
$provide.value("tgProjectService", mocks.projectService)
|
||||
|
||||
_mockLightboxFactory = ->
|
||||
mocks.lightboxFactory = {
|
||||
create: sinon.spy()
|
||||
}
|
||||
|
||||
$provide.value("tgLightboxFactory", mocks.lightboxFactory)
|
||||
|
||||
_mocks = ->
|
||||
module (_$provide_) ->
|
||||
$provide = _$provide_
|
||||
|
||||
_mockProjectService()
|
||||
_mockLightboxFactory()
|
||||
|
||||
return null
|
||||
|
||||
_inject = ->
|
||||
inject (_$controller_) ->
|
||||
$controller = _$controller_
|
||||
|
||||
_setup = ->
|
||||
_mocks()
|
||||
_inject()
|
||||
|
||||
beforeEach ->
|
||||
module "taigaComponents"
|
||||
|
||||
_setup()
|
||||
|
||||
it "open search lightbox", () ->
|
||||
ctrl = $controller("ProjectMenu")
|
||||
ctrl.search()
|
||||
|
||||
expectation = mocks.lightboxFactory.create.calledWithExactly("tg-search-box", {
|
||||
"class": "lightbox lightbox-search"
|
||||
})
|
||||
|
||||
expect(expectation).to.be.true
|
||||
|
||||
describe "show menu", ->
|
||||
it "project filled", () ->
|
||||
project = Immutable.fromJS({})
|
||||
|
||||
mocks.projectService.project = project
|
||||
mocks.projectService.sectionsBreadcrumb = Immutable.List()
|
||||
|
||||
ctrl = $controller("ProjectMenu")
|
||||
|
||||
ctrl.show()
|
||||
|
||||
expect(ctrl.project).to.be.equal(project)
|
||||
|
||||
it "videoconference url", () ->
|
||||
project = Immutable.fromJS({
|
||||
"videoconferences": "appear-in",
|
||||
"videoconferences_salt": "123",
|
||||
"slug": "project-slug"
|
||||
})
|
||||
|
||||
mocks.projectService.project = project
|
||||
mocks.projectService.sectionsBreadcrumb = Immutable.List()
|
||||
|
||||
ctrl = $controller("ProjectMenu")
|
||||
|
||||
ctrl.show()
|
||||
|
||||
url = "https://appear.in/project-slug-123"
|
||||
|
||||
expect(ctrl.project.get("videoconferenceUrl")).to.be.equal(url)
|
||||
|
||||
describe "menu permissions", () ->
|
||||
it "all options disable", () ->
|
||||
project = Immutable.fromJS({})
|
||||
|
||||
mocks.projectService.project = project
|
||||
mocks.projectService.sectionsBreadcrumb = Immutable.List()
|
||||
|
||||
ctrl = $controller("ProjectMenu")
|
||||
|
||||
ctrl.show()
|
||||
|
||||
menu = ctrl.menu.toJS()
|
||||
|
||||
expect(menu).to.be.eql({
|
||||
backlog: false,
|
||||
kanban: false,
|
||||
issues: false,
|
||||
wiki: false
|
||||
})
|
||||
|
||||
it "all options enabled", () ->
|
||||
project = Immutable.fromJS({
|
||||
is_backlog_activated: true,
|
||||
is_kanban_activated: true,
|
||||
is_issues_activated: true,
|
||||
is_wiki_activated: true,
|
||||
my_permissions: ["view_us", "view_issues", "view_wiki_pages"]
|
||||
})
|
||||
|
||||
mocks.projectService.project = project
|
||||
mocks.projectService.sectionsBreadcrumb = Immutable.List()
|
||||
|
||||
ctrl = $controller("ProjectMenu")
|
||||
|
||||
ctrl.show()
|
||||
|
||||
menu = ctrl.menu.toJS()
|
||||
|
||||
expect(menu).to.be.eql({
|
||||
backlog: true,
|
||||
kanban: true,
|
||||
issues: true,
|
||||
wiki: true
|
||||
})
|
||||
|
||||
it "all options disabled because the user doesn't have permissions", () ->
|
||||
project = Immutable.fromJS({
|
||||
is_backlog_activated: true,
|
||||
is_kanban_activated: true,
|
||||
is_issues_activated: true,
|
||||
is_wiki_activated: true,
|
||||
my_permissions: []
|
||||
})
|
||||
|
||||
mocks.projectService.project = project
|
||||
mocks.projectService.sectionsBreadcrumb = Immutable.List()
|
||||
|
||||
ctrl = $controller("ProjectMenu")
|
||||
|
||||
ctrl.show()
|
||||
|
||||
menu = ctrl.menu.toJS()
|
||||
|
||||
expect(menu).to.be.eql({
|
||||
backlog: false,
|
||||
kanban: false,
|
||||
issues: false,
|
||||
wiki: false
|
||||
})
|
||||
|
||||
describe "menu active", () ->
|
||||
it "backlog", () ->
|
||||
project = Immutable.fromJS({})
|
||||
|
||||
mocks.projectService.project = project
|
||||
mocks.projectService.section = "backlog"
|
||||
mocks.projectService.sectionsBreadcrumb = Immutable.List()
|
||||
|
||||
ctrl = $controller("ProjectMenu")
|
||||
|
||||
ctrl.show()
|
||||
|
||||
expect(ctrl.active).to.be.equal("backlog")
|
||||
|
||||
it "backlog-kanban without parent", () ->
|
||||
project = Immutable.fromJS({})
|
||||
|
||||
mocks.projectService.project = project
|
||||
mocks.projectService.section = "backlog-kanban"
|
||||
mocks.projectService.sectionsBreadcrumb = Immutable.List()
|
||||
|
||||
ctrl = $controller("ProjectMenu")
|
||||
|
||||
ctrl.show()
|
||||
|
||||
expect(ctrl.active).to.be.equal("backlog-kanban")
|
||||
|
||||
it "backlog-kanban when only kanban is enabled", () ->
|
||||
project = Immutable.fromJS({
|
||||
is_kanban_activated: true,
|
||||
my_permissions: []
|
||||
})
|
||||
|
||||
mocks.projectService.project = project
|
||||
mocks.projectService.section = "backlog-kanban"
|
||||
mocks.projectService.sectionsBreadcrumb = Immutable.List()
|
||||
|
||||
ctrl = $controller("ProjectMenu")
|
||||
|
||||
ctrl.show()
|
||||
|
||||
expect(ctrl.active).to.be.equal("kanban")
|
||||
|
||||
it "backlog-kanban when only backlog is enabled", () ->
|
||||
project = Immutable.fromJS({
|
||||
is_backlog_activated: true,
|
||||
my_permissions: []
|
||||
})
|
||||
|
||||
mocks.projectService.project = project
|
||||
mocks.projectService.section = "backlog-kanban"
|
||||
mocks.projectService.sectionsBreadcrumb = Immutable.List()
|
||||
|
||||
ctrl = $controller("ProjectMenu")
|
||||
|
||||
ctrl.show()
|
||||
|
||||
expect(ctrl.active).to.be.equal("backlog")
|
||||
|
||||
it "backlog-kanban when is child of kanban", () ->
|
||||
project = Immutable.fromJS({})
|
||||
|
||||
mocks.projectService.project = project
|
||||
mocks.projectService.section = "backlog-kanban"
|
||||
mocks.projectService.sectionsBreadcrumb = Immutable.List.of("oo", "backlog", "kanban")
|
||||
|
||||
ctrl = $controller("ProjectMenu")
|
||||
|
||||
ctrl.show()
|
||||
|
||||
expect(ctrl.active).to.be.equal("kanban")
|
||||
|
||||
it "backlog-kanban when is child of backlog", () ->
|
||||
project = Immutable.fromJS({})
|
||||
|
||||
mocks.projectService.project = project
|
||||
mocks.projectService.section = "backlog-kanban"
|
||||
mocks.projectService.sectionsBreadcrumb = Immutable.List.of("kanban", "oo", "backlog")
|
||||
|
||||
ctrl = $controller("ProjectMenu")
|
||||
|
||||
ctrl.show()
|
||||
|
||||
expect(ctrl.active).to.be.equal("backlog")
|
||||
|
||||
|
||||
it "backlog-kanban when kanban is not in the breadcrumb", () ->
|
||||
project = Immutable.fromJS({})
|
||||
|
||||
mocks.projectService.project = project
|
||||
mocks.projectService.section = "backlog-kanban"
|
||||
mocks.projectService.sectionsBreadcrumb = Immutable.List.of("oo", "backlog")
|
||||
|
||||
ctrl = $controller("ProjectMenu")
|
||||
|
||||
ctrl.show()
|
||||
|
||||
expect(ctrl.active).to.be.equal("backlog")
|
|
@ -0,0 +1,28 @@
|
|||
taiga = @.taiga
|
||||
|
||||
ProjectMenuDirective = (projectService, lightboxFactory) ->
|
||||
link = (scope, el, attrs, ctrl) ->
|
||||
projectChange = () ->
|
||||
if projectService.project
|
||||
ctrl.show()
|
||||
else
|
||||
ctrl.hide()
|
||||
|
||||
scope.$watch ( () ->
|
||||
return projectService.project
|
||||
), projectChange
|
||||
|
||||
return {
|
||||
scope: {},
|
||||
controller: "ProjectMenu",
|
||||
controllerAs: "vm",
|
||||
templateUrl: "components/project-menu/project-menu.html",
|
||||
link: link
|
||||
}
|
||||
|
||||
ProjectMenuDirective.$inject = [
|
||||
"tgProjectService",
|
||||
"tgLightboxFactory"
|
||||
]
|
||||
|
||||
angular.module("taigaComponents").directive("tgProjectMenu", ProjectMenuDirective)
|
|
@ -0,0 +1,47 @@
|
|||
nav.menu(ng-if="vm.project")
|
||||
div(class="menu-container")
|
||||
ul(class="main-nav")
|
||||
li(id="nav-search")
|
||||
a(href="", ng-class="{active: vm.active == 'search'}", title="{{'PROJECT.SECTION.SEARCH' | translate}}", tabindex="1", ng-click="vm.search()")
|
||||
span(class="icon icon-search")
|
||||
span.helper(translate="PROJECT.SECTION.SEARCH")
|
||||
|
||||
li(id="nav-timeline")
|
||||
a(ng-class="{active: vm.active == 'project-timeline'}", title="{{'PROJECT.SECTION.TIMELINE' | translate}}", tg-nav="project:project=vm.project.get('slug')", tabindex="2")
|
||||
include ../../../svg/timeline.svg
|
||||
span.helper(translate="PROJECT.SECTION.TIMELINE")
|
||||
|
||||
li(id="nav-backlog", ng-if="vm.menu.get('backlog')")
|
||||
a(ng-class="{active: vm.active == 'backlog'}", title="{{'PROJECT.SECTION.BACKLOG' | translate}}", tg-nav="project-backlog:project=vm.project.get('slug')", tabindex="2")
|
||||
span(class="icon icon-backlog")
|
||||
span.helper(translate="PROJECT.SECTION.BACKLOG")
|
||||
|
||||
li(id="nav-kanban", ng-if="vm.menu.get('kanban')")
|
||||
a(ng-class="{active: vm.active == 'kanban'}", title="{{'PROJECT.SECTION.KANBAN' | translate}}", tg-nav="project-kanban:project=vm.project.get('slug')", tabindex="3")
|
||||
span(class="icon icon-kanban")
|
||||
span.helper(translate="PROJECT.SECTION.KANBAN")
|
||||
|
||||
li(id="nav-issues", ng-if="vm.menu.get('issues')")
|
||||
a(ng-class="{active: vm.active == 'issues'}", title="{{'PROJECT.SECTION.ISSUES' | translate}}", tg-nav="project-issues:project=vm.project.get('slug')", tabindex="4")
|
||||
span(class="icon icon-issues")
|
||||
span.helper(translate="PROJECT.SECTION.ISSUES")
|
||||
|
||||
li(id="nav-wiki", ng-if="vm.menu.get('wiki')")
|
||||
a(ng-class="{active: vm.active == 'wiki'}", title="{{'PROJECT.SECTION.WIKI' | translate}}", tg-nav="project-wiki:project=vm.project.get('slug')", tabindex="5")
|
||||
span(class="icon icon-wiki")
|
||||
span.helper(translate="PROJECT.SECTION.WIKI")
|
||||
|
||||
li(id="nav-team")
|
||||
a(ng-class="{active: vm.active == 'team'}", title="{{'PROJECT.SECTION.TEAM' | translate}}", tg-nav="project-team:project=vm.project.get('slug')", tabindex="6")
|
||||
span(class="icon icon-team")
|
||||
span.helper(translate="PROJECT.SECTION.TEAM")
|
||||
|
||||
li(id="nav-video", ng-if="vm.project.get('videoconferenceUrl')")
|
||||
a(ng-href="{{vm.project.get('videoconferenceUrl')}}", target="_blank", title="{{'PROJECT.SECTION.MEETUP' | translate}}", tabindex="7")
|
||||
span(class="icon icon-video")
|
||||
span.helper(translate="PROJECT.SECTION.MEETUP")
|
||||
|
||||
li(id="nav-admin", ng-if="vm.project.get('i_am_owner')")
|
||||
a(ng-class="{active: vm.active == 'admin'}", tg-nav="project-admin-home:project=vm.project.get('slug')", title="{{'PROJECT.SECTION.ADMIN' | translate}}", tabindex="8")
|
||||
span(class="icon icon-settings")
|
||||
span.helper(translate="PROJECT.SECTION.ADMIN")
|
|
@ -0,0 +1,11 @@
|
|||
class FeedbackService extends taiga.Service
|
||||
@.$inject = ["tgLightboxFactory"]
|
||||
|
||||
constructor: (@lightboxFactory) ->
|
||||
|
||||
sendFeedback: ->
|
||||
@lightboxFactory.create("tg-lb-feedback", {
|
||||
"class": "lightbox lightbox-feedback lightbox-generic-form"
|
||||
})
|
||||
|
||||
angular.module("taigaFeedback").service("tgFeedbackService", FeedbackService)
|
|
@ -0,0 +1,38 @@
|
|||
describe "tgFeedbackService", ->
|
||||
feedbackService = provide = null
|
||||
mocks = {}
|
||||
|
||||
_mockTgLightboxFactory = () ->
|
||||
mocks.tgLightboxFactory = {
|
||||
create: sinon.stub()
|
||||
}
|
||||
|
||||
provide.value "tgLightboxFactory", mocks.tgLightboxFactory
|
||||
|
||||
_inject = (callback) ->
|
||||
inject (_tgFeedbackService_) ->
|
||||
feedbackService = _tgFeedbackService_
|
||||
callback() if callback
|
||||
|
||||
_mocks = () ->
|
||||
module ($provide) ->
|
||||
provide = $provide
|
||||
_mockTgLightboxFactory()
|
||||
return null
|
||||
|
||||
_setup = ->
|
||||
_mocks()
|
||||
|
||||
beforeEach ->
|
||||
module "taigaFeedback"
|
||||
_setup()
|
||||
_inject()
|
||||
|
||||
it "work in progress filled", () ->
|
||||
expect(mocks.tgLightboxFactory.create.callCount).to.be.equal(0)
|
||||
feedbackService.sendFeedback()
|
||||
expect(mocks.tgLightboxFactory.create.callCount).to.be.equal(1)
|
||||
params = {
|
||||
"class": "lightbox lightbox-feedback lightbox-generic-form"
|
||||
}
|
||||
expect(mocks.tgLightboxFactory.create.calledWith("tg-lb-feedback", params)).to.be.true()
|
|
@ -0,0 +1,28 @@
|
|||
DutyDirective = (navurls, $translate) ->
|
||||
link = (scope, el, attrs, ctrl) ->
|
||||
scope.vm = {}
|
||||
scope.vm.duty = scope.duty
|
||||
|
||||
scope.vm.getDutyType = () ->
|
||||
if scope.vm.duty
|
||||
if scope.vm.duty.get('_name') == "userstories"
|
||||
return $translate.instant("COMMON.USER_STORY")
|
||||
if scope.vm.duty.get('_name') == "tasks"
|
||||
return $translate.instant("COMMON.TASK")
|
||||
if scope.vm.duty.get('_name') == "issues"
|
||||
return $translate.instant("COMMON.ISSUE")
|
||||
|
||||
return {
|
||||
templateUrl: "home/duties/duty.html"
|
||||
scope: {
|
||||
"duty": "=tgDuty"
|
||||
}
|
||||
link: link
|
||||
}
|
||||
|
||||
DutyDirective.$inject = [
|
||||
"$tgNavUrls",
|
||||
"$translate"
|
||||
]
|
||||
|
||||
angular.module("taigaHome").directive("tgDuty", DutyDirective)
|
|
@ -0,0 +1,82 @@
|
|||
describe "dutyDirective", () ->
|
||||
scope = compile = provide = null
|
||||
mockTgProjectsService = null
|
||||
mockTgNavUrls = null
|
||||
mockTranslate = null
|
||||
template = "<div tg-duty='duty'></div>"
|
||||
|
||||
createDirective = () ->
|
||||
elm = compile(template)(scope)
|
||||
return elm
|
||||
|
||||
_mockTgNavUrls = () ->
|
||||
mockTgNavUrls = {
|
||||
resolve: sinon.stub()
|
||||
}
|
||||
provide.value "$tgNavUrls", mockTgNavUrls
|
||||
|
||||
_mockTranslateFilter = () ->
|
||||
mockTranslateFilter = (value) ->
|
||||
return value
|
||||
provide.value "translateFilter", mockTranslateFilter
|
||||
|
||||
_mockTgProjectsService = () ->
|
||||
mockTgProjectsService = {
|
||||
projectsById: {
|
||||
get: sinon.stub()
|
||||
}
|
||||
}
|
||||
provide.value "tgProjectsService", mockTgProjectsService
|
||||
|
||||
_mockTranslate = () ->
|
||||
mockTranslate = {
|
||||
instant: sinon.stub()
|
||||
}
|
||||
provide.value "$translate", mockTranslate
|
||||
|
||||
_mocks = () ->
|
||||
module ($provide) ->
|
||||
provide = $provide
|
||||
_mockTgNavUrls()
|
||||
_mockTgProjectsService()
|
||||
_mockTranslate()
|
||||
_mockTranslateFilter()
|
||||
return null
|
||||
|
||||
beforeEach ->
|
||||
module "templates"
|
||||
module "taigaHome"
|
||||
|
||||
_mocks()
|
||||
|
||||
inject ($rootScope, $compile) ->
|
||||
scope = $rootScope.$new()
|
||||
compile = $compile
|
||||
|
||||
it "duty directive scope content", () ->
|
||||
scope.duty = Immutable.fromJS({
|
||||
project: 1
|
||||
ref: 1
|
||||
_name: "userstories"
|
||||
assigned_to_extra_info: {
|
||||
photo: "http://jstesting.taiga.io/photo"
|
||||
full_name_display: "Taiga testing js"
|
||||
}
|
||||
})
|
||||
|
||||
mockTgProjectsService.projectsById.get
|
||||
.withArgs("1")
|
||||
.returns({slug: "project-slug", "name": "testing js project"})
|
||||
|
||||
mockTgNavUrls.resolve
|
||||
.withArgs("project-userstories-detail", {project: "project-slug", ref: 1})
|
||||
.returns("http://jstesting.taiga.io")
|
||||
|
||||
mockTranslate.instant
|
||||
.withArgs("COMMON.USER_STORY")
|
||||
.returns("User story translated")
|
||||
|
||||
elm = createDirective()
|
||||
scope.$apply()
|
||||
|
||||
expect(elm.isolateScope().vm.getDutyType()).to.be.equal("User story translated")
|
|
@ -0,0 +1,18 @@
|
|||
a(href="{{ ::vm.duty.get('url') }}", title="{{ ::duty.get('subject') }}")
|
||||
|
||||
img.avatar(ng-if="::vm.duty.get('assigned_to_extra_info')"
|
||||
ng-src="{{ ::vm.duty.get('assigned_to_extra_info').get('photo') }}"
|
||||
title="{{ ::vm.duty.get('assigned_to_extra_info').get('full_name_display') }}")
|
||||
|
||||
img.avatar(ng-if="::!vm.duty.get('assigned_to_extra_info')"
|
||||
src="/images/unnamed.png"
|
||||
title="{{'ACTIVITY.VALUES.UNASSIGNED' | translate}}")
|
||||
|
||||
div.duty-data
|
||||
div
|
||||
span.duty-type {{ ::vm.getDutyType() }}
|
||||
span.duty-status(ng-style="{'color': vm.duty.get('status_extra_info').get('color')}") {{ ::vm.duty.get('status_extra_info').get('name') }}
|
||||
span.duty-title
|
||||
span.duty-id(tg-bo-ref="duty.get('ref')")
|
||||
span.duty-name {{ ::duty.get('subject') }}
|
||||
div.duty-project {{ ::vm.duty.get('projectName')}}
|
|
@ -0,0 +1,75 @@
|
|||
.working-on,
|
||||
.watching {
|
||||
margin-bottom: 2rem;
|
||||
.duty-single {
|
||||
border-bottom: 1px solid $whitish;
|
||||
cursor: pointer;
|
||||
padding: .5rem;
|
||||
&:last-child {
|
||||
border: 0;
|
||||
}
|
||||
&.blocked {
|
||||
background: rgba($red-light, .2);
|
||||
.duty-type,
|
||||
.duty-status {
|
||||
color: $red;
|
||||
}
|
||||
}
|
||||
>a {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
}
|
||||
.avatar {
|
||||
flex-basis: 47px;
|
||||
height: 47px;
|
||||
margin-right: .5rem;
|
||||
width: 47px;
|
||||
}
|
||||
.duty-data {
|
||||
flex: 1;
|
||||
margin-right: .5rem;
|
||||
}
|
||||
.duty-type,
|
||||
.duty-status {
|
||||
@extend %small;
|
||||
color: $gray;
|
||||
margin-right: .3rem;
|
||||
}
|
||||
.duty-title {
|
||||
display: block;
|
||||
margin-top: .25rem;
|
||||
}
|
||||
.duty-id {
|
||||
color: $gray-light;
|
||||
margin-right: .3rem;
|
||||
}
|
||||
.duty-project {
|
||||
@extend %small;
|
||||
align-self: flex-start;
|
||||
color: $gray-light;
|
||||
margin-left: auto;
|
||||
text-align: right;
|
||||
width: 120px;
|
||||
}
|
||||
.see-more {
|
||||
display: block;
|
||||
margin: 2rem 30%;
|
||||
}
|
||||
}
|
||||
.watching-empty {
|
||||
padding: 5vh;
|
||||
text-align: center;
|
||||
svg {
|
||||
margin: 2rem auto;
|
||||
max-width: 160px;
|
||||
text-align: center;
|
||||
path {
|
||||
fill: $whitish;
|
||||
}
|
||||
}
|
||||
p {
|
||||
@extend %small;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
doctype html
|
||||
|
||||
include ../../partials/includes/components/beta
|
||||
div.home-wrapper.centered
|
||||
div.duty-summary
|
||||
div(tg-working-on)
|
||||
|
||||
aside.project-list(tg-home-project-list)
|
|
@ -0,0 +1 @@
|
|||
module = angular.module("taigaHome", [])
|
|
@ -0,0 +1,23 @@
|
|||
.home-wrapper {
|
||||
display: flex;
|
||||
padding-top: 2rem;
|
||||
.duty-summary {
|
||||
flex: 1;
|
||||
margin-right: 2rem;
|
||||
}
|
||||
.project-list {
|
||||
width: 250px;
|
||||
}
|
||||
.see-more-projects-btn {
|
||||
display: block;
|
||||
}
|
||||
.title-bar {
|
||||
@extend %title;
|
||||
@extend %larger;
|
||||
align-content: center;
|
||||
background: $whitish;
|
||||
display: flex;
|
||||
margin: 0 0 .5rem;
|
||||
padding: .9rem 1rem;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
groupBy = @.taiga.groupBy
|
||||
|
||||
class HomeService extends taiga.Service
|
||||
@.$inject = [
|
||||
"$tgNavUrls",
|
||||
"tgResources",
|
||||
"tgProjectsService"
|
||||
]
|
||||
|
||||
constructor: (@navurls, @rs, @projectsService) ->
|
||||
|
||||
_attachProjectInfoToWorkInProgress: (workInProgress, projectsById) ->
|
||||
_attachProjectInfoToDuty = (duty, objType) =>
|
||||
project = projectsById.get(String(duty.get('project')))
|
||||
|
||||
ctx = {
|
||||
project: project.get('slug')
|
||||
ref: duty.get('ref')
|
||||
}
|
||||
|
||||
url = @navurls.resolve("project-#{objType}-detail", ctx)
|
||||
|
||||
duty = duty.set('url', url)
|
||||
duty = duty.set('projectName', project.get('name'))
|
||||
duty = duty.set("_name", objType)
|
||||
|
||||
return duty
|
||||
|
||||
assignedTo = workInProgress.get("assignedTo")
|
||||
|
||||
if assignedTo.get("userStories")
|
||||
_duties = assignedTo.get("userStories").map (duty) ->
|
||||
return _attachProjectInfoToDuty(duty, "userstories")
|
||||
|
||||
assignedTo = assignedTo.set("userStories", _duties)
|
||||
|
||||
if assignedTo.get("tasks")
|
||||
_duties = assignedTo.get("tasks").map (duty) ->
|
||||
return _attachProjectInfoToDuty(duty, "tasks")
|
||||
|
||||
assignedTo = assignedTo.set("tasks", _duties)
|
||||
|
||||
if assignedTo.get("issues")
|
||||
_duties = assignedTo.get("issues").map (duty) ->
|
||||
return _attachProjectInfoToDuty(duty, "issues")
|
||||
|
||||
assignedTo = assignedTo.set("issues", _duties)
|
||||
|
||||
watching = workInProgress.get("watching")
|
||||
|
||||
if watching.get("userStories")
|
||||
_duties = watching.get("userStories").map (duty) ->
|
||||
return _attachProjectInfoToDuty(duty, "userstories")
|
||||
|
||||
watching = watching.set("userStories", _duties)
|
||||
|
||||
if watching.get("tasks")
|
||||
_duties = watching.get("tasks").map (duty) ->
|
||||
return _attachProjectInfoToDuty(duty, "tasks")
|
||||
|
||||
watching = watching.set("tasks", _duties)
|
||||
|
||||
if watching.get("issues")
|
||||
_duties = watching.get("issues").map (duty) ->
|
||||
return _attachProjectInfoToDuty(duty, "issues")
|
||||
|
||||
watching = watching.set("issues", _duties)
|
||||
|
||||
|
||||
workInProgress = workInProgress.set("assignedTo", assignedTo)
|
||||
workInProgress = workInProgress.set("watching", watching)
|
||||
|
||||
|
||||
getWorkInProgress: (userId) ->
|
||||
projectsById = Immutable.Map()
|
||||
|
||||
projectsPromise = @projectsService.getProjectsByUserId(userId).then (projects) ->
|
||||
projectsById = Immutable.fromJS(groupBy(projects.toJS(), (p) -> p.id))
|
||||
|
||||
assignedTo = Immutable.Map()
|
||||
|
||||
params = {
|
||||
status__is_closed: false
|
||||
assigned_to: userId
|
||||
}
|
||||
|
||||
params_us = {
|
||||
is_closed: false
|
||||
assigned_to: userId
|
||||
}
|
||||
|
||||
assignedUserStoriesPromise = @rs.userstories.listInAllProjects(params_us).then (userstories) ->
|
||||
assignedTo = assignedTo.set("userStories", userstories)
|
||||
|
||||
assignedTasksPromise = @rs.tasks.listInAllProjects(params).then (tasks) ->
|
||||
assignedTo = assignedTo.set("tasks", tasks)
|
||||
|
||||
assignedIssuesPromise = @rs.issues.listInAllProjects(params).then (issues) ->
|
||||
assignedTo = assignedTo.set("issues", issues)
|
||||
|
||||
params = {
|
||||
status__is_closed: false
|
||||
watchers: userId
|
||||
}
|
||||
|
||||
params_us = {
|
||||
is_closed: false
|
||||
watchers: userId
|
||||
}
|
||||
|
||||
watching = Immutable.Map()
|
||||
|
||||
watchingUserStoriesPromise = @rs.userstories.listInAllProjects(params_us).then (userstories) ->
|
||||
watching = watching.set("userStories", userstories)
|
||||
|
||||
watchingTasksPromise = @rs.tasks.listInAllProjects(params).then (tasks) ->
|
||||
watching = watching.set("tasks", tasks)
|
||||
|
||||
watchingIssuesPromise = @rs.issues.listInAllProjects(params).then (issues) ->
|
||||
watching = watching.set("issues", issues)
|
||||
|
||||
workInProgress = Immutable.Map()
|
||||
|
||||
Promise.all([
|
||||
projectsPromise
|
||||
assignedUserStoriesPromise,
|
||||
assignedTasksPromise,
|
||||
assignedIssuesPromise,
|
||||
watchingUserStoriesPromise,
|
||||
watchingTasksPromise,
|
||||
watchingIssuesPromise
|
||||
]).then =>
|
||||
workInProgress = workInProgress.set("assignedTo", assignedTo)
|
||||
workInProgress = workInProgress.set("watching", watching)
|
||||
|
||||
workInProgress = @._attachProjectInfoToWorkInProgress(workInProgress, projectsById)
|
||||
|
||||
return workInProgress
|
||||
|
||||
angular.module("taigaHome").service("tgHomeService", HomeService)
|
|
@ -0,0 +1,143 @@
|
|||
describe "tgHome", ->
|
||||
homeService = provide = null
|
||||
mocks = {}
|
||||
|
||||
_mockResources = () ->
|
||||
mocks.resources = {}
|
||||
|
||||
mocks.resources.userstories = {}
|
||||
mocks.resources.tasks = {}
|
||||
mocks.resources.issues = {}
|
||||
|
||||
mocks.resources.userstories.listInAllProjects = sinon.stub()
|
||||
mocks.resources.tasks.listInAllProjects = sinon.stub()
|
||||
mocks.resources.issues.listInAllProjects = sinon.stub()
|
||||
|
||||
provide.value "tgResources", mocks.resources
|
||||
|
||||
_mockTgNavUrls = () ->
|
||||
mocks.tgNavUrls = {
|
||||
resolve: sinon.stub()
|
||||
}
|
||||
|
||||
provide.value "$tgNavUrls", mocks.tgNavUrls
|
||||
|
||||
_mockProjectsService = () ->
|
||||
mocks.projectsService = {
|
||||
getProjectsByUserId: sinon.stub().promise()
|
||||
}
|
||||
|
||||
provide.value "tgProjectsService", mocks.projectsService
|
||||
|
||||
_inject = (callback) ->
|
||||
inject (_tgHomeService_) ->
|
||||
homeService = _tgHomeService_
|
||||
callback() if callback
|
||||
|
||||
_mocks = () ->
|
||||
module ($provide) ->
|
||||
provide = $provide
|
||||
_mockResources()
|
||||
_mockTgNavUrls()
|
||||
_mockProjectsService()
|
||||
|
||||
return null
|
||||
|
||||
_setup = ->
|
||||
_mocks()
|
||||
|
||||
beforeEach ->
|
||||
module "taigaHome"
|
||||
_setup()
|
||||
_inject()
|
||||
|
||||
it "get work in progress by user", (done) ->
|
||||
userId = 3
|
||||
|
||||
mocks.projectsService.getProjectsByUserId
|
||||
.withArgs(userId)
|
||||
.resolve(Immutable.fromJS([
|
||||
{id: 1, name: "fake1", slug: "project-1"},
|
||||
{id: 2, name: "fake2", slug: "project-2"}
|
||||
]))
|
||||
|
||||
mocks.resources.userstories.listInAllProjects.promise()
|
||||
.resolve(Immutable.fromJS([{id: 1, ref: 1, project: "1"}]))
|
||||
|
||||
mocks.resources.tasks.listInAllProjects.promise()
|
||||
.resolve(Immutable.fromJS([{id: 2, ref: 2, project: "1"}]))
|
||||
|
||||
mocks.resources.issues.listInAllProjects.promise()
|
||||
.resolve(Immutable.fromJS([{id: 3, ref: 3, project: "1"}]))
|
||||
|
||||
# mock urls
|
||||
mocks.tgNavUrls.resolve
|
||||
.withArgs("project-userstories-detail", {project: "project-1", ref: 1})
|
||||
.returns("/testing-project/us/1")
|
||||
|
||||
mocks.tgNavUrls.resolve
|
||||
.withArgs("project-tasks-detail", {project: "project-1", ref: 2})
|
||||
.returns("/testing-project/tasks/1")
|
||||
|
||||
mocks.tgNavUrls.resolve
|
||||
.withArgs("project-issues-detail", {project: "project-1", ref: 3})
|
||||
.returns("/testing-project/issues/1")
|
||||
|
||||
homeService.getWorkInProgress(userId)
|
||||
.then (workInProgress) ->
|
||||
expect(workInProgress.toJS()).to.be.eql({
|
||||
assignedTo: {
|
||||
userStories: [{
|
||||
id: 1,
|
||||
ref: 1,
|
||||
project: '1',
|
||||
url: '/testing-project/us/1',
|
||||
projectName: 'fake1',
|
||||
_name: 'userstories'
|
||||
}]
|
||||
tasks: [{
|
||||
id: 2,
|
||||
ref: 2,
|
||||
project: '1',
|
||||
url: '/testing-project/tasks/1',
|
||||
projectName: 'fake1',
|
||||
_name: 'tasks'
|
||||
}]
|
||||
issues: [{
|
||||
id: 3,
|
||||
ref: 3,
|
||||
project: '1',
|
||||
url: '/testing-project/issues/1',
|
||||
projectName: 'fake1',
|
||||
_name: 'issues'
|
||||
}]
|
||||
}
|
||||
watching: {
|
||||
userStories: [{
|
||||
id: 1,
|
||||
ref: 1,
|
||||
project: '1',
|
||||
url: '/testing-project/us/1',
|
||||
projectName: 'fake1',
|
||||
_name: 'userstories'
|
||||
}]
|
||||
tasks: [{
|
||||
id: 2,
|
||||
ref: 2,
|
||||
project: '1',
|
||||
url: '/testing-project/tasks/1',
|
||||
projectName: 'fake1',
|
||||
_name: 'tasks'
|
||||
}]
|
||||
issues: [{
|
||||
id: 3,
|
||||
ref: 3,
|
||||
project: '1',
|
||||
url: '/testing-project/issues/1',
|
||||
projectName: 'fake1',
|
||||
_name: 'issues'
|
||||
}]
|
||||
}
|
||||
})
|
||||
|
||||
done()
|
|
@ -0,0 +1,73 @@
|
|||
describe "homeProjectListDirective", () ->
|
||||
scope = compile = provide = null
|
||||
mocks = {}
|
||||
template = "<div tg-home-project-list></div>"
|
||||
projects = Immutable.fromJS({
|
||||
recents: [
|
||||
{id: 1},
|
||||
{id: 2},
|
||||
{id: 3}
|
||||
]
|
||||
})
|
||||
|
||||
createDirective = () ->
|
||||
elm = compile(template)(scope)
|
||||
return elm
|
||||
|
||||
_mockTgCurrentUserService = () ->
|
||||
mocks.currentUserService = {
|
||||
projects: projects
|
||||
}
|
||||
|
||||
provide.value "tgCurrentUserService", mocks.currentUserService
|
||||
|
||||
_mockTgProjectsService = () ->
|
||||
mocks.projectsService = {
|
||||
newProject: sinon.stub()
|
||||
}
|
||||
provide.value "tgProjectsService", mocks.projectsService
|
||||
|
||||
_mockTranslateFilter = () ->
|
||||
mockTranslateFilter = (value) ->
|
||||
return value
|
||||
provide.value "translateFilter", mockTranslateFilter
|
||||
|
||||
_mocks = () ->
|
||||
module ($provide) ->
|
||||
provide = $provide
|
||||
_mockTgCurrentUserService()
|
||||
_mockTgProjectsService()
|
||||
_mockTranslateFilter()
|
||||
return null
|
||||
|
||||
beforeEach ->
|
||||
module "templates"
|
||||
module "taigaHome"
|
||||
|
||||
_mocks()
|
||||
|
||||
inject ($rootScope, $compile) ->
|
||||
scope = $rootScope.$new()
|
||||
compile = $compile
|
||||
|
||||
recents = Immutable.fromJS([
|
||||
{
|
||||
id:1
|
||||
},
|
||||
{
|
||||
id: 2
|
||||
}
|
||||
])
|
||||
|
||||
it "home project list directive scope content", () ->
|
||||
elm = createDirective()
|
||||
scope.$apply()
|
||||
expect(elm.isolateScope().vm.projects.size).to.be.equal(3)
|
||||
|
||||
it "home project list directive newProject", () ->
|
||||
elm = createDirective()
|
||||
scope.$apply()
|
||||
|
||||
expect(mocks.projectsService.newProject.callCount).to.be.equal(0)
|
||||
elm.isolateScope().vm.newProject()
|
||||
expect(mocks.projectsService.newProject.callCount).to.be.equal(1)
|
|
@ -0,0 +1,23 @@
|
|||
HomeProjectListDirective = (currentUserService, projectsService) ->
|
||||
link = (scope, el, attrs, ctrl) ->
|
||||
scope.vm = {}
|
||||
|
||||
taiga.defineImmutableProperty(scope.vm, "projects", () -> currentUserService.projects.get("recents"))
|
||||
|
||||
scope.vm.newProject = ->
|
||||
projectsService.newProject()
|
||||
|
||||
directive = {
|
||||
templateUrl: "home/projects/home-project-list.html"
|
||||
scope: {}
|
||||
link: link
|
||||
}
|
||||
|
||||
return directive
|
||||
|
||||
HomeProjectListDirective.$inject = [
|
||||
"tgCurrentUserService",
|
||||
"tgProjectsService"
|
||||
]
|
||||
|
||||
angular.module("taigaHome").directive("tgHomeProjectList", HomeProjectListDirective)
|
|
@ -0,0 +1,27 @@
|
|||
ul.home-project-list(ng-show="vm.projects.size")
|
||||
li.home-project-list-single(tg-bind-scope, tg-repeat="project in vm.projects")
|
||||
a(href="#", tg-nav="project:project=project.get('slug')")
|
||||
h2.home-project-list-single-title
|
||||
span.project-name(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:150 }}
|
||||
span(ng-if="::project.get('description').size > 150") ...
|
||||
|
||||
a.see-more-projects-btn.button-gray(href="#",
|
||||
ng-show="vm.projects.size",
|
||||
tg-nav="projects",
|
||||
title="{{'PROJECT.NAVIGATION.SEE_MORE_PROJECTS' | translate}}",
|
||||
translate="PROJECT.NAVIGATION.SEE_MORE_PROJECTS")
|
||||
|
||||
section.projects-empty(ng-hide="vm.projects.size")
|
||||
include ../../../svg/empty-project.svg
|
||||
p(translate="HOME.EMPTY_PROJECT_LIST")
|
||||
a.create-project-button.button-green(href="#", ng-click="vm.newProject()",
|
||||
title="{{'PROJECT.NAVIGATION.TITLE_CREATE_PROJECT' | translate}}",
|
||||
translate="PROJECT.NAVIGATION.ACTION_CREATE_PROJECT")
|
||||
span(tg-import-project-button)
|
||||
a.import-project-button.button-blackish(href="#",
|
||||
title="{{'PROJECT.NAVIGATION.TITLE_IMPORT_PROJECT' | translate}}",
|
||||
translate="PROJECT.NAVIGATION.ACTION_IMPORT_PROJECT")
|
||||
input.import-file.hidden(type="file")
|
|
@ -0,0 +1,74 @@
|
|||
.home-project-list {
|
||||
li {
|
||||
border: 1px solid lighten($gray-light, 15%);
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
margin-bottom: .75rem;
|
||||
padding: 1rem;
|
||||
text-overflow: ellipsis;
|
||||
&:hover {
|
||||
border-color: $fresh-taiga;
|
||||
transition: all .3s linear;
|
||||
p {
|
||||
color: $gray;
|
||||
transition: color .3s linear;
|
||||
}
|
||||
.private path {
|
||||
fill: $gray;
|
||||
transition: fill .3s linear;
|
||||
}
|
||||
}
|
||||
}
|
||||
a {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 5rem;
|
||||
}
|
||||
h2 {
|
||||
@extend %text;
|
||||
color: $gray;
|
||||
font-size: 1.5rem;
|
||||
line-height: 1.3;
|
||||
margin-bottom: .5rem;
|
||||
text-transform: none;
|
||||
.project-name {
|
||||
display: inline-block;
|
||||
max-width: 90%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
vertical-align: middle;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
p {
|
||||
@extend %text;
|
||||
@extend %xsmall;
|
||||
color: $gray-light;
|
||||
line-height: 125%;
|
||||
margin: 0;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
}
|
||||
|
||||
.projects-empty {
|
||||
text-align: center;
|
||||
svg {
|
||||
height: 100px;
|
||||
margin: 1rem auto;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
path {
|
||||
fill: $whitish;
|
||||
}
|
||||
}
|
||||
p {
|
||||
@extend %small;
|
||||
}
|
||||
.create-project-button {
|
||||
display: block;
|
||||
margin-bottom: .25rem;
|
||||
}
|
||||
.import-project-button {
|
||||
display: block;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
class WorkingOnController
|
||||
@.$inject = [
|
||||
"tgHomeService"
|
||||
]
|
||||
|
||||
constructor: (@homeService) ->
|
||||
@.assignedTo = Immutable.Map()
|
||||
@.watching = Immutable.Map()
|
||||
|
||||
_setAssignedTo: (workInProgress) ->
|
||||
userStories = workInProgress.get("assignedTo").get("userStories")
|
||||
tasks = workInProgress.get("assignedTo").get("tasks")
|
||||
issues = workInProgress.get("assignedTo").get("issues")
|
||||
|
||||
@.assignedTo = userStories.concat(tasks).concat(issues)
|
||||
if @.assignedTo.size > 0
|
||||
@.assignedTo = @.assignedTo.sortBy((elem) -> elem.get("modified_date")).reverse()
|
||||
|
||||
_setWatching: (workInProgress) ->
|
||||
userStories = workInProgress.get("watching").get("userStories")
|
||||
tasks = workInProgress.get("watching").get("tasks")
|
||||
issues = workInProgress.get("watching").get("issues")
|
||||
|
||||
@.watching = userStories.concat(tasks).concat(issues)
|
||||
if @.watching.size > 0
|
||||
@.watching = @.watching.sortBy((elem) -> elem.get("modified_date")).reverse()
|
||||
|
||||
getWorkInProgress: (userId) ->
|
||||
return @homeService.getWorkInProgress(userId).then (workInProgress) =>
|
||||
@._setAssignedTo(workInProgress)
|
||||
@._setWatching(workInProgress)
|
||||
|
||||
angular.module("taigaHome").controller("WorkingOn", WorkingOnController)
|
|
@ -0,0 +1,69 @@
|
|||
describe "WorkingOn", ->
|
||||
$controller = null
|
||||
$provide = null
|
||||
mocks = {}
|
||||
|
||||
_mockHomeService = () ->
|
||||
mocks.homeService = {
|
||||
getWorkInProgress: sinon.stub()
|
||||
}
|
||||
|
||||
$provide.value("tgHomeService", mocks.homeService)
|
||||
|
||||
_mocks = () ->
|
||||
module (_$provide_) ->
|
||||
$provide = _$provide_
|
||||
|
||||
_mockHomeService()
|
||||
|
||||
return null
|
||||
|
||||
_inject = () ->
|
||||
inject (_$controller_) ->
|
||||
$controller = _$controller_
|
||||
|
||||
beforeEach ->
|
||||
module "taigaHome"
|
||||
_mocks()
|
||||
_inject()
|
||||
|
||||
it "get work in progress items", (done) ->
|
||||
userId = 3
|
||||
|
||||
workInProgress = Immutable.fromJS({
|
||||
assignedTo: {
|
||||
userStories: [{id: 1, modified_date: "2015-01-01"}, {id: 2, modified_date: "2015-01-04"}],
|
||||
tasks: [{id: 3, modified_date: "2015-01-02"}, {id: 4, modified_date: "2015-01-05"}],
|
||||
issues: [{id: 5, modified_date: "2015-01-03"}, {id: 6, modified_date: "2015-01-06"}]
|
||||
},
|
||||
watching: {
|
||||
userStories: [{id: 7, modified_date: "2015-01-01"}, {id: 8, modified_date: "2015-01-04"}],
|
||||
tasks: [{id: 9, modified_date: "2015-01-02"}, {id: 10, modified_date: "2015-01-05"}],
|
||||
issues: [{id: 11, modified_date: "2015-01-03"}, {id: 12, modified_date: "2015-01-06"}]
|
||||
}
|
||||
})
|
||||
|
||||
mocks.homeService.getWorkInProgress.withArgs(userId).promise().resolve(workInProgress)
|
||||
|
||||
ctrl = $controller("WorkingOn")
|
||||
|
||||
ctrl.getWorkInProgress(userId).then () ->
|
||||
expect(ctrl.assignedTo.toJS()).to.be.eql([
|
||||
{id: 6, modified_date: '2015-01-06'},
|
||||
{id: 4, modified_date: '2015-01-05'},
|
||||
{id: 2, modified_date: '2015-01-04'},
|
||||
{id: 5, modified_date: '2015-01-03'},
|
||||
{id: 3, modified_date: '2015-01-02'},
|
||||
{id: 1, modified_date: '2015-01-01'}
|
||||
])
|
||||
|
||||
expect(ctrl.watching.toJS()).to.be.eql([
|
||||
{id: 12, modified_date: '2015-01-06'},
|
||||
{id: 10, modified_date: '2015-01-05'},
|
||||
{id: 8, modified_date: '2015-01-04'},
|
||||
{id: 11, modified_date: '2015-01-03'},
|
||||
{id: 9, modified_date: '2015-01-02'},
|
||||
{id: 7, modified_date: '2015-01-01'}
|
||||
])
|
||||
|
||||
done()
|
|
@ -0,0 +1,20 @@
|
|||
WorkingOnDirective = (homeService, currentUserService) ->
|
||||
link = (scope, el, attrs, ctrl) ->
|
||||
userId = currentUserService.getUser().get("id")
|
||||
|
||||
ctrl.getWorkInProgress(userId)
|
||||
|
||||
return {
|
||||
controller: "WorkingOn",
|
||||
controllerAs: "vm",
|
||||
templateUrl: "home/working-on/working-on.html",
|
||||
scope: {},
|
||||
link: link
|
||||
}
|
||||
|
||||
WorkingOnDirective.$inject = [
|
||||
"tgHomeService",
|
||||
"tgCurrentUserService"
|
||||
]
|
||||
|
||||
angular.module("taigaHome").directive("tgWorkingOn", WorkingOnDirective)
|
|
@ -0,0 +1,12 @@
|
|||
div.title-bar.working-on-title(ng-show="vm.assignedTo.size", translate="HOME.WORKING_ON_SECTION")
|
||||
section.working-on(ng-show="vm.assignedTo.size")
|
||||
div.duty-single(tg-duty="duty", tg-repeat="duty in vm.assignedTo", ng-class="{blocked: duty.is_blocked}")
|
||||
|
||||
div.title-bar.watching-title(translate="HOME.WATCHING_SECTION")
|
||||
|
||||
section.watching-empty(ng-show="!vm.watching.size")
|
||||
include ../../../svg/hide.svg
|
||||
p(translate="HOME.EMPTY_WATCHING")
|
||||
|
||||
section.watching(ng-show="vm.watching.size")
|
||||
div.duty-single(tg-duty="duty", tg-repeat="duty in vm.watching", ng-class="{blocked: duty.is_blocked}")
|
|
@ -0,0 +1,10 @@
|
|||
#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
|
|
@ -0,0 +1,23 @@
|
|||
DropdownProjectListDirective = (currentUserService, projectsService) ->
|
||||
link = (scope, el, attrs, ctrl) ->
|
||||
scope.vm = {}
|
||||
|
||||
taiga.defineImmutableProperty(scope.vm, "projects", () -> currentUserService.projects.get("recents"))
|
||||
|
||||
scope.vm.newProject = ->
|
||||
projectsService.newProject()
|
||||
|
||||
directive = {
|
||||
templateUrl: "navigation-bar/dropdown-project-list/dropdown-project-list.html"
|
||||
scope: {}
|
||||
link: link
|
||||
}
|
||||
|
||||
return directive
|
||||
|
||||
DropdownProjectListDirective.$inject = [
|
||||
"tgCurrentUserService",
|
||||
"tgProjectsService"
|
||||
]
|
||||
|
||||
angular.module("taigaNavigationBar").directive("tgDropdownProjectList", DropdownProjectListDirective)
|