Merge branch 'main' into feature/ganttastic
# Conflicts: # pnpm-lock.yaml # src/modelTypes/ITask.ts # src/stores/auth.ts # src/types/vue-flatpickr-component.d.ts
This commit is contained in:
commit
b18640d688
|
@ -193,4 +193,15 @@ describe('List View Kanban', () => {
|
||||||
cy.get('.kanban .bucket')
|
cy.get('.kanban .bucket')
|
||||||
.should('not.contain', task.title)
|
.should('not.contain', task.title)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('Shows a button to filter the kanban board', () => {
|
||||||
|
const data = TaskFactory.create(10, {
|
||||||
|
list_id: 1,
|
||||||
|
bucket_id: 1,
|
||||||
|
})
|
||||||
|
cy.visit('/lists/1/kanban')
|
||||||
|
|
||||||
|
cy.get('.list-kanban .filter-container .base-button')
|
||||||
|
.should('exist')
|
||||||
|
})
|
||||||
})
|
})
|
|
@ -128,4 +128,24 @@ describe('Home Page Task Overview', () => {
|
||||||
.last()
|
.last()
|
||||||
.should('contain.text', newTaskTitle)
|
.should('contain.text', newTaskTitle)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('Should show the cta buttons for new list when there are no tasks', () => {
|
||||||
|
TaskFactory.truncate()
|
||||||
|
|
||||||
|
cy.visit('/')
|
||||||
|
|
||||||
|
cy.get('.home.app-content .content')
|
||||||
|
.should('contain.text', 'You can create a new list for your new tasks:')
|
||||||
|
.should('contain.text', 'Or import your lists and tasks from other services into Vikunja:')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should not show the cta buttons for new list when there are tasks', () => {
|
||||||
|
seedTasks()
|
||||||
|
|
||||||
|
cy.visit('/')
|
||||||
|
|
||||||
|
cy.get('.home.app-content .content')
|
||||||
|
.should('not.contain.text', 'You can create a new list for your new tasks:')
|
||||||
|
.should('not.contain.text', 'Or import your lists and tasks from other services into Vikunja:')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -12,15 +12,51 @@ import {LabelTaskFactory} from '../../factories/label_task'
|
||||||
import {BucketFactory} from '../../factories/bucket'
|
import {BucketFactory} from '../../factories/bucket'
|
||||||
|
|
||||||
import '../../support/authenticateUser'
|
import '../../support/authenticateUser'
|
||||||
|
import {TaskAttachmentFactory} from '../../factories/task_attachments'
|
||||||
|
|
||||||
|
function addLabelToTaskAndVerify(labelTitle: string) {
|
||||||
|
cy.get('.task-view .action-buttons .button')
|
||||||
|
.contains('Add Labels')
|
||||||
|
.click()
|
||||||
|
cy.get('.task-view .details.labels-list .multiselect input')
|
||||||
|
.type(labelTitle)
|
||||||
|
cy.get('.task-view .details.labels-list .multiselect .search-results')
|
||||||
|
.children()
|
||||||
|
.first()
|
||||||
|
.click()
|
||||||
|
|
||||||
|
cy.get('.global-notification', { timeout: 4000 })
|
||||||
|
.should('contain', 'Success')
|
||||||
|
cy.get('.task-view .details.labels-list .multiselect .input-wrapper span.tag')
|
||||||
|
.should('exist')
|
||||||
|
.should('contain', labelTitle)
|
||||||
|
}
|
||||||
|
|
||||||
|
function uploadAttachmentAndVerify(taskId: number) {
|
||||||
|
cy.intercept(`${Cypress.env('API_URL')}/tasks/${taskId}/attachments`).as('uploadAttachment')
|
||||||
|
cy.get('.task-view .action-buttons .button')
|
||||||
|
.contains('Add Attachments')
|
||||||
|
.click()
|
||||||
|
cy.get('input[type=file]', {timeout: 1000})
|
||||||
|
.selectFile('cypress/fixtures/image.jpg', {force: true}) // The input is not visible, but on purpose
|
||||||
|
cy.wait('@uploadAttachment')
|
||||||
|
|
||||||
|
cy.get('.attachments .attachments .files a.attachment')
|
||||||
|
.should('exist')
|
||||||
|
}
|
||||||
|
|
||||||
describe('Task', () => {
|
describe('Task', () => {
|
||||||
let namespaces
|
let namespaces
|
||||||
let lists
|
let lists
|
||||||
|
let buckets
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
UserFactory.create(1)
|
UserFactory.create(1)
|
||||||
namespaces = NamespaceFactory.create(1)
|
namespaces = NamespaceFactory.create(1)
|
||||||
lists = ListFactory.create(1)
|
lists = ListFactory.create(1)
|
||||||
|
buckets = BucketFactory.create(1, {
|
||||||
|
list_id: lists[0].id,
|
||||||
|
})
|
||||||
TaskFactory.truncate()
|
TaskFactory.truncate()
|
||||||
UserListFactory.truncate()
|
UserListFactory.truncate()
|
||||||
})
|
})
|
||||||
|
@ -80,6 +116,7 @@ describe('Task', () => {
|
||||||
describe('Task Detail View', () => {
|
describe('Task Detail View', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
TaskCommentFactory.truncate()
|
TaskCommentFactory.truncate()
|
||||||
|
LabelTaskFactory.truncate()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Shows all task details', () => {
|
it('Shows all task details', () => {
|
||||||
|
@ -344,21 +381,31 @@ describe('Task', () => {
|
||||||
|
|
||||||
cy.visit(`/tasks/${tasks[0].id}`)
|
cy.visit(`/tasks/${tasks[0].id}`)
|
||||||
|
|
||||||
cy.get('.task-view .action-buttons .button')
|
addLabelToTaskAndVerify(labels[0].title)
|
||||||
.contains('Add Labels')
|
})
|
||||||
|
|
||||||
|
it('Can add a label to a task and it shows up on the kanban board afterwards', () => {
|
||||||
|
const tasks = TaskFactory.create(1, {
|
||||||
|
id: 1,
|
||||||
|
list_id: lists[0].id,
|
||||||
|
bucket_id: buckets[0].id,
|
||||||
|
})
|
||||||
|
const labels = LabelFactory.create(1)
|
||||||
|
LabelTaskFactory.truncate()
|
||||||
|
|
||||||
|
cy.visit(`/lists/${lists[0].id}/kanban`)
|
||||||
|
|
||||||
|
cy.get('.bucket .task')
|
||||||
|
.contains(tasks[0].title)
|
||||||
.click()
|
.click()
|
||||||
cy.get('.task-view .details.labels-list .multiselect input')
|
|
||||||
.type(labels[0].title)
|
addLabelToTaskAndVerify(labels[0].title)
|
||||||
cy.get('.task-view .details.labels-list .multiselect .search-results')
|
|
||||||
.children()
|
cy.get('.modal-content .close')
|
||||||
.first()
|
|
||||||
.click()
|
.click()
|
||||||
|
|
||||||
cy.get('.global-notification', { timeout: 4000 })
|
cy.get('.bucket .task')
|
||||||
.should('contain', 'Success')
|
.should('contain.text', labels[0].title)
|
||||||
cy.get('.task-view .details.labels-list .multiselect .input-wrapper span.tag')
|
|
||||||
.should('exist')
|
|
||||||
.should('contain', labels[0].title)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Can remove a label from a task', () => {
|
it('Can remove a label from a task', () => {
|
||||||
|
@ -417,5 +464,117 @@ describe('Task', () => {
|
||||||
cy.get('.global-notification')
|
cy.get('.global-notification')
|
||||||
.should('contain', 'Success')
|
.should('contain', 'Success')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('Can set a priority for a task', () => {
|
||||||
|
const tasks = TaskFactory.create(1, {
|
||||||
|
id: 1,
|
||||||
|
})
|
||||||
|
cy.visit(`/tasks/${tasks[0].id}`)
|
||||||
|
|
||||||
|
cy.get('.task-view .action-buttons .button')
|
||||||
|
.contains('Set Priority')
|
||||||
|
.click()
|
||||||
|
cy.get('.task-view .columns.details .column')
|
||||||
|
.contains('Priority')
|
||||||
|
.get('.select select')
|
||||||
|
.select('Urgent')
|
||||||
|
cy.get('.global-notification')
|
||||||
|
.should('contain', 'Success')
|
||||||
|
|
||||||
|
cy.get('.task-view .columns.details .column')
|
||||||
|
.contains('Priority')
|
||||||
|
.get('.select select')
|
||||||
|
.should('have.value', '4')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Can set the progress for a task', () => {
|
||||||
|
const tasks = TaskFactory.create(1, {
|
||||||
|
id: 1,
|
||||||
|
})
|
||||||
|
cy.visit(`/tasks/${tasks[0].id}`)
|
||||||
|
|
||||||
|
cy.get('.task-view .action-buttons .button')
|
||||||
|
.contains('Set Progress')
|
||||||
|
.click()
|
||||||
|
cy.get('.task-view .columns.details .column')
|
||||||
|
.contains('Progress')
|
||||||
|
.get('.select select')
|
||||||
|
.select('50%')
|
||||||
|
cy.get('.global-notification')
|
||||||
|
.should('contain', 'Success')
|
||||||
|
|
||||||
|
cy.wait(200)
|
||||||
|
|
||||||
|
cy.get('.task-view .columns.details .column')
|
||||||
|
.contains('Progress')
|
||||||
|
.get('.select select')
|
||||||
|
.should('be.visible')
|
||||||
|
.should('have.value', '0.5')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Can add an attachment to a task', () => {
|
||||||
|
TaskAttachmentFactory.truncate()
|
||||||
|
const tasks = TaskFactory.create(1, {
|
||||||
|
id: 1,
|
||||||
|
})
|
||||||
|
cy.visit(`/tasks/${tasks[0].id}`)
|
||||||
|
|
||||||
|
uploadAttachmentAndVerify(tasks[0].id)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Can add an attachment to a task and see it appearing on kanban', () => {
|
||||||
|
TaskAttachmentFactory.truncate()
|
||||||
|
const tasks = TaskFactory.create(1, {
|
||||||
|
id: 1,
|
||||||
|
list_id: lists[0].id,
|
||||||
|
bucket_id: buckets[0].id,
|
||||||
|
})
|
||||||
|
const labels = LabelFactory.create(1)
|
||||||
|
LabelTaskFactory.truncate()
|
||||||
|
|
||||||
|
cy.visit(`/lists/${lists[0].id}/kanban`)
|
||||||
|
|
||||||
|
cy.get('.bucket .task')
|
||||||
|
.contains(tasks[0].title)
|
||||||
|
.click()
|
||||||
|
|
||||||
|
uploadAttachmentAndVerify(tasks[0].id)
|
||||||
|
|
||||||
|
cy.get('.modal-content .close')
|
||||||
|
.click()
|
||||||
|
|
||||||
|
cy.get('.bucket .task .footer .icon svg.fa-paperclip')
|
||||||
|
.should('exist')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Can check items off a checklist', () => {
|
||||||
|
const tasks = TaskFactory.create(1, {
|
||||||
|
id: 1,
|
||||||
|
description: `
|
||||||
|
This is a checklist:
|
||||||
|
|
||||||
|
* [ ] one item
|
||||||
|
* [ ] another item
|
||||||
|
* [ ] third item
|
||||||
|
* [ ] fourth item
|
||||||
|
* [x] and this one is already done
|
||||||
|
`,
|
||||||
|
})
|
||||||
|
cy.visit(`/tasks/${tasks[0].id}`)
|
||||||
|
|
||||||
|
cy.get('.task-view .checklist-summary')
|
||||||
|
.should('contain.text', '1 of 5 tasks')
|
||||||
|
cy.get('.editor .content ul > li input[type=checkbox]')
|
||||||
|
.eq(2)
|
||||||
|
.click()
|
||||||
|
|
||||||
|
cy.get('.editor .content ul > li input[type=checkbox]')
|
||||||
|
.eq(2)
|
||||||
|
.should('be.checked')
|
||||||
|
cy.get('.editor .content input[type=checkbox]')
|
||||||
|
.should('have.length', 5)
|
||||||
|
cy.get('.task-view .checklist-summary')
|
||||||
|
.should('contain.text', '2 of 5 tasks')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -55,4 +55,9 @@ context('Login', () => {
|
||||||
|
|
||||||
testAndAssertFailed(fixture)
|
testAndAssertFailed(fixture)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('Should redirect to /login when no user is logged in', () => {
|
||||||
|
cy.visit('/')
|
||||||
|
cy.url().should('include', '/login')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
import {Factory} from '../support/factory'
|
||||||
|
import {formatISO} from 'date-fns'
|
||||||
|
|
||||||
|
export class TaskAttachmentFactory extends Factory {
|
||||||
|
static table = 'task_attachments'
|
||||||
|
|
||||||
|
static factory() {
|
||||||
|
const now = new Date()
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: '{increment}',
|
||||||
|
task_id: 1,
|
||||||
|
file_id: 1,
|
||||||
|
created: formatISO(now),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,7 +6,7 @@
|
||||||
],
|
],
|
||||||
"packageRules": [
|
"packageRules": [
|
||||||
{
|
{
|
||||||
"matchPackageNames": ["netlify-cli"],
|
"matchPackageNames": ["netlify-cli", "happy-dom"],
|
||||||
"extends": ["schedule:weekly"]
|
"extends": ["schedule:weekly"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -44,8 +44,8 @@
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
:shadow="false"
|
:shadow="false"
|
||||||
>
|
>
|
||||||
<img :src="userAvatar" alt="" class="avatar" width="40" height="40"/>
|
<img :src="authStore.avatarUrl" alt="" class="avatar" width="40" height="40"/>
|
||||||
<span class="username">{{ userInfo.name !== '' ? userInfo.name : userInfo.username }}</span>
|
<span class="username">{{ authStore.userDisplayName }}</span>
|
||||||
<span class="icon is-small">
|
<span class="icon is-small">
|
||||||
<icon icon="chevron-down"/>
|
<icon icon="chevron-down"/>
|
||||||
</span>
|
</span>
|
||||||
|
@ -80,7 +80,7 @@
|
||||||
{{ $t('about.title') }}
|
{{ $t('about.title') }}
|
||||||
</dropdown-item>
|
</dropdown-item>
|
||||||
<dropdown-item
|
<dropdown-item
|
||||||
@click="logout()"
|
@click="authStore.logout()"
|
||||||
>
|
>
|
||||||
{{ $t('user.auth.logout') }}
|
{{ $t('user.auth.logout') }}
|
||||||
</dropdown-item>
|
</dropdown-item>
|
||||||
|
@ -117,8 +117,6 @@ const canWriteCurrentList = computed(() => baseStore.currentList.maxRight > Righ
|
||||||
const menuActive = computed(() => baseStore.menuActive)
|
const menuActive = computed(() => baseStore.menuActive)
|
||||||
|
|
||||||
const authStore = useAuthStore()
|
const authStore = useAuthStore()
|
||||||
const userInfo = computed(() => authStore.info)
|
|
||||||
const userAvatar = computed(() => authStore.avatarUrl)
|
|
||||||
|
|
||||||
const configStore = useConfigStore()
|
const configStore = useConfigStore()
|
||||||
const imprintUrl = computed(() => configStore.legal.imprintUrl)
|
const imprintUrl = computed(() => configStore.legal.imprintUrl)
|
||||||
|
@ -136,10 +134,6 @@ onMounted(async () => {
|
||||||
listTitle.value.style.setProperty('--nav-username-width', `${usernameWidth}px`)
|
listTitle.value.style.setProperty('--nav-username-width', `${usernameWidth}px`)
|
||||||
})
|
})
|
||||||
|
|
||||||
function logout() {
|
|
||||||
authStore.logout()
|
|
||||||
}
|
|
||||||
|
|
||||||
function openQuickActions() {
|
function openQuickActions() {
|
||||||
baseStore.setQuickActionsActive(true)
|
baseStore.setQuickActionsActive(true)
|
||||||
}
|
}
|
||||||
|
|
|
@ -285,9 +285,9 @@ function handleCheckboxClick(e: Event) {
|
||||||
console.debug('no index found')
|
console.debug('no index found')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
console.debug(index, text.value.slice(index, 9))
|
const listPrefix = text.value.substring(index, index + 1)
|
||||||
|
|
||||||
const listPrefix = text.value.slice(index, 1)
|
console.debug({index, listPrefix, checked, text: text.value})
|
||||||
|
|
||||||
text.value = replaceAt(text.value, index, `${listPrefix} ${checked ? '[x]' : '[ ]'} `)
|
text.value = replaceAt(text.value, index, `${listPrefix} ${checked ? '[x]' : '[ ]'} `)
|
||||||
bubble()
|
bubble()
|
||||||
|
|
|
@ -55,13 +55,13 @@
|
||||||
>
|
>
|
||||||
{{ $t('menu.archive') }}
|
{{ $t('menu.archive') }}
|
||||||
</dropdown-item>
|
</dropdown-item>
|
||||||
<task-subscription
|
<Subscription
|
||||||
class="has-no-shadow"
|
class="has-no-shadow"
|
||||||
:is-button="false"
|
:is-button="false"
|
||||||
entity="list"
|
entity="list"
|
||||||
:entity-id="list.id"
|
:entity-id="list.id"
|
||||||
:model-value="list.subscription"
|
:model-value="list.subscription"
|
||||||
@update:model-value="sub => subscription = sub"
|
@update:model-value="setSubscriptionInStore"
|
||||||
type="dropdown"
|
type="dropdown"
|
||||||
/>
|
/>
|
||||||
<dropdown-item
|
<dropdown-item
|
||||||
|
@ -81,10 +81,12 @@ import {ref, computed, watchEffect, type PropType} from 'vue'
|
||||||
import {isSavedFilter} from '@/helpers/savedFilter'
|
import {isSavedFilter} from '@/helpers/savedFilter'
|
||||||
import Dropdown from '@/components/misc/dropdown.vue'
|
import Dropdown from '@/components/misc/dropdown.vue'
|
||||||
import DropdownItem from '@/components/misc/dropdown-item.vue'
|
import DropdownItem from '@/components/misc/dropdown-item.vue'
|
||||||
import TaskSubscription from '@/components/misc/subscription.vue'
|
import Subscription from '@/components/misc/subscription.vue'
|
||||||
import type {IList} from '@/modelTypes/IList'
|
import type {IList} from '@/modelTypes/IList'
|
||||||
import type {ISubscription} from '@/modelTypes/ISubscription'
|
import type {ISubscription} from '@/modelTypes/ISubscription'
|
||||||
import {useConfigStore} from '@/stores/config'
|
import {useConfigStore} from '@/stores/config'
|
||||||
|
import {useListStore} from '@/stores/lists'
|
||||||
|
import {useNamespaceStore} from '@/stores/namespaces'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
list: {
|
list: {
|
||||||
|
@ -93,6 +95,8 @@ const props = defineProps({
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const listStore = useListStore()
|
||||||
|
const namespaceStore = useNamespaceStore()
|
||||||
const subscription = ref<ISubscription | null>(null)
|
const subscription = ref<ISubscription | null>(null)
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
subscription.value = props.list.subscription ?? null
|
subscription.value = props.list.subscription ?? null
|
||||||
|
@ -100,4 +104,14 @@ watchEffect(() => {
|
||||||
|
|
||||||
const configStore = useConfigStore()
|
const configStore = useConfigStore()
|
||||||
const backgroundsEnabled = computed(() => configStore.enabledBackgroundProviders?.length > 0)
|
const backgroundsEnabled = computed(() => configStore.enabledBackgroundProviders?.length > 0)
|
||||||
|
|
||||||
|
function setSubscriptionInStore(sub: ISubscription) {
|
||||||
|
subscription.value = sub
|
||||||
|
const updatedList = {
|
||||||
|
...props.list,
|
||||||
|
subscription: sub,
|
||||||
|
}
|
||||||
|
listStore.setList(updatedList)
|
||||||
|
namespaceStore.setListInNamespaceById(updatedList)
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -210,6 +210,7 @@ import ListService from '@/services/list'
|
||||||
import NamespaceService from '@/services/namespace'
|
import NamespaceService from '@/services/namespace'
|
||||||
import EditLabels from '@/components/tasks/partials/editLabels.vue'
|
import EditLabels from '@/components/tasks/partials/editLabels.vue'
|
||||||
|
|
||||||
|
import {dateIsValid, formatISO} from '@/helpers/time/formatDate'
|
||||||
import {objectToSnakeCase} from '@/helpers/case'
|
import {objectToSnakeCase} from '@/helpers/case'
|
||||||
import {getDefaultParams} from '@/composables/taskList'
|
import {getDefaultParams} from '@/composables/taskList'
|
||||||
import {camelCase} from 'camel-case'
|
import {camelCase} from 'camel-case'
|
||||||
|
@ -391,7 +392,14 @@ export default defineComponent({
|
||||||
this.params.filter_value.push(dateTo)
|
this.params.filter_value.push(dateTo)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.filters[camelCase(filterName)] = {dateFrom, dateTo}
|
this.filters[camelCase(filterName)] = {
|
||||||
|
// Passing the dates as string values avoids an endless loop between values changing
|
||||||
|
// in the datepicker (bubbling up to here) and changing here and bubbling down to the
|
||||||
|
// datepicker (because there's a new date instance every time this function gets called).
|
||||||
|
// See https://kolaente.dev/vikunja/frontend/issues/2384
|
||||||
|
dateFrom: dateIsValid(dateFrom) ? formatISO(dateFrom) : dateFrom,
|
||||||
|
dateTo: dateIsValid(dateTo) ? formatISO(dateTo) : dateTo,
|
||||||
|
}
|
||||||
this.change()
|
this.change()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -511,12 +519,12 @@ export default defineComponent({
|
||||||
if (typeof this.filters[filterName] === 'undefined' || this.filters[filterName] === '') {
|
if (typeof this.filters[filterName] === 'undefined' || this.filters[filterName] === '') {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't load things if we already have something loaded.
|
// Don't load things if we already have something loaded.
|
||||||
// This is not the most ideal solution because it prevents a re-population when filters are changed
|
// This is not the most ideal solution because it prevents a re-population when filters are changed
|
||||||
// from the outside. It is still fine because we're not changing them from the outside, other than
|
// from the outside. It is still fine because we're not changing them from the outside, other than
|
||||||
// loading them initially.
|
// loading them initially.
|
||||||
if(this[kind].length > 0) {
|
if (this[kind].length > 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
>
|
>
|
||||||
<div class="p-4">
|
<div class="p-4">
|
||||||
<slot />
|
<slot/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
|
@ -30,10 +30,12 @@
|
||||||
{{ $t('misc.cancel') }}
|
{{ $t('misc.cancel') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
<x-button
|
<x-button
|
||||||
|
v-if="hasPrimaryAction"
|
||||||
variant="primary"
|
variant="primary"
|
||||||
@click.prevent.stop="primary()"
|
@click.prevent.stop="primary()"
|
||||||
:icon="primaryIcon"
|
:icon="primaryIcon"
|
||||||
:disabled="primaryDisabled || loading"
|
:disabled="primaryDisabled || loading"
|
||||||
|
class="ml-2"
|
||||||
>
|
>
|
||||||
{{ primaryLabel || $t('misc.create') }}
|
{{ primaryLabel || $t('misc.create') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
|
@ -60,6 +62,10 @@ defineProps({
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
hasPrimaryAction: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
tertiary: {
|
tertiary: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
|
|
|
@ -61,7 +61,7 @@ const route = useRoute()
|
||||||
|
|
||||||
const baseStore = useBaseStore()
|
const baseStore = useBaseStore()
|
||||||
|
|
||||||
const ready = ref(false)
|
const ready = computed(() => baseStore.ready)
|
||||||
const online = useOnline()
|
const online = useOnline()
|
||||||
|
|
||||||
const error = ref('')
|
const error = ref('')
|
||||||
|
@ -70,11 +70,11 @@ const showLoading = computed(() => !ready.value && error.value === '')
|
||||||
async function load() {
|
async function load() {
|
||||||
try {
|
try {
|
||||||
await baseStore.loadApp()
|
await baseStore.loadApp()
|
||||||
const redirectTo = getAuthForRoute(route)
|
baseStore.setReady(true)
|
||||||
|
const redirectTo = await getAuthForRoute(route)
|
||||||
if (typeof redirectTo !== 'undefined') {
|
if (typeof redirectTo !== 'undefined') {
|
||||||
await router.push(redirectTo)
|
await router.push(redirectTo)
|
||||||
}
|
}
|
||||||
ready.value = true
|
|
||||||
} catch (e: unknown) {
|
} catch (e: unknown) {
|
||||||
error.value = String(e)
|
error.value = String(e)
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,17 +69,38 @@ const emit = defineEmits(['update:modelValue'])
|
||||||
const subscriptionService = shallowRef(new SubscriptionService())
|
const subscriptionService = shallowRef(new SubscriptionService())
|
||||||
|
|
||||||
const {t} = useI18n({useScope: 'global'})
|
const {t} = useI18n({useScope: 'global'})
|
||||||
|
|
||||||
const tooltipText = computed(() => {
|
const tooltipText = computed(() => {
|
||||||
if (disabled.value) {
|
if (disabled.value) {
|
||||||
return t('task.subscription.subscribedThroughParent', {
|
if (props.entity === 'list' && subscriptionEntity.value === 'namespace') {
|
||||||
entity: props.entity,
|
return t('task.subscription.subscribedListThroughParentNamespace')
|
||||||
parent: subscriptionEntity.value,
|
}
|
||||||
})
|
if (props.entity === 'task' && subscriptionEntity.value === 'namespace') {
|
||||||
|
return t('task.subscription.subscribedTaskThroughParentNamespace')
|
||||||
|
}
|
||||||
|
if (props.entity === 'task' && subscriptionEntity.value === 'list') {
|
||||||
|
return t('task.subscription.subscribedTaskThroughParentList')
|
||||||
|
}
|
||||||
|
|
||||||
|
return ''
|
||||||
}
|
}
|
||||||
|
|
||||||
return props.modelValue !== null ?
|
switch (props.entity) {
|
||||||
t('task.subscription.subscribed', {entity: props.entity}) :
|
case 'namespace':
|
||||||
t('task.subscription.notSubscribed', {entity: props.entity})
|
return props.modelValue !== null ?
|
||||||
|
t('task.subscription.subscribedNamespace') :
|
||||||
|
t('task.subscription.notSubscribedNamespace')
|
||||||
|
case 'list':
|
||||||
|
return props.modelValue !== null ?
|
||||||
|
t('task.subscription.subscribedList') :
|
||||||
|
t('task.subscription.notSubscribedList')
|
||||||
|
case 'task':
|
||||||
|
return props.modelValue !== null ?
|
||||||
|
t('task.subscription.subscribedTask') :
|
||||||
|
t('task.subscription.notSubscribedTask')
|
||||||
|
}
|
||||||
|
|
||||||
|
return ''
|
||||||
})
|
})
|
||||||
|
|
||||||
const buttonText = computed(() => props.modelValue ? t('task.subscription.unsubscribe') : t('task.subscription.subscribe'))
|
const buttonText = computed(() => props.modelValue ? t('task.subscription.unsubscribe') : t('task.subscription.subscribe'))
|
||||||
|
@ -105,7 +126,20 @@ async function subscribe() {
|
||||||
})
|
})
|
||||||
await subscriptionService.value.create(subscription)
|
await subscriptionService.value.create(subscription)
|
||||||
emit('update:modelValue', subscription)
|
emit('update:modelValue', subscription)
|
||||||
success({message: t('task.subscription.subscribeSuccess', {entity: props.entity})})
|
|
||||||
|
let message = ''
|
||||||
|
switch (props.entity) {
|
||||||
|
case 'namespace':
|
||||||
|
message = t('task.subscription.subscribeSuccessNamespace')
|
||||||
|
break
|
||||||
|
case 'list':
|
||||||
|
message = t('task.subscription.subscribeSuccessList')
|
||||||
|
break
|
||||||
|
case 'task':
|
||||||
|
message = t('task.subscription.subscribeSuccessTask')
|
||||||
|
break
|
||||||
|
}
|
||||||
|
success({message})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function unsubscribe() {
|
async function unsubscribe() {
|
||||||
|
@ -115,6 +149,19 @@ async function unsubscribe() {
|
||||||
})
|
})
|
||||||
await subscriptionService.value.delete(subscription)
|
await subscriptionService.value.delete(subscription)
|
||||||
emit('update:modelValue', null)
|
emit('update:modelValue', null)
|
||||||
success({message: t('task.subscription.unsubscribeSuccess', {entity: props.entity})})
|
|
||||||
|
let message = ''
|
||||||
|
switch (props.entity) {
|
||||||
|
case 'namespace':
|
||||||
|
message = t('task.subscription.unsubscribeSuccessNamespace')
|
||||||
|
break
|
||||||
|
case 'list':
|
||||||
|
message = t('task.subscription.unsubscribeSuccessList')
|
||||||
|
break
|
||||||
|
case 'task':
|
||||||
|
message = t('task.subscription.unsubscribeSuccessTask')
|
||||||
|
break
|
||||||
|
}
|
||||||
|
success({message})
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -33,14 +33,13 @@
|
||||||
>
|
>
|
||||||
{{ $t('menu.archive') }}
|
{{ $t('menu.archive') }}
|
||||||
</dropdown-item>
|
</dropdown-item>
|
||||||
<task-subscription
|
<Subscription
|
||||||
v-if="subscription"
|
|
||||||
class="has-no-shadow"
|
class="has-no-shadow"
|
||||||
:is-button="false"
|
:is-button="false"
|
||||||
entity="namespace"
|
entity="namespace"
|
||||||
:entity-id="namespace.id"
|
:entity-id="namespace.id"
|
||||||
:model-value="subscription"
|
:model-value="subscription"
|
||||||
@update:model-value="sub => subscription = sub"
|
@update:model-value="setSubscriptionInStore"
|
||||||
type="dropdown"
|
type="dropdown"
|
||||||
/>
|
/>
|
||||||
<dropdown-item
|
<dropdown-item
|
||||||
|
@ -59,9 +58,10 @@ import {ref, onMounted, type PropType} from 'vue'
|
||||||
|
|
||||||
import Dropdown from '@/components/misc/dropdown.vue'
|
import Dropdown from '@/components/misc/dropdown.vue'
|
||||||
import DropdownItem from '@/components/misc/dropdown-item.vue'
|
import DropdownItem from '@/components/misc/dropdown-item.vue'
|
||||||
import TaskSubscription from '@/components/misc/subscription.vue'
|
import Subscription from '@/components/misc/subscription.vue'
|
||||||
import type {INamespace} from '@/modelTypes/INamespace'
|
import type {INamespace} from '@/modelTypes/INamespace'
|
||||||
import type {ISubscription} from '@/modelTypes/ISubscription'
|
import type {ISubscription} from '@/modelTypes/ISubscription'
|
||||||
|
import {useNamespaceStore} from '@/stores/namespaces'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
namespace: {
|
namespace: {
|
||||||
|
@ -70,8 +70,20 @@ const props = defineProps({
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const namespaceStore = useNamespaceStore()
|
||||||
|
|
||||||
const subscription = ref<ISubscription | null>(null)
|
const subscription = ref<ISubscription | null>(null)
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
subscription.value = props.namespace.subscription
|
subscription.value = props.namespace.subscription
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function setSubscriptionInStore(sub: ISubscription) {
|
||||||
|
subscription.value = sub
|
||||||
|
namespaceStore.setNamespaces([
|
||||||
|
{
|
||||||
|
...props.namespace,
|
||||||
|
subscription: sub,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
<input
|
<input
|
||||||
v-if="editEnabled"
|
v-if="editEnabled"
|
||||||
:disabled="attachmentService.loading || undefined"
|
:disabled="loading || undefined"
|
||||||
@change="uploadNewAttachment()"
|
@change="uploadNewAttachment()"
|
||||||
id="files"
|
id="files"
|
||||||
multiple
|
multiple
|
||||||
|
@ -35,7 +35,15 @@
|
||||||
:key="a.id"
|
:key="a.id"
|
||||||
@click="viewOrDownload(a)"
|
@click="viewOrDownload(a)"
|
||||||
>
|
>
|
||||||
<div class="filename">{{ a.file.name }}</div>
|
<div class="filename">
|
||||||
|
{{ a.file.name }}
|
||||||
|
<span
|
||||||
|
v-if="task.coverImageAttachmentId === a.id"
|
||||||
|
class="is-task-cover"
|
||||||
|
>
|
||||||
|
{{ $t('task.attachment.usedAsCover') }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<p class="attachment-info-meta">
|
<p class="attachment-info-meta">
|
||||||
<i18n-t keypath="task.attachment.createdBy" scope="global">
|
<i18n-t keypath="task.attachment.createdBy" scope="global">
|
||||||
|
@ -78,6 +86,17 @@
|
||||||
>
|
>
|
||||||
{{ $t('misc.delete') }}
|
{{ $t('misc.delete') }}
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
|
<BaseButton
|
||||||
|
v-if="editEnabled"
|
||||||
|
class="attachment-info-meta-button"
|
||||||
|
@click.prevent.stop="setCoverImage(task.coverImageAttachmentId === a.id ? null : a)"
|
||||||
|
>
|
||||||
|
{{
|
||||||
|
task.coverImageAttachmentId === a.id
|
||||||
|
? $t('task.attachment.unsetAsCover')
|
||||||
|
: $t('task.attachment.setAsCover')
|
||||||
|
}}
|
||||||
|
</BaseButton>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
|
@ -85,7 +104,7 @@
|
||||||
|
|
||||||
<x-button
|
<x-button
|
||||||
v-if="editEnabled"
|
v-if="editEnabled"
|
||||||
:disabled="attachmentService.loading"
|
:disabled="loading"
|
||||||
@click="filesRef?.click()"
|
@click="filesRef?.click()"
|
||||||
class="mb-4"
|
class="mb-4"
|
||||||
icon="cloud-upload-alt"
|
icon="cloud-upload-alt"
|
||||||
|
@ -118,7 +137,7 @@
|
||||||
<template #header>
|
<template #header>
|
||||||
<span>{{ $t('task.attachment.delete') }}</span>
|
<span>{{ $t('task.attachment.delete') }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #text>
|
<template #text>
|
||||||
<p>
|
<p>
|
||||||
{{ $t('task.attachment.deleteText1', {filename: attachmentToDelete.file.name}) }}<br/>
|
{{ $t('task.attachment.deleteText1', {filename: attachmentToDelete.file.name}) }}<br/>
|
||||||
|
@ -138,13 +157,14 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {ref, shallowReactive, computed, type PropType} from 'vue'
|
import {ref, shallowReactive, computed} from 'vue'
|
||||||
import {useDropZone} from '@vueuse/core'
|
import {useDropZone} from '@vueuse/core'
|
||||||
|
|
||||||
import User from '@/components/misc/user.vue'
|
import User from '@/components/misc/user.vue'
|
||||||
import BaseButton from '@/components/base/BaseButton.vue'
|
import BaseButton from '@/components/base/BaseButton.vue'
|
||||||
|
|
||||||
import AttachmentService from '@/services/attachment'
|
import AttachmentService from '@/services/attachment'
|
||||||
|
import {SUPPORTED_IMAGE_SUFFIX} from '@/models/attachment'
|
||||||
import type AttachmentModel from '@/models/attachment'
|
import type AttachmentModel from '@/models/attachment'
|
||||||
import type {IAttachment} from '@/modelTypes/IAttachment'
|
import type {IAttachment} from '@/modelTypes/IAttachment'
|
||||||
import type {ITask} from '@/modelTypes/ITask'
|
import type {ITask} from '@/modelTypes/ITask'
|
||||||
|
@ -155,38 +175,44 @@ import {uploadFiles, generateAttachmentUrl} from '@/helpers/attachments'
|
||||||
import {getHumanSize} from '@/helpers/getHumanSize'
|
import {getHumanSize} from '@/helpers/getHumanSize'
|
||||||
import {useCopyToClipboard} from '@/composables/useCopyToClipboard'
|
import {useCopyToClipboard} from '@/composables/useCopyToClipboard'
|
||||||
import {error, success} from '@/message'
|
import {error, success} from '@/message'
|
||||||
|
import {useTaskStore} from '@/stores/tasks'
|
||||||
|
import {useI18n} from 'vue-i18n'
|
||||||
|
|
||||||
const props = defineProps({
|
const taskStore = useTaskStore()
|
||||||
taskId: {
|
const {t} = useI18n({useScope: 'global'})
|
||||||
type: Number as PropType<ITask['id']>,
|
|
||||||
required: true,
|
const props = withDefaults(defineProps<{
|
||||||
},
|
task: ITask,
|
||||||
initialAttachments: {
|
initialAttachments?: IAttachment[],
|
||||||
type: Array,
|
editEnabled: boolean,
|
||||||
},
|
}>(), {
|
||||||
editEnabled: {
|
editEnabled: true,
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// FIXME: this should go through the store
|
||||||
|
const emit = defineEmits(['task-changed'])
|
||||||
|
|
||||||
const attachmentService = shallowReactive(new AttachmentService())
|
const attachmentService = shallowReactive(new AttachmentService())
|
||||||
|
|
||||||
const attachmentStore = useAttachmentStore()
|
const attachmentStore = useAttachmentStore()
|
||||||
const attachments = computed(() => attachmentStore.attachments)
|
const attachments = computed(() => attachmentStore.attachments)
|
||||||
|
|
||||||
|
const loading = computed(() => attachmentService.loading || taskStore.isLoading)
|
||||||
|
|
||||||
function onDrop(files: File[] | null) {
|
function onDrop(files: File[] | null) {
|
||||||
if (files && files.length !== 0) {
|
if (files && files.length !== 0) {
|
||||||
uploadFilesToTask(files)
|
uploadFilesToTask(files)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const { isOverDropZone } = useDropZone(document, onDrop)
|
const {isOverDropZone} = useDropZone(document, onDrop)
|
||||||
|
|
||||||
function downloadAttachment(attachment: IAttachment) {
|
function downloadAttachment(attachment: IAttachment) {
|
||||||
attachmentService.download(attachment)
|
attachmentService.download(attachment)
|
||||||
}
|
}
|
||||||
|
|
||||||
const filesRef = ref<HTMLInputElement | null>(null)
|
const filesRef = ref<HTMLInputElement | null>(null)
|
||||||
|
|
||||||
function uploadNewAttachment() {
|
function uploadNewAttachment() {
|
||||||
const files = filesRef.value?.files
|
const files = filesRef.value?.files
|
||||||
|
|
||||||
|
@ -198,7 +224,7 @@ function uploadNewAttachment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function uploadFilesToTask(files: File[] | FileList) {
|
function uploadFilesToTask(files: File[] | FileList) {
|
||||||
uploadFiles(attachmentService, props.taskId, files)
|
uploadFiles(attachmentService, props.task.id, files)
|
||||||
}
|
}
|
||||||
|
|
||||||
const attachmentToDelete = ref<AttachmentModel | null>(null)
|
const attachmentToDelete = ref<AttachmentModel | null>(null)
|
||||||
|
@ -217,16 +243,15 @@ async function deleteAttachment() {
|
||||||
attachmentStore.removeById(attachmentToDelete.value.id)
|
attachmentStore.removeById(attachmentToDelete.value.id)
|
||||||
success(r)
|
success(r)
|
||||||
setAttachmentToDelete(null)
|
setAttachmentToDelete(null)
|
||||||
} catch(e) {
|
} catch (e) {
|
||||||
error(e)
|
error(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const attachmentImageBlobUrl = ref<string | null>(null)
|
const attachmentImageBlobUrl = ref<string | null>(null)
|
||||||
const SUPPORTED_SUFFIX = ['.jpg', '.png', '.bmp', '.gif']
|
|
||||||
|
|
||||||
async function viewOrDownload(attachment: AttachmentModel) {
|
async function viewOrDownload(attachment: AttachmentModel) {
|
||||||
if (SUPPORTED_SUFFIX.some((suffix) => attachment.file.name.endsWith(suffix)) ) {
|
if (SUPPORTED_IMAGE_SUFFIX.some((suffix) => attachment.file.name.endsWith(suffix))) {
|
||||||
attachmentImageBlobUrl.value = await attachmentService.getBlobUrl(attachment)
|
attachmentImageBlobUrl.value = await attachmentService.getBlobUrl(attachment)
|
||||||
} else {
|
} else {
|
||||||
downloadAttachment(attachment)
|
downloadAttachment(attachment)
|
||||||
|
@ -234,8 +259,15 @@ async function viewOrDownload(attachment: AttachmentModel) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const copy = useCopyToClipboard()
|
const copy = useCopyToClipboard()
|
||||||
|
|
||||||
function copyUrl(attachment: IAttachment) {
|
function copyUrl(attachment: IAttachment) {
|
||||||
copy(generateAttachmentUrl(props.taskId, attachment.id))
|
copy(generateAttachmentUrl(props.task.id, attachment.id))
|
||||||
|
}
|
||||||
|
|
||||||
|
async function setCoverImage(attachment: IAttachment | null) {
|
||||||
|
const task = await taskStore.setCoverImage(props.task, attachment)
|
||||||
|
emit('task-changed', task)
|
||||||
|
success({message: t('task.attachment.successfullyChangedCoverImage')})
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -316,7 +348,7 @@ function copyUrl(attachment: IAttachment) {
|
||||||
height: auto;
|
height: auto;
|
||||||
text-shadow: var(--shadow-md);
|
text-shadow: var(--shadow-md);
|
||||||
animation: bounce 2s infinite;
|
animation: bounce 2s infinite;
|
||||||
|
|
||||||
@media (prefers-reduced-motion: reduce) {
|
@media (prefers-reduced-motion: reduce) {
|
||||||
animation: none;
|
animation: none;
|
||||||
}
|
}
|
||||||
|
@ -338,7 +370,7 @@ function copyUrl(attachment: IAttachment) {
|
||||||
.attachment-info-meta {
|
.attachment-info-meta {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
:deep(.user) {
|
:deep(.user) {
|
||||||
display: flex !important;
|
display: flex !important;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -348,7 +380,7 @@ function copyUrl(attachment: IAttachment) {
|
||||||
@media screen and (max-width: $mobile) {
|
@media screen and (max-width: $mobile) {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
|
|
||||||
:deep(.user) {
|
:deep(.user) {
|
||||||
margin: .5rem 0;
|
margin: .5rem 0;
|
||||||
}
|
}
|
||||||
|
@ -394,5 +426,13 @@ function copyUrl(attachment: IAttachment) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.is-task-cover {
|
||||||
|
background: var(--primary);
|
||||||
|
color: var(--white);
|
||||||
|
padding: .25rem .35rem;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: .75rem;
|
||||||
|
}
|
||||||
|
|
||||||
@include modal-transition();
|
@include modal-transition();
|
||||||
</style>
|
</style>
|
|
@ -1,34 +1,29 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<Multiselect
|
||||||
tabindex="-1"
|
:loading="listUserService.loading"
|
||||||
@focus="focus"
|
:placeholder="$t('task.assignee.placeholder')"
|
||||||
|
:multiple="true"
|
||||||
|
@search="findUser"
|
||||||
|
:search-results="foundUsers"
|
||||||
|
@select="addAssignee"
|
||||||
|
label="name"
|
||||||
|
:select-placeholder="$t('task.assignee.selectPlaceholder')"
|
||||||
|
v-model="assignees"
|
||||||
|
ref="userSearchInputRef"
|
||||||
>
|
>
|
||||||
<Multiselect
|
<template #tag="{item: user}">
|
||||||
:loading="listUserService.loading"
|
<span class="assignee">
|
||||||
:placeholder="$t('task.assignee.placeholder')"
|
<user :avatar-size="32" :show-username="false" :user="user"/>
|
||||||
:multiple="true"
|
<BaseButton @click="removeAssignee(user)" class="remove-assignee" v-if="!disabled">
|
||||||
@search="findUser"
|
<icon icon="times"/>
|
||||||
:search-results="foundUsers"
|
</BaseButton>
|
||||||
@select="addAssignee"
|
</span>
|
||||||
label="name"
|
</template>
|
||||||
:select-placeholder="$t('task.assignee.selectPlaceholder')"
|
</Multiselect>
|
||||||
v-model="assignees"
|
|
||||||
ref="multiselect"
|
|
||||||
>
|
|
||||||
<template #tag="{item: user}">
|
|
||||||
<span class="assignee">
|
|
||||||
<user :avatar-size="32" :show-username="false" :user="user"/>
|
|
||||||
<BaseButton @click="removeAssignee(user)" class="remove-assignee" v-if="!disabled">
|
|
||||||
<icon icon="times"/>
|
|
||||||
</BaseButton>
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
</Multiselect>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {ref, shallowReactive, watch, type PropType} from 'vue'
|
import {ref, shallowReactive, watch, nextTick, type PropType} from 'vue'
|
||||||
import {useI18n} from 'vue-i18n'
|
import {useI18n} from 'vue-i18n'
|
||||||
|
|
||||||
import User from '@/components/misc/user.vue'
|
import User from '@/components/misc/user.vue'
|
||||||
|
@ -41,32 +36,34 @@ import {success} from '@/message'
|
||||||
import {useTaskStore} from '@/stores/tasks'
|
import {useTaskStore} from '@/stores/tasks'
|
||||||
|
|
||||||
import type {IUser} from '@/modelTypes/IUser'
|
import type {IUser} from '@/modelTypes/IUser'
|
||||||
|
import {getDisplayName} from '@/models/user'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
taskId: {
|
taskId: {
|
||||||
type: Number,
|
type: Number,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
listId: {
|
listId: {
|
||||||
type: Number,
|
type: Number,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
disabled: {
|
disabled: {
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
modelValue: {
|
modelValue: {
|
||||||
type: Array as PropType<IUser[]>,
|
type: Array as PropType<IUser[]>,
|
||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
const emit = defineEmits(['update:modelValue'])
|
const emit = defineEmits(['update:modelValue'])
|
||||||
|
|
||||||
const taskStore = useTaskStore()
|
const taskStore = useTaskStore()
|
||||||
const {t} = useI18n({useScope: 'global'})
|
const {t} = useI18n({useScope: 'global'})
|
||||||
|
|
||||||
const listUserService = shallowReactive(new ListUserService())
|
const listUserService = shallowReactive(new ListUserService())
|
||||||
const foundUsers = ref([])
|
const foundUsers = ref<IUser[]>([])
|
||||||
const assignees = ref<IUser[]>([])
|
const assignees = ref<IUser[]>([])
|
||||||
|
let isAdding = false
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.modelValue,
|
() => props.modelValue,
|
||||||
|
@ -80,9 +77,19 @@ watch(
|
||||||
)
|
)
|
||||||
|
|
||||||
async function addAssignee(user: IUser) {
|
async function addAssignee(user: IUser) {
|
||||||
await taskStore.addAssignee({user: user, taskId: props.taskId})
|
if (isAdding) {
|
||||||
emit('update:modelValue', assignees.value)
|
return
|
||||||
success({message: t('task.assignee.assignSuccess')})
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
nextTick(() => isAdding = true)
|
||||||
|
|
||||||
|
await taskStore.addAssignee({user: user, taskId: props.taskId})
|
||||||
|
emit('update:modelValue', assignees.value)
|
||||||
|
success({message: t('task.assignee.assignSuccess')})
|
||||||
|
} finally {
|
||||||
|
nextTick(() => isAdding = false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function removeAssignee(user: IUser) {
|
async function removeAssignee(user: IUser) {
|
||||||
|
@ -103,13 +110,14 @@ async function findUser(query: string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await listUserService.getAll({listId: props.listId}, {s: query})
|
const response = await listUserService.getAll({listId: props.listId}, {s: query}) as IUser[]
|
||||||
|
|
||||||
// Filter the results to not include users who are already assigned
|
// Filter the results to not include users who are already assigned
|
||||||
foundUsers.value = response.filter(({id}) => !includesById(assignees.value, id))
|
foundUsers.value = response
|
||||||
|
.filter(({id}) => !includesById(assignees.value, id))
|
||||||
.map(u => {
|
.map(u => {
|
||||||
// Users may not have a display name set, so we fall back on the username in that case
|
// Users may not have a display name set, so we fall back on the username in that case
|
||||||
u.name = u.name === '' ? u.username : u.name
|
u.name = getDisplayName(u)
|
||||||
return u
|
return u
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -117,11 +125,6 @@ async function findUser(query: string) {
|
||||||
function clearAllFoundUsers() {
|
function clearAllFoundUsers() {
|
||||||
foundUsers.value = []
|
foundUsers.value = []
|
||||||
}
|
}
|
||||||
|
|
||||||
const multiselect = ref()
|
|
||||||
function focus() {
|
|
||||||
multiselect.value.focus()
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
|
@ -11,62 +11,70 @@
|
||||||
@click.ctrl="() => toggleTaskDone(task)"
|
@click.ctrl="() => toggleTaskDone(task)"
|
||||||
@click.meta="() => toggleTaskDone(task)"
|
@click.meta="() => toggleTaskDone(task)"
|
||||||
>
|
>
|
||||||
<span class="task-id">
|
<img
|
||||||
<Done class="kanban-card__done" :is-done="task.done" variant="small"/>
|
v-if="coverImageBlobUrl"
|
||||||
<template v-if="task.identifier === ''">
|
:src="coverImageBlobUrl"
|
||||||
#{{ task.index }}
|
alt=""
|
||||||
</template>
|
class="cover-image"
|
||||||
<template v-else>
|
/>
|
||||||
{{ task.identifier }}
|
<div class="p-2">
|
||||||
</template>
|
<span class="task-id">
|
||||||
</span>
|
<Done class="kanban-card__done" :is-done="task.done" variant="small"/>
|
||||||
<span
|
<template v-if="task.identifier === ''">
|
||||||
:class="{'overdue': task.dueDate <= new Date() && !task.done}"
|
#{{ task.index }}
|
||||||
class="due-date"
|
</template>
|
||||||
v-if="task.dueDate > 0"
|
<template v-else>
|
||||||
v-tooltip="formatDateLong(task.dueDate)">
|
{{ task.identifier }}
|
||||||
<span class="icon">
|
</template>
|
||||||
<icon :icon="['far', 'calendar-alt']"/>
|
|
||||||
</span>
|
</span>
|
||||||
<time :datetime="formatISO(task.dueDate)">
|
<span
|
||||||
{{ formatDateSince(task.dueDate) }}
|
:class="{'overdue': task.dueDate <= new Date() && !task.done}"
|
||||||
</time>
|
class="due-date"
|
||||||
</span>
|
v-if="task.dueDate > 0"
|
||||||
<h3>{{ task.title }}</h3>
|
v-tooltip="formatDateLong(task.dueDate)">
|
||||||
<progress
|
<span class="icon">
|
||||||
class="progress is-small"
|
<icon :icon="['far', 'calendar-alt']"/>
|
||||||
v-if="task.percentDone > 0"
|
</span>
|
||||||
:value="task.percentDone * 100" max="100">
|
<time :datetime="formatISO(task.dueDate)">
|
||||||
{{ task.percentDone * 100 }}%
|
{{ formatDateSince(task.dueDate) }}
|
||||||
</progress>
|
</time>
|
||||||
<div class="footer">
|
</span>
|
||||||
<labels :labels="task.labels"/>
|
<h3>{{ task.title }}</h3>
|
||||||
<priority-label :priority="task.priority" :done="task.done"/>
|
<progress
|
||||||
<div class="assignees" v-if="task.assignees.length > 0">
|
class="progress is-small"
|
||||||
<user
|
v-if="task.percentDone > 0"
|
||||||
v-for="u in task.assignees"
|
:value="task.percentDone * 100" max="100">
|
||||||
:avatar-size="24"
|
{{ task.percentDone * 100 }}%
|
||||||
:key="task.id + 'assignee' + u.id"
|
</progress>
|
||||||
:show-username="false"
|
<div class="footer">
|
||||||
:user="u"
|
<labels :labels="task.labels"/>
|
||||||
/>
|
<priority-label :priority="task.priority" :done="task.done"/>
|
||||||
|
<div class="assignees" v-if="task.assignees.length > 0">
|
||||||
|
<user
|
||||||
|
v-for="u in task.assignees"
|
||||||
|
:avatar-size="24"
|
||||||
|
:key="task.id + 'assignee' + u.id"
|
||||||
|
:show-username="false"
|
||||||
|
:user="u"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<checklist-summary :task="task"/>
|
||||||
|
<span class="icon" v-if="task.attachments.length > 0">
|
||||||
|
<icon icon="paperclip"/>
|
||||||
|
</span>
|
||||||
|
<span v-if="task.description" class="icon">
|
||||||
|
<icon icon="align-left"/>
|
||||||
|
</span>
|
||||||
|
<span class="icon" v-if="task.repeatAfter.amount > 0">
|
||||||
|
<icon icon="history"/>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<checklist-summary :task="task"/>
|
|
||||||
<span class="icon" v-if="task.attachments.length > 0">
|
|
||||||
<icon icon="paperclip"/>
|
|
||||||
</span>
|
|
||||||
<span v-if="task.description" class="icon">
|
|
||||||
<icon icon="align-left"/>
|
|
||||||
</span>
|
|
||||||
<span class="icon" v-if="task.repeatAfter.amount > 0">
|
|
||||||
<icon icon="history"/>
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {ref, computed} from 'vue'
|
import {ref, computed, watch} from 'vue'
|
||||||
import {useRouter} from 'vue-router'
|
import {useRouter} from 'vue-router'
|
||||||
|
|
||||||
import PriorityLabel from '@/components/tasks/partials/priorityLabel.vue'
|
import PriorityLabel from '@/components/tasks/partials/priorityLabel.vue'
|
||||||
|
@ -77,6 +85,8 @@ import ChecklistSummary from './checklist-summary.vue'
|
||||||
|
|
||||||
import {TASK_DEFAULT_COLOR, getHexColor} from '@/models/task'
|
import {TASK_DEFAULT_COLOR, getHexColor} from '@/models/task'
|
||||||
import type {ITask} from '@/modelTypes/ITask'
|
import type {ITask} from '@/modelTypes/ITask'
|
||||||
|
import {SUPPORTED_IMAGE_SUFFIX} from '@/models/attachment'
|
||||||
|
import AttachmentService from '@/services/attachment'
|
||||||
|
|
||||||
import {formatDateLong, formatISO, formatDateSince} from '@/helpers/time/formatDate'
|
import {formatDateLong, formatISO, formatDateSince} from '@/helpers/time/formatDate'
|
||||||
import {colorIsDark} from '@/helpers/color/colorIsDark'
|
import {colorIsDark} from '@/helpers/color/colorIsDark'
|
||||||
|
@ -114,6 +124,29 @@ function openTaskDetail() {
|
||||||
state: {backdropView: router.currentRoute.value.fullPath},
|
state: {backdropView: router.currentRoute.value.fullPath},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const coverImageBlobUrl = ref<string | null>(null)
|
||||||
|
|
||||||
|
async function maybeDownloadCoverImage() {
|
||||||
|
if (!props.task.coverImageAttachmentId) {
|
||||||
|
coverImageBlobUrl.value = null
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const attachment = props.task.attachments.find(a => a.id === props.task.coverImageAttachmentId)
|
||||||
|
if (!attachment || !SUPPORTED_IMAGE_SUFFIX.some((suffix) => attachment.file.name.endsWith(suffix))) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const attachmentService = new AttachmentService()
|
||||||
|
coverImageBlobUrl.value = await attachmentService.getBlobUrl(attachment)
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.task.coverImageAttachmentId,
|
||||||
|
maybeDownloadCoverImage,
|
||||||
|
{immediate: true},
|
||||||
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@ -125,12 +158,11 @@ $task-background: var(--white);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
box-shadow: var(--shadow-xs);
|
box-shadow: var(--shadow-xs);
|
||||||
display: block;
|
display: block;
|
||||||
border: 3px solid transparent;
|
|
||||||
|
|
||||||
font-size: .9rem;
|
font-size: .9rem;
|
||||||
padding: .4rem;
|
|
||||||
border-radius: $radius;
|
border-radius: $radius;
|
||||||
background: $task-background;
|
background: $task-background;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
&.loader-container.is-loading::after {
|
&.loader-container.is-loading::after {
|
||||||
width: 1.5rem;
|
width: 1.5rem;
|
||||||
|
|
|
@ -37,7 +37,11 @@
|
||||||
@create="createAndRelateTask"
|
@create="createAndRelateTask"
|
||||||
>
|
>
|
||||||
<template #searchResult="{option: task}">
|
<template #searchResult="{option: task}">
|
||||||
<span v-if="typeof task !== 'string'" class="search-result">
|
<span
|
||||||
|
v-if="typeof task !== 'string'"
|
||||||
|
class="search-result"
|
||||||
|
:class="{'is-strikethrough': task.done}"
|
||||||
|
>
|
||||||
<span
|
<span
|
||||||
class="different-list"
|
class="different-list"
|
||||||
v-if="task.listId !== listId"
|
v-if="task.listId !== listId"
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
import {describe, it, expect} from 'vitest'
|
|
||||||
import {hourToSalutation} from './useDateTimeSalutation'
|
|
||||||
|
|
||||||
const dateWithHour = (hours: number): Date => {
|
|
||||||
const date = new Date()
|
|
||||||
date.setHours(hours)
|
|
||||||
return date
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('Salutation', () => {
|
|
||||||
it('shows the right salutation in the night', () => {
|
|
||||||
const salutation = hourToSalutation(dateWithHour(4))
|
|
||||||
expect(salutation).toBe('home.welcomeNight')
|
|
||||||
})
|
|
||||||
it('shows the right salutation in the morning', () => {
|
|
||||||
const salutation = hourToSalutation(dateWithHour(8))
|
|
||||||
expect(salutation).toBe('home.welcomeMorning')
|
|
||||||
})
|
|
||||||
it('shows the right salutation in the day', () => {
|
|
||||||
const salutation = hourToSalutation(dateWithHour(13))
|
|
||||||
expect(salutation).toBe('home.welcomeDay')
|
|
||||||
})
|
|
||||||
it('shows the right salutation in the night', () => {
|
|
||||||
const salutation = hourToSalutation(dateWithHour(20))
|
|
||||||
expect(salutation).toBe('home.welcomeEvening')
|
|
||||||
})
|
|
||||||
it('shows the right salutation in the night again', () => {
|
|
||||||
const salutation = hourToSalutation(dateWithHour(23))
|
|
||||||
expect(salutation).toBe('home.welcomeNight')
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -1,31 +0,0 @@
|
||||||
import {computed} from 'vue'
|
|
||||||
import {useNow} from '@vueuse/core'
|
|
||||||
|
|
||||||
const TRANSLATION_KEY_PREFIX = 'home.welcome'
|
|
||||||
|
|
||||||
export function hourToSalutation(now: Date) {
|
|
||||||
const hours = now.getHours()
|
|
||||||
|
|
||||||
if (hours < 5) {
|
|
||||||
return `${TRANSLATION_KEY_PREFIX}Night`
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hours < 11) {
|
|
||||||
return `${TRANSLATION_KEY_PREFIX}Morning`
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hours < 18) {
|
|
||||||
return `${TRANSLATION_KEY_PREFIX}Day`
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hours < 23) {
|
|
||||||
return `${TRANSLATION_KEY_PREFIX}Evening`
|
|
||||||
}
|
|
||||||
|
|
||||||
return `${TRANSLATION_KEY_PREFIX}Night`
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useDateTimeSalutation() {
|
|
||||||
const now = useNow()
|
|
||||||
return computed(() => hourToSalutation(now.value))
|
|
||||||
}
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
import {computed} from 'vue'
|
||||||
|
import {useI18n} from 'vue-i18n'
|
||||||
|
import {useNow} from '@vueuse/core'
|
||||||
|
|
||||||
|
import {useAuthStore} from '@/stores/auth'
|
||||||
|
import {hourToDaytime} from '@/helpers/hourToDaytime'
|
||||||
|
|
||||||
|
export type Daytime = 'night' | 'morning' | 'day' | 'evening'
|
||||||
|
|
||||||
|
export function useDaytimeSalutation() {
|
||||||
|
const {t} = useI18n({useScope: 'global'})
|
||||||
|
const now = useNow()
|
||||||
|
const authStore = useAuthStore()
|
||||||
|
|
||||||
|
const name = computed(() => authStore.userDisplayName)
|
||||||
|
const daytime = computed(() => hourToDaytime(now.value))
|
||||||
|
|
||||||
|
const salutations = {
|
||||||
|
'night': () => t('home.welcomeNight', {username: name.value}),
|
||||||
|
'morning': () => t('home.welcomeMorning', {username: name.value}),
|
||||||
|
'day': () => t('home.welcomeDay', {username: name.value}),
|
||||||
|
'evening': () => t('home.welcomeEvening', {username: name.value}),
|
||||||
|
} as Record<Daytime, () => string>
|
||||||
|
|
||||||
|
return computed(() => name.value ? salutations[daytime.value]() : undefined)
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
import {useRouter} from 'vue-router'
|
||||||
|
import {getLastVisited, clearLastVisited} from '@/helpers/saveLastVisited'
|
||||||
|
|
||||||
|
export function useRedirectToLastVisited() {
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
function redirectIfSaved() {
|
||||||
|
const last = getLastVisited()
|
||||||
|
if (last !== null) {
|
||||||
|
router.push({
|
||||||
|
name: last.name,
|
||||||
|
params: last.params,
|
||||||
|
query: last.query,
|
||||||
|
})
|
||||||
|
clearLastVisited()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
router.push({name: 'home'})
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
redirectIfSaved,
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,7 +19,7 @@ export function useRenewTokenOnFocus() {
|
||||||
authStore.renewToken()
|
authStore.renewToken()
|
||||||
|
|
||||||
// Check if the token is still valid if the window gets focus again to maybe renew it
|
// Check if the token is still valid if the window gets focus again to maybe renew it
|
||||||
useEventListener('focus', () => {
|
useEventListener('focus', async () => {
|
||||||
if (!authenticated.value) {
|
if (!authenticated.value) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -29,8 +29,8 @@ export function useRenewTokenOnFocus() {
|
||||||
// If the token expiry is negative, it is already expired and we have no choice but to redirect
|
// If the token expiry is negative, it is already expired and we have no choice but to redirect
|
||||||
// the user to the login page
|
// the user to the login page
|
||||||
if (expiresIn < 0) {
|
if (expiresIn < 0) {
|
||||||
authStore.checkAuth()
|
await authStore.checkAuth()
|
||||||
router.push({name: 'user.login'})
|
await router.push({name: 'user.login'})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
import {describe, it, expect} from 'vitest'
|
||||||
|
import {hourToDaytime} from "./hourToDaytime"
|
||||||
|
|
||||||
|
function dateWithHour(hours: number): Date {
|
||||||
|
const newDate = new Date()
|
||||||
|
newDate.setHours(hours, 0, 0,0 )
|
||||||
|
return newDate
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('Salutation', () => {
|
||||||
|
it('shows the right salutation in the night', () => {
|
||||||
|
const salutation = hourToDaytime(dateWithHour(4))
|
||||||
|
expect(salutation).toBe('night')
|
||||||
|
})
|
||||||
|
it('shows the right salutation in the morning', () => {
|
||||||
|
const salutation = hourToDaytime(dateWithHour(8))
|
||||||
|
expect(salutation).toBe('morning')
|
||||||
|
})
|
||||||
|
it('shows the right salutation in the day', () => {
|
||||||
|
const salutation = hourToDaytime(dateWithHour(13))
|
||||||
|
expect(salutation).toBe('day')
|
||||||
|
})
|
||||||
|
it('shows the right salutation in the night', () => {
|
||||||
|
const salutation = hourToDaytime(dateWithHour(20))
|
||||||
|
expect(salutation).toBe('evening')
|
||||||
|
})
|
||||||
|
it('shows the right salutation in the night again', () => {
|
||||||
|
const salutation = hourToDaytime(dateWithHour(23))
|
||||||
|
expect(salutation).toBe('night')
|
||||||
|
})
|
||||||
|
})
|
|
@ -0,0 +1,14 @@
|
||||||
|
import type { Daytime } from '@/composables/useDaytimeSalutation'
|
||||||
|
|
||||||
|
export function hourToDaytime(now: Date): Daytime {
|
||||||
|
const hours = now.getHours()
|
||||||
|
|
||||||
|
const daytimeMap = {
|
||||||
|
night: hours < 5 || hours > 23,
|
||||||
|
morning: hours < 11,
|
||||||
|
day: hours < 18,
|
||||||
|
evening: hours < 23,
|
||||||
|
} as Record<Daytime, boolean>
|
||||||
|
|
||||||
|
return (Object.keys(daytimeMap) as Daytime[]).find((daytime) => daytimeMap[daytime]) || 'night'
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
const LAST_VISITED_KEY = 'lastVisited'
|
const LAST_VISITED_KEY = 'lastVisited'
|
||||||
|
|
||||||
export const saveLastVisited = (name: string, params: object) => {
|
export const saveLastVisited = (name: string, params: object, query: object) => {
|
||||||
localStorage.setItem(LAST_VISITED_KEY, JSON.stringify({name, params}))
|
localStorage.setItem(LAST_VISITED_KEY, JSON.stringify({name, params, query}))
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getLastVisited = () => {
|
export const getLastVisited = () => {
|
||||||
|
|
|
@ -8,7 +8,7 @@ import {i18n} from '@/i18n'
|
||||||
|
|
||||||
const locales = {en: enGB, de, ch: de, fr, ru}
|
const locales = {en: enGB, de, ch: de, fr, ru}
|
||||||
|
|
||||||
const dateIsValid = date => {
|
export function dateIsValid(date) {
|
||||||
if (date === null) {
|
if (date === null) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
{
|
{
|
||||||
"home": {
|
"home": {
|
||||||
"welcomeNight": "Good Night {username}",
|
"welcomeNight": "Good Night {username}!",
|
||||||
"welcomeMorning": "Good Morning {username}",
|
"welcomeMorning": "Good Morning {username}!",
|
||||||
"welcomeDay": "Hi {username}",
|
"welcomeDay": "Hi {username}!",
|
||||||
"welcomeEvening": "Good Evening {username}",
|
"welcomeEvening": "Good Evening {username}!",
|
||||||
"lastViewed": "Last viewed",
|
"lastViewed": "Last viewed",
|
||||||
"list": {
|
"list": {
|
||||||
"newText": "You can create a new list for your new tasks:",
|
"newText": "You can create a new list for your new tasks:",
|
||||||
|
@ -169,6 +169,14 @@
|
||||||
"title": "List Title",
|
"title": "List Title",
|
||||||
"color": "Color",
|
"color": "Color",
|
||||||
"lists": "Lists",
|
"lists": "Lists",
|
||||||
|
"list": {
|
||||||
|
"title": "List",
|
||||||
|
"add": "Add",
|
||||||
|
"addPlaceholder": "Add a new task…",
|
||||||
|
"empty": "This list is currently empty.",
|
||||||
|
"newTaskCta": "Create a new task.",
|
||||||
|
"editTask": "Edit Task"
|
||||||
|
},
|
||||||
"search": "Type to search for a list…",
|
"search": "Type to search for a list…",
|
||||||
"searchSelect": "Click or press enter to select this list",
|
"searchSelect": "Click or press enter to select this list",
|
||||||
"shared": "Shared Lists",
|
"shared": "Shared Lists",
|
||||||
|
@ -270,14 +278,6 @@
|
||||||
"delete": "Delete"
|
"delete": "Delete"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"list": {
|
|
||||||
"title": "List",
|
|
||||||
"add": "Add",
|
|
||||||
"addPlaceholder": "Add a new task…",
|
|
||||||
"empty": "This list is currently empty.",
|
|
||||||
"newTaskCta": "Create a new task.",
|
|
||||||
"editTask": "Edit Task"
|
|
||||||
},
|
|
||||||
"gantt": {
|
"gantt": {
|
||||||
"title": "Gantt",
|
"title": "Gantt",
|
||||||
"showTasksWithoutDates": "Show tasks which don't have dates set",
|
"showTasksWithoutDates": "Show tasks which don't have dates set",
|
||||||
|
@ -672,13 +672,23 @@
|
||||||
"updated": "Updated"
|
"updated": "Updated"
|
||||||
},
|
},
|
||||||
"subscription": {
|
"subscription": {
|
||||||
"subscribedThroughParent": "You can't unsubscribe here because you are subscribed to this {entity} through its {parent}.",
|
"subscribedListThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this list through its namespace.",
|
||||||
"subscribed": "You are currently subscribed to this {entity} and will receive notifications for changes.",
|
"subscribedTaskThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this task through its namespace.",
|
||||||
"notSubscribed": "You are not subscribed to this {entity} and won't receive notifications for changes.",
|
"subscribedTaskThroughParentList": "You can't unsubscribe here because you are subscribed to this task through its list.",
|
||||||
|
"subscribedNamespace": "You are currently subscribed to this namespace and will receive notifications for changes.",
|
||||||
|
"notSubscribedNamespace": "You are not subscribed to this namespace and won't receive notifications for changes.",
|
||||||
|
"subscribedList": "You are currently subscribed to this list and will receive notifications for changes.",
|
||||||
|
"notSubscribedList": "You are not subscribed to this list and won't receive notifications for changes.",
|
||||||
|
"subscribedTask": "You are currently subscribed to this task and will receive notifications for changes.",
|
||||||
|
"notSubscribedTask": "You are not subscribed to this task and won't receive notifications for changes.",
|
||||||
"subscribe": "Subscribe",
|
"subscribe": "Subscribe",
|
||||||
"unsubscribe": "Unsubscribe",
|
"unsubscribe": "Unsubscribe",
|
||||||
"subscribeSuccess": "You are now subscribed to this {entity}",
|
"subscribeSuccessNamespace": "You are now subscribed to this namespace",
|
||||||
"unsubscribeSuccess": "You are now unsubscribed to this {entity}"
|
"unsubscribeSuccessNamespace": "You are now unsubscribed to this namespace",
|
||||||
|
"subscribeSuccessList": "You are now subscribed to this list",
|
||||||
|
"unsubscribeSuccessList": "You are now unsubscribed to this list",
|
||||||
|
"subscribeSuccessTask": "You are now subscribed to this task",
|
||||||
|
"unsubscribeSuccessTask": "You are now unsubscribed to this task"
|
||||||
},
|
},
|
||||||
"attachment": {
|
"attachment": {
|
||||||
"title": "Attachments",
|
"title": "Attachments",
|
||||||
|
@ -690,7 +700,11 @@
|
||||||
"deleteTooltip": "Delete this attachment",
|
"deleteTooltip": "Delete this attachment",
|
||||||
"deleteText1": "Are you sure you want to delete the attachment {filename}?",
|
"deleteText1": "Are you sure you want to delete the attachment {filename}?",
|
||||||
"copyUrl": "Copy URL",
|
"copyUrl": "Copy URL",
|
||||||
"copyUrlTooltip": "Copy the url of this attachment for usage in text"
|
"copyUrlTooltip": "Copy the url of this attachment for usage in text",
|
||||||
|
"setAsCover": "Make cover",
|
||||||
|
"unsetAsCover": "Remove cover",
|
||||||
|
"successfullyChangedCoverImage": "The cover image was successfully changed.",
|
||||||
|
"usedAsCover": "Cover image"
|
||||||
},
|
},
|
||||||
"comment": {
|
"comment": {
|
||||||
"title": "Comments",
|
"title": "Comments",
|
||||||
|
@ -839,6 +853,12 @@
|
||||||
"text1": "Are you sure you want to remove this user from the team?",
|
"text1": "Are you sure you want to remove this user from the team?",
|
||||||
"text2": "They will lose access to all lists and namespaces this team has access to. This CANNOT BE UNDONE!",
|
"text2": "They will lose access to all lists and namespaces this team has access to. This CANNOT BE UNDONE!",
|
||||||
"success": "The user was successfully deleted from the team."
|
"success": "The user was successfully deleted from the team."
|
||||||
|
},
|
||||||
|
"leave": {
|
||||||
|
"title": "Leave team",
|
||||||
|
"text1": "Are you sure you want to leave this team?",
|
||||||
|
"text2": "You will loose access to all lists and namespaces this team has access to. If you change your mind you'll need a team admin to add you again.",
|
||||||
|
"success": "You have successfully left the team."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"attributes": {
|
"attributes": {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
{
|
{
|
||||||
"home": {
|
"home": {
|
||||||
"welcomeNight": "Dobrou noc {username}",
|
"welcomeNight": "Dobrou noc {username}!",
|
||||||
"welcomeMorning": "Dobré ráno {username}",
|
"welcomeMorning": "Dobré ráno {username}!",
|
||||||
"welcomeDay": "Ahoj {username}",
|
"welcomeDay": "Ahoj {username}!",
|
||||||
"welcomeEvening": "Dobrý večer {username}",
|
"welcomeEvening": "Dobrý večer {username}!",
|
||||||
"lastViewed": "Naposledy zobrazeno",
|
"lastViewed": "Naposledy zobrazeno",
|
||||||
"list": {
|
"list": {
|
||||||
"newText": "Můžete vytvořit nový seznam pro své nové úkoly:",
|
"newText": "Můžete vytvořit nový seznam pro své nové úkoly:",
|
||||||
|
@ -77,7 +77,7 @@
|
||||||
"newName": "Nové jméno",
|
"newName": "Nové jméno",
|
||||||
"savedSuccess": "Nastavení bylo úspěšně aktualizováno.",
|
"savedSuccess": "Nastavení bylo úspěšně aktualizováno.",
|
||||||
"emailReminders": "Posílat mi připomenutí pro úkoly e-mailem",
|
"emailReminders": "Posílat mi připomenutí pro úkoly e-mailem",
|
||||||
"overdueReminders": "Send me a summary of my undone overdue tasks every day",
|
"overdueReminders": "Pošlete mi každý den shrnutí mých zpožděných úkolů",
|
||||||
"discoverableByName": "Nechat ostatní uživatele mě najít podle jména",
|
"discoverableByName": "Nechat ostatní uživatele mě najít podle jména",
|
||||||
"discoverableByEmail": "Nechat ostatní uživatele mě najít podle e-mailu",
|
"discoverableByEmail": "Nechat ostatní uživatele mě najít podle e-mailu",
|
||||||
"playSoundWhenDone": "Přehrát zvuk při označení úkolů jako hotovo",
|
"playSoundWhenDone": "Přehrát zvuk při označení úkolů jako hotovo",
|
||||||
|
@ -87,7 +87,7 @@
|
||||||
"language": "Jazyk",
|
"language": "Jazyk",
|
||||||
"defaultList": "Výchozí seznam",
|
"defaultList": "Výchozí seznam",
|
||||||
"timezone": "Časové pásmo",
|
"timezone": "Časové pásmo",
|
||||||
"overdueTasksRemindersTime": "Overdue tasks reminder email time"
|
"overdueTasksRemindersTime": "Čas odeslání emailu o zpožděných úkolech"
|
||||||
},
|
},
|
||||||
"totp": {
|
"totp": {
|
||||||
"title": "Dvoufaktorové ověření",
|
"title": "Dvoufaktorové ověření",
|
||||||
|
@ -169,10 +169,18 @@
|
||||||
"title": "Název seznamu",
|
"title": "Název seznamu",
|
||||||
"color": "Barva",
|
"color": "Barva",
|
||||||
"lists": "Seznamy",
|
"lists": "Seznamy",
|
||||||
|
"list": {
|
||||||
|
"title": "Seznam",
|
||||||
|
"add": "Přidat",
|
||||||
|
"addPlaceholder": "Přidat nový úkol…",
|
||||||
|
"empty": "Tento seznam je nyní prázdný.",
|
||||||
|
"newTaskCta": "Vytvořit nový úkol.",
|
||||||
|
"editTask": "Upravit úkol"
|
||||||
|
},
|
||||||
"search": "Začni psát pro vyhledání seznamu…",
|
"search": "Začni psát pro vyhledání seznamu…",
|
||||||
"searchSelect": "Klikněte nebo stiskněte Enter pro výběr tohoto seznamu",
|
"searchSelect": "Klikněte nebo stiskněte Enter pro výběr tohoto seznamu",
|
||||||
"shared": "Sdílené seznamy",
|
"shared": "Sdílené seznamy",
|
||||||
"noDescriptionAvailable": "No list description is available.",
|
"noDescriptionAvailable": "Popis seznamu není k dispozici.",
|
||||||
"create": {
|
"create": {
|
||||||
"header": "Nový seznam",
|
"header": "Nový seznam",
|
||||||
"titlePlaceholder": "Název seznamu přijde sem…",
|
"titlePlaceholder": "Název seznamu přijde sem…",
|
||||||
|
@ -244,8 +252,8 @@
|
||||||
"removeText": "Jste si jisti, že chcete odstranit tento sdílený odkaz? K tomuto seznamu již nebude možné přistupovat s tímto sdíleným odkazem. Tuto akci nelze vrátit zpět!",
|
"removeText": "Jste si jisti, že chcete odstranit tento sdílený odkaz? K tomuto seznamu již nebude možné přistupovat s tímto sdíleným odkazem. Tuto akci nelze vrátit zpět!",
|
||||||
"createSuccess": "Sdílený odkaz byl úspěšně vytvořen.",
|
"createSuccess": "Sdílený odkaz byl úspěšně vytvořen.",
|
||||||
"deleteSuccess": "Sdílený odkaz byl úspěšně smazán",
|
"deleteSuccess": "Sdílený odkaz byl úspěšně smazán",
|
||||||
"view": "View",
|
"view": "Zobrazit",
|
||||||
"sharedBy": "Shared by {0}"
|
"sharedBy": "Sdíleno {0}"
|
||||||
},
|
},
|
||||||
"userTeam": {
|
"userTeam": {
|
||||||
"typeUser": "uživatel | uživatelé",
|
"typeUser": "uživatel | uživatelé",
|
||||||
|
@ -270,14 +278,6 @@
|
||||||
"delete": "Smazat"
|
"delete": "Smazat"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"list": {
|
|
||||||
"title": "Seznam",
|
|
||||||
"add": "Přidat",
|
|
||||||
"addPlaceholder": "Přidat nový úkol…",
|
|
||||||
"empty": "Tento seznam je nyní prázdný.",
|
|
||||||
"newTaskCta": "Vytvořit nový úkol.",
|
|
||||||
"editTask": "Upravit úkol"
|
|
||||||
},
|
|
||||||
"gantt": {
|
"gantt": {
|
||||||
"title": "Gantt",
|
"title": "Gantt",
|
||||||
"showTasksWithoutDates": "Zobrazit úkoly, které nemají nastavené datum",
|
"showTasksWithoutDates": "Zobrazit úkoly, které nemají nastavené datum",
|
||||||
|
@ -297,23 +297,23 @@
|
||||||
"title": "Kanban",
|
"title": "Kanban",
|
||||||
"limit": "Limit: {limit}",
|
"limit": "Limit: {limit}",
|
||||||
"noLimit": "Nenastaveno",
|
"noLimit": "Nenastaveno",
|
||||||
"doneBucket": "Kbelík \"Hotovo\"",
|
"doneBucket": "Sloupec \"Hotovo\"",
|
||||||
"doneBucketHint": "Všechny úkoly přesunuté do tohoto kbelíku budou automaticky označeny jako dokončené.",
|
"doneBucketHint": "Všechny úkoly přesunuté do tohoto sloupce budou automaticky označeny jako dokončené.",
|
||||||
"doneBucketHintExtended": "Všechny úkoly přesunuté do kbelíku \"Hotovo\" budou označeny jako dokončené automaticky. Všechny úkoly označené jako dokončené odjinud sem budou přesunuty také.",
|
"doneBucketHintExtended": "Všechny úkoly přesunuté do sloupce \"Hotovo\" budou označeny jako dokončené automaticky. Všechny úkoly označené jako dokončené jinde sem budou přesunuty také.",
|
||||||
"doneBucketSavedSuccess": "Kbelík \"Hotovo\" byl úspěšně uložen.",
|
"doneBucketSavedSuccess": "Sloupec \"Hotovo\" byl úspěšně uložen.",
|
||||||
"deleteLast": "Nelze odstranit poslední kbelík.",
|
"deleteLast": "Nelze odstranit poslední sloupec.",
|
||||||
"addTaskPlaceholder": "Zadejte nový název úkolu…",
|
"addTaskPlaceholder": "Zadejte nový název úkolu…",
|
||||||
"addTask": "Přidat úkol",
|
"addTask": "Přidat úkol",
|
||||||
"addAnotherTask": "Přidat další úkol",
|
"addAnotherTask": "Přidat další úkol",
|
||||||
"addBucket": "Vytvořit nový kbelík",
|
"addBucket": "Vytvořit nový sloupec",
|
||||||
"addBucketPlaceholder": "Zadejte název nového kbelíku…",
|
"addBucketPlaceholder": "Zadejte název nového sloupce…",
|
||||||
"deleteHeaderBucket": "Smazat kbelík",
|
"deleteHeaderBucket": "Smazat sloupec",
|
||||||
"deleteBucketText1": "Opravdu chcete smazat tento kbelík?",
|
"deleteBucketText1": "Opravdu chcete smazat tento sloupec?",
|
||||||
"deleteBucketText2": "Toto neodstraní žádné úkoly, ale přesune je do výchozího kbelíku.",
|
"deleteBucketText2": "Toto nesmaže žádné úkoly, ale přesune je do výchozího sloupce.",
|
||||||
"deleteBucketSuccess": "Kbelík byl úspěšně smazán.",
|
"deleteBucketSuccess": "Sloupec byl úspěšně smazán.",
|
||||||
"bucketTitleSavedSuccess": "Název kbelíku byl úspěšně uložen.",
|
"bucketTitleSavedSuccess": "Název sloupce byl úspěšně uložen.",
|
||||||
"bucketLimitSavedSuccess": "Limit kbelíku byl úspěšně uložen.",
|
"bucketLimitSavedSuccess": "Limit sloupce byl úspěšně uložen.",
|
||||||
"collapse": "Sbalit tento kbelík"
|
"collapse": "Sbalit tento sloupec"
|
||||||
},
|
},
|
||||||
"pseudo": {
|
"pseudo": {
|
||||||
"favorites": {
|
"favorites": {
|
||||||
|
@ -672,13 +672,23 @@
|
||||||
"updated": "Aktualizováno"
|
"updated": "Aktualizováno"
|
||||||
},
|
},
|
||||||
"subscription": {
|
"subscription": {
|
||||||
"subscribedThroughParent": "Zde se nemůžete odhlásit, protože jste přihlášeni k odběru {entity} prostřednictvím jeho {parent}.",
|
"subscribedListThroughParentNamespace": "Zde se nemůžete odhlásit, protože jste přihlášeni k odběru tohoto seznamu prostřednictvím jeho prostoru.",
|
||||||
"subscribed": "Aktuálně jste přihlášeni k odběru {entity} a budete dostávat oznámení o změnách.",
|
"subscribedTaskThroughParentNamespace": "Zde se nemůžete odhlásit, protože jste přihlášeni k odběru tohoto úkolu prostřednictvím jeho prostoru.",
|
||||||
"notSubscribed": "Nejste přihlášeni k odběru {entity} a nebudete dostávat upozornění na změny.",
|
"subscribedTaskThroughParentList": "Zde se nemůžete odhlásit, protože jste přihlášeni k odběru tohoto úkolu prostřednictvím jeho seznamu.",
|
||||||
|
"subscribedNamespace": "Nyní jste přihlášeni k odběru tohoto prostoru a budete dostávat oznámení o změnách.",
|
||||||
|
"notSubscribedNamespace": "Nejste přihlášeni k odběru tohoto prostoru, takže nebudete dostávat upozornění na změny.",
|
||||||
|
"subscribedList": "Nyní jste přihlášeni k odběru tohoto seznamu a budete dostávat oznámení o změnách.",
|
||||||
|
"notSubscribedList": "Nejste přihlášeni k odběru tohoto seznamu, takže nebudete dostávat upozornění na změny.",
|
||||||
|
"subscribedTask": "Nyní jste přihlášeni k odběru tohoto úkolu a budete dostávat oznámení o změnách.",
|
||||||
|
"notSubscribedTask": "Nejste přihlášeni k odběru tohoto úkolu, takže nebudete dostávat upozornění na změny.",
|
||||||
"subscribe": "Odebírat",
|
"subscribe": "Odebírat",
|
||||||
"unsubscribe": "Odhlásit odběr",
|
"unsubscribe": "Odhlásit odběr",
|
||||||
"subscribeSuccess": "Nyní jste přihlášeni k odběru {entity}",
|
"subscribeSuccessNamespace": "Nyní jste přihlášeni k tomuto prostoru",
|
||||||
"unsubscribeSuccess": "Nyní jste odhlášeni od odběru {entity}"
|
"unsubscribeSuccessNamespace": "Nyní jste odhlášeni od tohoto prostoru",
|
||||||
|
"subscribeSuccessList": "Nyní jste přihlášeni k tomuto seznamu",
|
||||||
|
"unsubscribeSuccessList": "Nyní jste odhlášeni od tohoto seznamu",
|
||||||
|
"subscribeSuccessTask": "Nyní jste přihlášeni k tomuto úkolu",
|
||||||
|
"unsubscribeSuccessTask": "Nyní jste odhlášeni od tohoto úkolu"
|
||||||
},
|
},
|
||||||
"attachment": {
|
"attachment": {
|
||||||
"title": "Přílohy",
|
"title": "Přílohy",
|
||||||
|
@ -690,7 +700,11 @@
|
||||||
"deleteTooltip": "Smazat tuto přílohu",
|
"deleteTooltip": "Smazat tuto přílohu",
|
||||||
"deleteText1": "Opravdu chcete odstranit přílohu {filename}?",
|
"deleteText1": "Opravdu chcete odstranit přílohu {filename}?",
|
||||||
"copyUrl": "Kopírovat URL",
|
"copyUrl": "Kopírovat URL",
|
||||||
"copyUrlTooltip": "Kopírovat URL této přílohy pro použití v textu"
|
"copyUrlTooltip": "Kopírovat URL této přílohy pro použití v textu",
|
||||||
|
"setAsCover": "Použij titulní obrázek",
|
||||||
|
"unsetAsCover": "Odstraň titulní obrázek",
|
||||||
|
"successfullyChangedCoverImage": "Titulní obrázek byl úspěšně změněn.",
|
||||||
|
"usedAsCover": "Titulní obrázek"
|
||||||
},
|
},
|
||||||
"comment": {
|
"comment": {
|
||||||
"title": "Komentáře",
|
"title": "Komentáře",
|
||||||
|
@ -701,7 +715,7 @@
|
||||||
"comment": "Komentář",
|
"comment": "Komentář",
|
||||||
"delete": "Smazat tento komentář",
|
"delete": "Smazat tento komentář",
|
||||||
"deleteText1": "Opravdu chcete smazat tento komentář?",
|
"deleteText1": "Opravdu chcete smazat tento komentář?",
|
||||||
"deleteSuccess": "The comment was deleted successfully.",
|
"deleteSuccess": "Komentář byl úspěšně odstraněn.",
|
||||||
"addedSuccess": "Komentář byl úspěšně přidán."
|
"addedSuccess": "Komentář byl úspěšně přidán."
|
||||||
},
|
},
|
||||||
"deferDueDate": {
|
"deferDueDate": {
|
||||||
|
@ -728,16 +742,16 @@
|
||||||
"removeSuccess": "Štítek byl úspěšně odstraněn.",
|
"removeSuccess": "Štítek byl úspěšně odstraněn.",
|
||||||
"addCreateSuccess": "Štítek byl úspěšně vytvořen a přidán.",
|
"addCreateSuccess": "Štítek byl úspěšně vytvořen a přidán.",
|
||||||
"delete": {
|
"delete": {
|
||||||
"header": "Delete this label",
|
"header": "Smazat tento štítek",
|
||||||
"text1": "Are you sure you want to delete this label?",
|
"text1": "Opravdu chcete smazat tento štítek?",
|
||||||
"text2": "This will remove it from all tasks and cannot be restored."
|
"text2": "Odebere štítek ze všech úkolů a nelze to vrátit zpět."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"priority": {
|
"priority": {
|
||||||
"unset": "Zrušit nastavení",
|
"unset": "Zrušit nastavení",
|
||||||
"low": "Nízká",
|
"low": "Nízká",
|
||||||
"medium": "Střední",
|
"medium": "Střední",
|
||||||
"high": "High",
|
"high": "Vysoká",
|
||||||
"urgent": "Naléhavé",
|
"urgent": "Naléhavé",
|
||||||
"doNow": "UDĚLEJ TO HNED"
|
"doNow": "UDĚLEJ TO HNED"
|
||||||
},
|
},
|
||||||
|
@ -781,7 +795,7 @@
|
||||||
"weeks": "Týdny",
|
"weeks": "Týdny",
|
||||||
"months": "Měsíce",
|
"months": "Měsíce",
|
||||||
"years": "Roky",
|
"years": "Roky",
|
||||||
"invalidAmount": "Please enter more than 0."
|
"invalidAmount": "Zadejte prosím více než 0."
|
||||||
},
|
},
|
||||||
"quickAddMagic": {
|
"quickAddMagic": {
|
||||||
"hint": "Můžeš použít Kouzelné rychlé přidání",
|
"hint": "Můžeš použít Kouzelné rychlé přidání",
|
||||||
|
@ -791,15 +805,15 @@
|
||||||
"multiple": "Toto můžete použít několikrát.",
|
"multiple": "Toto můžete použít několikrát.",
|
||||||
"label1": "Chcete-li přidat štítek, jednoduše napište před název štítku {prefix}.",
|
"label1": "Chcete-li přidat štítek, jednoduše napište před název štítku {prefix}.",
|
||||||
"label2": "Vikunja nejprve zkontroluje, zda štítek již existuje a vytvoří jej, pokud ne.",
|
"label2": "Vikunja nejprve zkontroluje, zda štítek již existuje a vytvoří jej, pokud ne.",
|
||||||
"label3": "To use spaces, simply add a \" or ' around the label name.",
|
"label3": "Chcete-li použít mezery, uzavřete název štítku do \" nebo '.",
|
||||||
"label4": "Například: {prefix}\"Štítek s mezerami\".",
|
"label4": "Například: {prefix}\"Štítek s mezerami\".",
|
||||||
"priority1": "Chcete-li nastavit prioritu úkolu, přidejte číslo 1-5, s prefixem {prefix}.",
|
"priority1": "Chcete-li nastavit prioritu úkolu, přidejte číslo 1-5, s prefixem {prefix}.",
|
||||||
"priority2": "Čím vyšší číslo, tím vyšší priorita.",
|
"priority2": "Čím vyšší číslo, tím vyšší priorita.",
|
||||||
"assignees": "Chcete-li přímo přiřadit úkol k uživateli, přidejte k úkolu jejich uživatelské jméno s prefixem {prefix}.",
|
"assignees": "Chcete-li přímo přiřadit úkol k uživateli, přidejte k úkolu jejich uživatelské jméno s prefixem {prefix}.",
|
||||||
"list1": "Chcete-li nastavit seznam, ve kterém se má úkol zobrazit, zadejte jeho název s předponou {prefix}.",
|
"list1": "Chcete-li nastavit seznam, ve kterém se má úkol zobrazit, zadejte jeho název s předponou {prefix}.",
|
||||||
"list2": "Toto vrátí chybu, pokud seznam neexistuje.",
|
"list2": "Toto vrátí chybu, pokud seznam neexistuje.",
|
||||||
"list3": "To use spaces, simply add a \" or ' around the list name.",
|
"list3": "Chcete-li použít mezery, uzavřete název seznamu do \" nebo '.",
|
||||||
"list4": "For example: {prefix}\"List with spaces\".",
|
"list4": "Například: {prefix}\"Štítek s mezerami\".",
|
||||||
"dateAndTime": "Datum a čas",
|
"dateAndTime": "Datum a čas",
|
||||||
"date": "Jakékoliv datum bude použito jako datum dokončení nového úkolu. Můžete použít data v kterémkoli z těchto formátů:",
|
"date": "Jakékoliv datum bude použito jako datum dokončení nového úkolu. Můžete použít data v kterémkoli z těchto formátů:",
|
||||||
"dateWeekday": "každý pracovní den použije další datum s tímto datem",
|
"dateWeekday": "každý pracovní den použije další datum s tímto datem",
|
||||||
|
@ -839,6 +853,12 @@
|
||||||
"text1": "Opravdu chcete odebrat tohoto uživatele z týmu?",
|
"text1": "Opravdu chcete odebrat tohoto uživatele z týmu?",
|
||||||
"text2": "Ztratí přístup ke všem seznamům a prostorům, k nimž má tento tým přístup. To NEMŮŽE BÝT VZATO ZPĚT!",
|
"text2": "Ztratí přístup ke všem seznamům a prostorům, k nimž má tento tým přístup. To NEMŮŽE BÝT VZATO ZPĚT!",
|
||||||
"success": "Uživatel byl úspěšně odstraněn z týmu."
|
"success": "Uživatel byl úspěšně odstraněn z týmu."
|
||||||
|
},
|
||||||
|
"leave": {
|
||||||
|
"title": "Opustit tým",
|
||||||
|
"text1": "Opravdu chcete opustit tento tým?",
|
||||||
|
"text2": "Ztratíte přístup ke všem seznamům a prostorům, k nimž má tento tým přístup. Pokud změníte názor, budete potřebovat správce týmu, aby vás znovu přidal.",
|
||||||
|
"success": "Úspěšně jste opustili tým."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"attributes": {
|
"attributes": {
|
||||||
|
@ -870,8 +890,8 @@
|
||||||
"related": "Upravit související úkoly tohoto úkolu",
|
"related": "Upravit související úkoly tohoto úkolu",
|
||||||
"color": "Změnit barvu tohoto úkolu",
|
"color": "Změnit barvu tohoto úkolu",
|
||||||
"move": "Přesunout tento úkol do jiného seznamu",
|
"move": "Přesunout tento úkol do jiného seznamu",
|
||||||
"reminder": "Manage reminders of this task",
|
"reminder": "Spravovat připomenutí této úlohy",
|
||||||
"description": "Toggle editing of the task description"
|
"description": "Přepnout úpravy popisu úkolu"
|
||||||
},
|
},
|
||||||
"list": {
|
"list": {
|
||||||
"title": "Zobrazení seznamů",
|
"title": "Zobrazení seznamů",
|
||||||
|
@ -943,7 +963,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"date": {
|
"date": {
|
||||||
"locale": "cs-CZ",
|
"locale": "cs",
|
||||||
"altFormatLong": "j M Y H:i",
|
"altFormatLong": "j M Y H:i",
|
||||||
"altFormatShort": "j M Y"
|
"altFormatShort": "j M Y"
|
||||||
},
|
},
|
||||||
|
@ -1013,11 +1033,11 @@
|
||||||
"8002": "Štítek neexistuje.",
|
"8002": "Štítek neexistuje.",
|
||||||
"8003": "K tomuto štítku nemáte přístup.",
|
"8003": "K tomuto štítku nemáte přístup.",
|
||||||
"9001": "Právo je neplatné.",
|
"9001": "Právo je neplatné.",
|
||||||
"10001": "Kbelík neexistuje.",
|
"10001": "Sloupec neexistuje.",
|
||||||
"10002": "Kbelík nepatří do tohoto seznamu.",
|
"10002": "Sloupec nepatří do tohoto seznamu.",
|
||||||
"10003": "Poslední kbelík v seznamu nelze odstranit.",
|
"10003": "Poslední sloupec v seznamu nelze odstranit.",
|
||||||
"10004": "Nemůžete přidat úkol do tohoto kbelíku, protože již překročil limit úkolů, které do něj můžete uložit.",
|
"10004": "Nemůžete přidat úkol do tohoto sloupce, protože již překročil limit úkolů, které do něj můžete uložit.",
|
||||||
"10005": "Na seznam může být pouze jeden kbelík \"Hotovo\".",
|
"10005": "Pro seznam může být pouze jeden sloupec \"Hotovo\".",
|
||||||
"11001": "Uložený filtr neexistuje.",
|
"11001": "Uložený filtr neexistuje.",
|
||||||
"11002": "Uložené filtry nejsou k dispozici pro sdílení odkazů.",
|
"11002": "Uložené filtry nejsou k dispozici pro sdílení odkazů.",
|
||||||
"12001": "Typ předplatného je neplatný.",
|
"12001": "Typ předplatného je neplatný.",
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
{
|
{
|
||||||
"home": {
|
"home": {
|
||||||
"welcomeNight": "Gute Nacht, {username}",
|
"welcomeNight": "Gute Nacht, {username}!",
|
||||||
"welcomeMorning": "Guten Morgen, {username}",
|
"welcomeMorning": "Guten Morgen, {username}!",
|
||||||
"welcomeDay": "Hallo, {username}",
|
"welcomeDay": "Hallo {username}!",
|
||||||
"welcomeEvening": "Guten Abend, {username}",
|
"welcomeEvening": "Guten Abend, {username}!",
|
||||||
"lastViewed": "Zuletzt angesehen",
|
"lastViewed": "Zuletzt angesehen",
|
||||||
"list": {
|
"list": {
|
||||||
"newText": "Du kannst eine neue Liste für deine neuen Aufgaben erstellen:",
|
"newText": "Du kannst eine neue Liste für deine neuen Aufgaben erstellen:",
|
||||||
|
@ -169,6 +169,14 @@
|
||||||
"title": "Listentitel",
|
"title": "Listentitel",
|
||||||
"color": "Farbe",
|
"color": "Farbe",
|
||||||
"lists": "Listen",
|
"lists": "Listen",
|
||||||
|
"list": {
|
||||||
|
"title": "Liste",
|
||||||
|
"add": "Hinzufügen",
|
||||||
|
"addPlaceholder": "Eine neue Aufgabe hinzufügen …",
|
||||||
|
"empty": "Diese Liste ist derzeit leer.",
|
||||||
|
"newTaskCta": "Eine neue Aufgabe erstellen.",
|
||||||
|
"editTask": "Aufgabe bearbeiten"
|
||||||
|
},
|
||||||
"search": "Tippe, um nach einer Liste zu suchen…",
|
"search": "Tippe, um nach einer Liste zu suchen…",
|
||||||
"searchSelect": "Klicke auf oder drücke die Eingabetaste, um diese Liste auszuwählen",
|
"searchSelect": "Klicke auf oder drücke die Eingabetaste, um diese Liste auszuwählen",
|
||||||
"shared": "Geteilte Listen",
|
"shared": "Geteilte Listen",
|
||||||
|
@ -270,14 +278,6 @@
|
||||||
"delete": "Löschen"
|
"delete": "Löschen"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"list": {
|
|
||||||
"title": "Liste",
|
|
||||||
"add": "Hinzufügen",
|
|
||||||
"addPlaceholder": "Eine neue Aufgabe hinzufügen …",
|
|
||||||
"empty": "Diese Liste ist derzeit leer.",
|
|
||||||
"newTaskCta": "Eine neue Aufgabe erstellen.",
|
|
||||||
"editTask": "Aufgabe bearbeiten"
|
|
||||||
},
|
|
||||||
"gantt": {
|
"gantt": {
|
||||||
"title": "Gantt",
|
"title": "Gantt",
|
||||||
"showTasksWithoutDates": "Aufgaben anzeigen, für die keine Daten festgelegt sind",
|
"showTasksWithoutDates": "Aufgaben anzeigen, für die keine Daten festgelegt sind",
|
||||||
|
@ -335,7 +335,7 @@
|
||||||
"create": {
|
"create": {
|
||||||
"title": "Neuer Namespace",
|
"title": "Neuer Namespace",
|
||||||
"titleRequired": "Bitte gebe einen Titel an.",
|
"titleRequired": "Bitte gebe einen Titel an.",
|
||||||
"explanation": "Ein Namespace ist eine Sammlung von Listen, die du teilen und zur Organisation verwenden kannst. Jede Liste zu einem Namespace.",
|
"explanation": "Ein Namespace ist eine Sammlung von Listen, die du teilen und zur Organisation verwenden kannst. Jede Liste gehört zu einem Namespace.",
|
||||||
"tooltip": "Was ist ein Namespace?",
|
"tooltip": "Was ist ein Namespace?",
|
||||||
"success": "Der Namespace wurde erfolgreich erstellt."
|
"success": "Der Namespace wurde erfolgreich erstellt."
|
||||||
},
|
},
|
||||||
|
@ -672,13 +672,23 @@
|
||||||
"updated": "Aktualisiert"
|
"updated": "Aktualisiert"
|
||||||
},
|
},
|
||||||
"subscription": {
|
"subscription": {
|
||||||
"subscribedThroughParent": "Du kannst hier nicht de-abonnieren, da du diese {entity} durch {parent} abonniert hast.",
|
"subscribedListThroughParentNamespace": "Du kannst hier nicht de-abonnieren, da du diese Liste über ihren Namespace abonniert hast.",
|
||||||
"subscribed": "Du erhältst Benachrichtigungen zu dieser {entity}.",
|
"subscribedTaskThroughParentNamespace": "Du kannst hier nicht de-abonnieren, da du diese Aufgabe über ihren Namespace abonniert hast.",
|
||||||
"notSubscribed": "Du hast diese {entity} nicht abonniert und erhältst keine Benachrichtigungen über Änderungen.",
|
"subscribedTaskThroughParentList": "Du kannst hier nicht de-abonnieren, da du diese Aufgabe über ihre Liste abonniert hast.",
|
||||||
|
"subscribedNamespace": "Du hast diesen Namespace abonniert und erhältst Benachrichtigungen über Änderungen.",
|
||||||
|
"notSubscribedNamespace": "Du hast diesen Namespace nicht abonniert und erhältst keine Benachrichtigungen über Änderungen.",
|
||||||
|
"subscribedList": "Du hast diese Liste abonniert und erhältst Benachrichtigungen über Änderungen.",
|
||||||
|
"notSubscribedList": "Du hast diese Liste nicht abonniert und erhältst keine Benachrichtigungen über Änderungen.",
|
||||||
|
"subscribedTask": "Du hast diese Aufgabe abonniert und erhältst Benachrichtigungen über Änderungen.",
|
||||||
|
"notSubscribedTask": "Du hast diese Aufgabe nicht abonniert und erhältst keine Benachrichtigungen über Änderungen.",
|
||||||
"subscribe": "Abonnieren",
|
"subscribe": "Abonnieren",
|
||||||
"unsubscribe": "Abbestellen",
|
"unsubscribe": "Abbestellen",
|
||||||
"subscribeSuccess": "Du hast jetzt diese {entity} abonniert",
|
"subscribeSuccessNamespace": "Du hast diesen Namespace jetzt abonniert",
|
||||||
"unsubscribeSuccess": "Du hast diese {entity} jetzt abbestellt"
|
"unsubscribeSuccessNamespace": "Du hast diesen Namespace jetzt nicht mehr abonniert",
|
||||||
|
"subscribeSuccessList": "Du hast diese Liste jetzt abonniert",
|
||||||
|
"unsubscribeSuccessList": "Du hast diese Liste jetzt nicht mehr abonniert",
|
||||||
|
"subscribeSuccessTask": "Du hast diese Aufgabe jetzt abonniert",
|
||||||
|
"unsubscribeSuccessTask": "Du hast diese Aufgabe jetzt nicht mehr abonniert"
|
||||||
},
|
},
|
||||||
"attachment": {
|
"attachment": {
|
||||||
"title": "Anhänge",
|
"title": "Anhänge",
|
||||||
|
@ -690,7 +700,11 @@
|
||||||
"deleteTooltip": "Diesen Anhang löschen",
|
"deleteTooltip": "Diesen Anhang löschen",
|
||||||
"deleteText1": "Soll der Anhang {filename} gelöscht werden?",
|
"deleteText1": "Soll der Anhang {filename} gelöscht werden?",
|
||||||
"copyUrl": "URL kopieren",
|
"copyUrl": "URL kopieren",
|
||||||
"copyUrlTooltip": "Die URL dieses Anhangs zur Verwendung im Text kopieren"
|
"copyUrlTooltip": "Die URL dieses Anhangs zur Verwendung im Text kopieren",
|
||||||
|
"setAsCover": "Als Titelbild setzen",
|
||||||
|
"unsetAsCover": "Titelbild entfernen",
|
||||||
|
"successfullyChangedCoverImage": "Das Titelbild wurde erfolgreich geändert.",
|
||||||
|
"usedAsCover": "Titelbild"
|
||||||
},
|
},
|
||||||
"comment": {
|
"comment": {
|
||||||
"title": "Kommentare",
|
"title": "Kommentare",
|
||||||
|
@ -839,6 +853,12 @@
|
||||||
"text1": "Bist du sicher, dass du diese:n Benutzer:in aus dem Team entfernen willst?",
|
"text1": "Bist du sicher, dass du diese:n Benutzer:in aus dem Team entfernen willst?",
|
||||||
"text2": "Diese:r Benutzer:in verliert den Zugriff auf alle Listen und Namespaces auf die dieses Team Zugriff hat. Dies kann nicht rückgängig gemacht werden!",
|
"text2": "Diese:r Benutzer:in verliert den Zugriff auf alle Listen und Namespaces auf die dieses Team Zugriff hat. Dies kann nicht rückgängig gemacht werden!",
|
||||||
"success": "Der:die Benutzer:in wurde erfolgreich aus dem Team gelöscht."
|
"success": "Der:die Benutzer:in wurde erfolgreich aus dem Team gelöscht."
|
||||||
|
},
|
||||||
|
"leave": {
|
||||||
|
"title": "Team verlassen",
|
||||||
|
"text1": "Bist du sicher, dass du dieses Team verlassen willst?",
|
||||||
|
"text2": "Du wirst Zugriff auf alle Listen und Namespaces verlieren, auf die dieses Team Zugriff hat. Wenn du deine Meinung änderst, musst du durch einen Team-Admin wieder hinzugefügt werden.",
|
||||||
|
"success": "Du hast das Team erfolgreich verlassen."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"attributes": {
|
"attributes": {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
{
|
{
|
||||||
"home": {
|
"home": {
|
||||||
"welcomeNight": "Guet Nacht, {username}",
|
"welcomeNight": "Gute Nacht, {username}!",
|
||||||
"welcomeMorning": "Guete Morgä, {username}",
|
"welcomeMorning": "Guten Morgen, {username}!",
|
||||||
"welcomeDay": "Hoi {username}",
|
"welcomeDay": "Hallo {username}!",
|
||||||
"welcomeEvening": "Guete Abig, {username}",
|
"welcomeEvening": "Guten Abend, {username}!",
|
||||||
"lastViewed": "Zletscht ahglueget",
|
"lastViewed": "Zletscht ahglueget",
|
||||||
"list": {
|
"list": {
|
||||||
"newText": "Du chasch e Liste für dini neue Uufgabe erstelle:",
|
"newText": "Du chasch e Liste für dini neue Uufgabe erstelle:",
|
||||||
|
@ -169,6 +169,14 @@
|
||||||
"title": "Liste Titl",
|
"title": "Liste Titl",
|
||||||
"color": "Farb",
|
"color": "Farb",
|
||||||
"lists": "Listene",
|
"lists": "Listene",
|
||||||
|
"list": {
|
||||||
|
"title": "Liste",
|
||||||
|
"add": "Hinzuefüege",
|
||||||
|
"addPlaceholder": "E neui Uufgab erstelle…",
|
||||||
|
"empty": "D'Liste isch momentan leer.",
|
||||||
|
"newTaskCta": "Neui Uufgab erstelle.",
|
||||||
|
"editTask": "Uufgab bearbeite"
|
||||||
|
},
|
||||||
"search": "Schriib, um nachere Liste z'sueche…",
|
"search": "Schriib, um nachere Liste z'sueche…",
|
||||||
"searchSelect": "Druck uf Enter um die Liste uuszwähle",
|
"searchSelect": "Druck uf Enter um die Liste uuszwähle",
|
||||||
"shared": "Teilti Liste",
|
"shared": "Teilti Liste",
|
||||||
|
@ -270,14 +278,6 @@
|
||||||
"delete": "Chüble"
|
"delete": "Chüble"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"list": {
|
|
||||||
"title": "Liste",
|
|
||||||
"add": "Hinzuefüege",
|
|
||||||
"addPlaceholder": "E neui Uufgab erstelle…",
|
|
||||||
"empty": "D'Liste isch momentan leer.",
|
|
||||||
"newTaskCta": "Neui Uufgab erstelle.",
|
|
||||||
"editTask": "Uufgab bearbeite"
|
|
||||||
},
|
|
||||||
"gantt": {
|
"gantt": {
|
||||||
"title": "Gantt",
|
"title": "Gantt",
|
||||||
"showTasksWithoutDates": "Zeig Uufgabe, wo kei Date hend",
|
"showTasksWithoutDates": "Zeig Uufgabe, wo kei Date hend",
|
||||||
|
@ -335,7 +335,7 @@
|
||||||
"create": {
|
"create": {
|
||||||
"title": "Neuer Namespace",
|
"title": "Neuer Namespace",
|
||||||
"titleRequired": "Bitte gib en Titl ah.",
|
"titleRequired": "Bitte gib en Titl ah.",
|
||||||
"explanation": "Ein Namespace ist eine Sammlung von Listen, die du teilen und zur Organisation verwenden kannst. Jede Liste zu einem Namespace.",
|
"explanation": "Ein Namespace ist eine Sammlung von Listen, die du teilen und zur Organisation verwenden kannst. Jede Liste gehört zu einem Namespace.",
|
||||||
"tooltip": "Was isch en Namensruum?",
|
"tooltip": "Was isch en Namensruum?",
|
||||||
"success": "Namensruum erstellt."
|
"success": "Namensruum erstellt."
|
||||||
},
|
},
|
||||||
|
@ -672,13 +672,23 @@
|
||||||
"updated": "Aktualisiert"
|
"updated": "Aktualisiert"
|
||||||
},
|
},
|
||||||
"subscription": {
|
"subscription": {
|
||||||
"subscribedThroughParent": "Du chasch da nid deabonnierä, weil du zu dere {entity} durch {parent} dezue abonniert bisch.",
|
"subscribedListThroughParentNamespace": "Du kannst hier nicht de-abonnieren, da du diese Liste über ihren Namespace abonniert hast.",
|
||||||
"subscribed": "Du bisch momentan zu dere {entity} abonniert und bechunsch Benachrichtigunge für Änderige.",
|
"subscribedTaskThroughParentNamespace": "Du kannst hier nicht de-abonnieren, da du diese Aufgabe über ihren Namespace abonniert hast.",
|
||||||
"notSubscribed": "Du bisch momentan nid zu dere {entity} abonniert und bechunsch kei Benachrichtigunge für Änderige.",
|
"subscribedTaskThroughParentList": "Du kannst hier nicht de-abonnieren, da du diese Aufgabe über ihre Liste abonniert hast.",
|
||||||
|
"subscribedNamespace": "Du hast diesen Namespace abonniert und erhältst Benachrichtigungen über Änderungen.",
|
||||||
|
"notSubscribedNamespace": "Du hast diesen Namespace nicht abonniert und erhältst keine Benachrichtigungen über Änderungen.",
|
||||||
|
"subscribedList": "Du hast diese Liste abonniert und erhältst Benachrichtigungen über Änderungen.",
|
||||||
|
"notSubscribedList": "Du hast diese Liste nicht abonniert und erhältst keine Benachrichtigungen über Änderungen.",
|
||||||
|
"subscribedTask": "Du hast diese Aufgabe abonniert und erhältst Benachrichtigungen über Änderungen.",
|
||||||
|
"notSubscribedTask": "Du hast diese Aufgabe nicht abonniert und erhältst keine Benachrichtigungen über Änderungen.",
|
||||||
"subscribe": "Abooniere",
|
"subscribe": "Abooniere",
|
||||||
"unsubscribe": "Deabonniere",
|
"unsubscribe": "Deabonniere",
|
||||||
"subscribeSuccess": "Du hesch die {entity} abonniert",
|
"subscribeSuccessNamespace": "Du hast diesen Namespace jetzt abonniert",
|
||||||
"unsubscribeSuccess": "Du hesch die {entity} deabonniert"
|
"unsubscribeSuccessNamespace": "Du hast diesen Namespace jetzt nicht mehr abonniert",
|
||||||
|
"subscribeSuccessList": "Du hast diese Liste jetzt abonniert",
|
||||||
|
"unsubscribeSuccessList": "Du hast diese Liste jetzt nicht mehr abonniert",
|
||||||
|
"subscribeSuccessTask": "Du hast diese Aufgabe jetzt abonniert",
|
||||||
|
"unsubscribeSuccessTask": "Du hast diese Aufgabe jetzt nicht mehr abonniert"
|
||||||
},
|
},
|
||||||
"attachment": {
|
"attachment": {
|
||||||
"title": "Aahhäng",
|
"title": "Aahhäng",
|
||||||
|
@ -690,7 +700,11 @@
|
||||||
"deleteTooltip": "De Aahhang lösche",
|
"deleteTooltip": "De Aahhang lösche",
|
||||||
"deleteText1": "Bisch du dir sicher, dass du de Aahang {filename} lösche wetsch?",
|
"deleteText1": "Bisch du dir sicher, dass du de Aahang {filename} lösche wetsch?",
|
||||||
"copyUrl": "URL Kopierä",
|
"copyUrl": "URL Kopierä",
|
||||||
"copyUrlTooltip": "D'Url vo dem Aahang kopiere, um sie im Text zbruuche"
|
"copyUrlTooltip": "D'Url vo dem Aahang kopiere, um sie im Text zbruuche",
|
||||||
|
"setAsCover": "Als Titelbild setzen",
|
||||||
|
"unsetAsCover": "Titelbild entfernen",
|
||||||
|
"successfullyChangedCoverImage": "Das Titelbild wurde erfolgreich geändert.",
|
||||||
|
"usedAsCover": "Titelbild"
|
||||||
},
|
},
|
||||||
"comment": {
|
"comment": {
|
||||||
"title": "Kommentär",
|
"title": "Kommentär",
|
||||||
|
@ -839,6 +853,12 @@
|
||||||
"text1": "Bisch du dir sicher, dass du de Benutzer usm Team werfe wetsch?",
|
"text1": "Bisch du dir sicher, dass du de Benutzer usm Team werfe wetsch?",
|
||||||
"text2": "Diese:r Benutzer:in verliert den Zugriff auf alle Listen und Namespaces auf die dieses Team Zugriff hat. Dies kann nicht rückgängig gemacht werden!",
|
"text2": "Diese:r Benutzer:in verliert den Zugriff auf alle Listen und Namespaces auf die dieses Team Zugriff hat. Dies kann nicht rückgängig gemacht werden!",
|
||||||
"success": "Benutzer erfolgriich usegworfe."
|
"success": "Benutzer erfolgriich usegworfe."
|
||||||
|
},
|
||||||
|
"leave": {
|
||||||
|
"title": "Team verlassen",
|
||||||
|
"text1": "Bist du sicher, dass du dieses Team verlassen willst?",
|
||||||
|
"text2": "Du wirst Zugriff auf alle Listen und Namespaces verlieren, auf die dieses Team Zugriff hat. Wenn du deine Meinung änderst, musst du durch einen Team-Admin wieder hinzugefügt werden.",
|
||||||
|
"success": "Du hast das Team erfolgreich verlassen."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"attributes": {
|
"attributes": {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
{
|
{
|
||||||
"home": {
|
"home": {
|
||||||
"welcomeNight": "Good Night {username}",
|
"welcomeNight": "Good Night {username}!",
|
||||||
"welcomeMorning": "Good Morning {username}",
|
"welcomeMorning": "Good Morning {username}!",
|
||||||
"welcomeDay": "Hi {username}",
|
"welcomeDay": "Hi {username}!",
|
||||||
"welcomeEvening": "Good Evening {username}",
|
"welcomeEvening": "Good Evening {username}!",
|
||||||
"lastViewed": "Last viewed",
|
"lastViewed": "Last viewed",
|
||||||
"list": {
|
"list": {
|
||||||
"newText": "You can create a new list for your new tasks:",
|
"newText": "You can create a new list for your new tasks:",
|
||||||
|
@ -169,6 +169,7 @@
|
||||||
"title": "List Title",
|
"title": "List Title",
|
||||||
"color": "Color",
|
"color": "Color",
|
||||||
"lists": "Lists",
|
"lists": "Lists",
|
||||||
|
"list": "List",
|
||||||
"search": "Type to search for a list…",
|
"search": "Type to search for a list…",
|
||||||
"searchSelect": "Click or press enter to select this list",
|
"searchSelect": "Click or press enter to select this list",
|
||||||
"shared": "Shared Lists",
|
"shared": "Shared Lists",
|
||||||
|
@ -675,13 +676,23 @@
|
||||||
"updated": "Updated"
|
"updated": "Updated"
|
||||||
},
|
},
|
||||||
"subscription": {
|
"subscription": {
|
||||||
"subscribedThroughParent": "You can't unsubscribe here because you are subscribed to this {entity} through its {parent}.",
|
"subscribedListThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this list through its namespace.",
|
||||||
"subscribed": "You are currently subscribed to this {entity} and will receive notifications for changes.",
|
"subscribedTaskThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this task through its namespace.",
|
||||||
"notSubscribed": "You are not subscribed to this {entity} and won't receive notifications for changes.",
|
"subscribedTaskThroughParentList": "You can't unsubscribe here because you are subscribed to this task through its list.",
|
||||||
|
"subscribedNamespace": "You are currently subscribed to this namespace and will receive notifications for changes.",
|
||||||
|
"notSubscribedNamespace": "You are not subscribed to this namespace and won't receive notifications for changes.",
|
||||||
|
"subscribedList": "You are currently subscribed to this list and will receive notifications for changes.",
|
||||||
|
"notSubscribedList": "You are not subscribed to this list and won't receive notifications for changes.",
|
||||||
|
"subscribedTask": "You are currently subscribed to this task and will receive notifications for changes.",
|
||||||
|
"notSubscribedTask": "You are not subscribed to this task and won't receive notifications for changes.",
|
||||||
"subscribe": "Subscribe",
|
"subscribe": "Subscribe",
|
||||||
"unsubscribe": "Unsubscribe",
|
"unsubscribe": "Unsubscribe",
|
||||||
"subscribeSuccess": "You are now subscribed to this {entity}",
|
"subscribeSuccessNamespace": "You are now subscribed to this namespace",
|
||||||
"unsubscribeSuccess": "You are now unsubscribed to this {entity}"
|
"unsubscribeSuccessNamespace": "You are now unsubscribed to this namespace",
|
||||||
|
"subscribeSuccessList": "You are now subscribed to this list",
|
||||||
|
"unsubscribeSuccessList": "You are now unsubscribed to this list",
|
||||||
|
"subscribeSuccessTask": "You are now subscribed to this task",
|
||||||
|
"unsubscribeSuccessTask": "You are now unsubscribed to this task"
|
||||||
},
|
},
|
||||||
"attachment": {
|
"attachment": {
|
||||||
"title": "Attachments",
|
"title": "Attachments",
|
||||||
|
@ -693,7 +704,11 @@
|
||||||
"deleteTooltip": "Delete this attachment",
|
"deleteTooltip": "Delete this attachment",
|
||||||
"deleteText1": "Are you sure you want to delete the attachment {filename}?",
|
"deleteText1": "Are you sure you want to delete the attachment {filename}?",
|
||||||
"copyUrl": "Copy URL",
|
"copyUrl": "Copy URL",
|
||||||
"copyUrlTooltip": "Copy the url of this attachment for usage in text"
|
"copyUrlTooltip": "Copy the url of this attachment for usage in text",
|
||||||
|
"setAsCover": "Make cover",
|
||||||
|
"unsetAsCover": "Remove cover",
|
||||||
|
"successfullyChangedCoverImage": "The cover image was successfully changed.",
|
||||||
|
"usedAsCover": "Cover image"
|
||||||
},
|
},
|
||||||
"comment": {
|
"comment": {
|
||||||
"title": "Comments",
|
"title": "Comments",
|
||||||
|
@ -842,6 +857,12 @@
|
||||||
"text1": "Are you sure you want to remove this user from the team?",
|
"text1": "Are you sure you want to remove this user from the team?",
|
||||||
"text2": "They will lose access to all lists and namespaces this team has access to. This CANNOT BE UNDONE!",
|
"text2": "They will lose access to all lists and namespaces this team has access to. This CANNOT BE UNDONE!",
|
||||||
"success": "The user was successfully deleted from the team."
|
"success": "The user was successfully deleted from the team."
|
||||||
|
},
|
||||||
|
"leave": {
|
||||||
|
"title": "Leave team",
|
||||||
|
"text1": "Are you sure you want to leave this team?",
|
||||||
|
"text2": "You will loose access to all lists and namespaces this team has access to. If you change your mind you'll need a team admin to add you again.",
|
||||||
|
"success": "You have successfully left the team."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"attributes": {
|
"attributes": {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
{
|
{
|
||||||
"home": {
|
"home": {
|
||||||
"welcomeNight": "Good Night {username}",
|
"welcomeNight": "Good Night {username}!",
|
||||||
"welcomeMorning": "Good Morning {username}",
|
"welcomeMorning": "Good Morning {username}!",
|
||||||
"welcomeDay": "Hi {username}",
|
"welcomeDay": "Hi {username}!",
|
||||||
"welcomeEvening": "Good Evening {username}",
|
"welcomeEvening": "Good Evening {username}!",
|
||||||
"lastViewed": "Last viewed",
|
"lastViewed": "Last viewed",
|
||||||
"list": {
|
"list": {
|
||||||
"newText": "You can create a new list for your new tasks:",
|
"newText": "You can create a new list for your new tasks:",
|
||||||
|
@ -43,7 +43,7 @@
|
||||||
"confirmEmailSuccess": "You successfully confirmed your email! You can log in now.",
|
"confirmEmailSuccess": "You successfully confirmed your email! You can log in now.",
|
||||||
"totpTitle": "Two Factor Authentication Code",
|
"totpTitle": "Two Factor Authentication Code",
|
||||||
"totpPlaceholder": "e.g. 123456",
|
"totpPlaceholder": "e.g. 123456",
|
||||||
"login": "Login",
|
"login": "Iniciar sesión",
|
||||||
"createAccount": "Create account",
|
"createAccount": "Create account",
|
||||||
"loginWith": "Log in with {provider}",
|
"loginWith": "Log in with {provider}",
|
||||||
"authenticating": "Authenticating…",
|
"authenticating": "Authenticating…",
|
||||||
|
@ -169,6 +169,14 @@
|
||||||
"title": "List Title",
|
"title": "List Title",
|
||||||
"color": "Color",
|
"color": "Color",
|
||||||
"lists": "Lists",
|
"lists": "Lists",
|
||||||
|
"list": {
|
||||||
|
"title": "List",
|
||||||
|
"add": "Add",
|
||||||
|
"addPlaceholder": "Add a new task…",
|
||||||
|
"empty": "This list is currently empty.",
|
||||||
|
"newTaskCta": "Create a new task.",
|
||||||
|
"editTask": "Edit Task"
|
||||||
|
},
|
||||||
"search": "Type to search for a list…",
|
"search": "Type to search for a list…",
|
||||||
"searchSelect": "Click or press enter to select this list",
|
"searchSelect": "Click or press enter to select this list",
|
||||||
"shared": "Shared Lists",
|
"shared": "Shared Lists",
|
||||||
|
@ -270,14 +278,6 @@
|
||||||
"delete": "Delete"
|
"delete": "Delete"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"list": {
|
|
||||||
"title": "List",
|
|
||||||
"add": "Add",
|
|
||||||
"addPlaceholder": "Add a new task…",
|
|
||||||
"empty": "This list is currently empty.",
|
|
||||||
"newTaskCta": "Create a new task.",
|
|
||||||
"editTask": "Edit Task"
|
|
||||||
},
|
|
||||||
"gantt": {
|
"gantt": {
|
||||||
"title": "Gantt",
|
"title": "Gantt",
|
||||||
"showTasksWithoutDates": "Show tasks which don't have dates set",
|
"showTasksWithoutDates": "Show tasks which don't have dates set",
|
||||||
|
@ -672,13 +672,23 @@
|
||||||
"updated": "Updated"
|
"updated": "Updated"
|
||||||
},
|
},
|
||||||
"subscription": {
|
"subscription": {
|
||||||
"subscribedThroughParent": "You can't unsubscribe here because you are subscribed to this {entity} through its {parent}.",
|
"subscribedListThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this list through its namespace.",
|
||||||
"subscribed": "You are currently subscribed to this {entity} and will receive notifications for changes.",
|
"subscribedTaskThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this task through its namespace.",
|
||||||
"notSubscribed": "You are not subscribed to this {entity} and won't receive notifications for changes.",
|
"subscribedTaskThroughParentList": "You can't unsubscribe here because you are subscribed to this task through its list.",
|
||||||
|
"subscribedNamespace": "You are currently subscribed to this namespace and will receive notifications for changes.",
|
||||||
|
"notSubscribedNamespace": "You are not subscribed to this namespace and won't receive notifications for changes.",
|
||||||
|
"subscribedList": "You are currently subscribed to this list and will receive notifications for changes.",
|
||||||
|
"notSubscribedList": "You are not subscribed to this list and won't receive notifications for changes.",
|
||||||
|
"subscribedTask": "You are currently subscribed to this task and will receive notifications for changes.",
|
||||||
|
"notSubscribedTask": "You are not subscribed to this task and won't receive notifications for changes.",
|
||||||
"subscribe": "Subscribe",
|
"subscribe": "Subscribe",
|
||||||
"unsubscribe": "Unsubscribe",
|
"unsubscribe": "Unsubscribe",
|
||||||
"subscribeSuccess": "You are now subscribed to this {entity}",
|
"subscribeSuccessNamespace": "You are now subscribed to this namespace",
|
||||||
"unsubscribeSuccess": "You are now unsubscribed to this {entity}"
|
"unsubscribeSuccessNamespace": "You are now unsubscribed to this namespace",
|
||||||
|
"subscribeSuccessList": "You are now subscribed to this list",
|
||||||
|
"unsubscribeSuccessList": "You are now unsubscribed to this list",
|
||||||
|
"subscribeSuccessTask": "You are now subscribed to this task",
|
||||||
|
"unsubscribeSuccessTask": "You are now unsubscribed to this task"
|
||||||
},
|
},
|
||||||
"attachment": {
|
"attachment": {
|
||||||
"title": "Attachments",
|
"title": "Attachments",
|
||||||
|
@ -690,7 +700,11 @@
|
||||||
"deleteTooltip": "Delete this attachment",
|
"deleteTooltip": "Delete this attachment",
|
||||||
"deleteText1": "Are you sure you want to delete the attachment {filename}?",
|
"deleteText1": "Are you sure you want to delete the attachment {filename}?",
|
||||||
"copyUrl": "Copy URL",
|
"copyUrl": "Copy URL",
|
||||||
"copyUrlTooltip": "Copy the url of this attachment for usage in text"
|
"copyUrlTooltip": "Copy the url of this attachment for usage in text",
|
||||||
|
"setAsCover": "Make cover",
|
||||||
|
"unsetAsCover": "Remove cover",
|
||||||
|
"successfullyChangedCoverImage": "The cover image was successfully changed.",
|
||||||
|
"usedAsCover": "Cover image"
|
||||||
},
|
},
|
||||||
"comment": {
|
"comment": {
|
||||||
"title": "Comments",
|
"title": "Comments",
|
||||||
|
@ -839,6 +853,12 @@
|
||||||
"text1": "Are you sure you want to remove this user from the team?",
|
"text1": "Are you sure you want to remove this user from the team?",
|
||||||
"text2": "They will lose access to all lists and namespaces this team has access to. This CANNOT BE UNDONE!",
|
"text2": "They will lose access to all lists and namespaces this team has access to. This CANNOT BE UNDONE!",
|
||||||
"success": "The user was successfully deleted from the team."
|
"success": "The user was successfully deleted from the team."
|
||||||
|
},
|
||||||
|
"leave": {
|
||||||
|
"title": "Leave team",
|
||||||
|
"text1": "Are you sure you want to leave this team?",
|
||||||
|
"text2": "You will loose access to all lists and namespaces this team has access to. If you change your mind you'll need a team admin to add you again.",
|
||||||
|
"success": "You have successfully left the team."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"attributes": {
|
"attributes": {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
{
|
{
|
||||||
"home": {
|
"home": {
|
||||||
"welcomeNight": "Bonne nuit {username}",
|
"welcomeNight": "Good Night {username}!",
|
||||||
"welcomeMorning": "Bonjour {username}",
|
"welcomeMorning": "Good Morning {username}!",
|
||||||
"welcomeDay": "Salut {username}",
|
"welcomeDay": "Hi {username}!",
|
||||||
"welcomeEvening": "Bonsoir {username}",
|
"welcomeEvening": "Good Evening {username}!",
|
||||||
"lastViewed": "Dernière consultation",
|
"lastViewed": "Dernière consultation",
|
||||||
"list": {
|
"list": {
|
||||||
"newText": "Tu peux créer une nouvelle liste pour tes nouvelles tâches :",
|
"newText": "Tu peux créer une nouvelle liste pour tes nouvelles tâches :",
|
||||||
|
@ -169,6 +169,14 @@
|
||||||
"title": "Nom de la liste",
|
"title": "Nom de la liste",
|
||||||
"color": "Couleur",
|
"color": "Couleur",
|
||||||
"lists": "Listes",
|
"lists": "Listes",
|
||||||
|
"list": {
|
||||||
|
"title": "Liste",
|
||||||
|
"add": "Ajouter",
|
||||||
|
"addPlaceholder": "Ajouter une nouvelle tâche…",
|
||||||
|
"empty": "Cette liste est actuellement vide.",
|
||||||
|
"newTaskCta": "Créer une nouvelle tâche.",
|
||||||
|
"editTask": "Modifier la tâche"
|
||||||
|
},
|
||||||
"search": "Écris pour rechercher une liste…",
|
"search": "Écris pour rechercher une liste…",
|
||||||
"searchSelect": "Clique ou appuie sur la touche Entrée pour sélectionner cette liste",
|
"searchSelect": "Clique ou appuie sur la touche Entrée pour sélectionner cette liste",
|
||||||
"shared": "Listes partagées",
|
"shared": "Listes partagées",
|
||||||
|
@ -270,14 +278,6 @@
|
||||||
"delete": "Supprimer"
|
"delete": "Supprimer"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"list": {
|
|
||||||
"title": "Liste",
|
|
||||||
"add": "Ajouter",
|
|
||||||
"addPlaceholder": "Ajouter une nouvelle tâche…",
|
|
||||||
"empty": "Cette liste est actuellement vide.",
|
|
||||||
"newTaskCta": "Créer une nouvelle tâche.",
|
|
||||||
"editTask": "Modifier la tâche"
|
|
||||||
},
|
|
||||||
"gantt": {
|
"gantt": {
|
||||||
"title": "Gantt",
|
"title": "Gantt",
|
||||||
"showTasksWithoutDates": "Afficher les tâches pour lesquelles aucune date n’a été fixée",
|
"showTasksWithoutDates": "Afficher les tâches pour lesquelles aucune date n’a été fixée",
|
||||||
|
@ -672,13 +672,23 @@
|
||||||
"updated": "Mis à jour"
|
"updated": "Mis à jour"
|
||||||
},
|
},
|
||||||
"subscription": {
|
"subscription": {
|
||||||
"subscribedThroughParent": "Tu ne peux pas te désabonner ici car tu es abonné·e à cette {entity} par le biais de son {parent}.",
|
"subscribedListThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this list through its namespace.",
|
||||||
"subscribed": "Tu es actuellement abonné·e à cette {entity} et recevras des notifications pour les changements.",
|
"subscribedTaskThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this task through its namespace.",
|
||||||
"notSubscribed": "Tu n’es pas abonné·e à cette {entity} et ne recevras pas de notifications pour les changements.",
|
"subscribedTaskThroughParentList": "You can't unsubscribe here because you are subscribed to this task through its list.",
|
||||||
|
"subscribedNamespace": "You are currently subscribed to this namespace and will receive notifications for changes.",
|
||||||
|
"notSubscribedNamespace": "You are not subscribed to this namespace and won't receive notifications for changes.",
|
||||||
|
"subscribedList": "You are currently subscribed to this list and will receive notifications for changes.",
|
||||||
|
"notSubscribedList": "You are not subscribed to this list and won't receive notifications for changes.",
|
||||||
|
"subscribedTask": "You are currently subscribed to this task and will receive notifications for changes.",
|
||||||
|
"notSubscribedTask": "You are not subscribed to this task and won't receive notifications for changes.",
|
||||||
"subscribe": "S’abonner",
|
"subscribe": "S’abonner",
|
||||||
"unsubscribe": "Se désabonner",
|
"unsubscribe": "Se désabonner",
|
||||||
"subscribeSuccess": "Tu es maintenant abonné·e à cette {entity}",
|
"subscribeSuccessNamespace": "You are now subscribed to this namespace",
|
||||||
"unsubscribeSuccess": "Tu es maintenant désabonné·e de cette {entity}"
|
"unsubscribeSuccessNamespace": "You are now unsubscribed to this namespace",
|
||||||
|
"subscribeSuccessList": "You are now subscribed to this list",
|
||||||
|
"unsubscribeSuccessList": "You are now unsubscribed to this list",
|
||||||
|
"subscribeSuccessTask": "You are now subscribed to this task",
|
||||||
|
"unsubscribeSuccessTask": "You are now unsubscribed to this task"
|
||||||
},
|
},
|
||||||
"attachment": {
|
"attachment": {
|
||||||
"title": "Pièces jointes",
|
"title": "Pièces jointes",
|
||||||
|
@ -690,7 +700,11 @@
|
||||||
"deleteTooltip": "Supprimer cette pièce jointe",
|
"deleteTooltip": "Supprimer cette pièce jointe",
|
||||||
"deleteText1": "Supprimer la pièce jointe {filename} ?",
|
"deleteText1": "Supprimer la pièce jointe {filename} ?",
|
||||||
"copyUrl": "Copier l’URL",
|
"copyUrl": "Copier l’URL",
|
||||||
"copyUrlTooltip": "Copier l’URL de cette pièce jointe pour l’utiliser dans le texte"
|
"copyUrlTooltip": "Copier l’URL de cette pièce jointe pour l’utiliser dans le texte",
|
||||||
|
"setAsCover": "Make cover",
|
||||||
|
"unsetAsCover": "Remove cover",
|
||||||
|
"successfullyChangedCoverImage": "The cover image was successfully changed.",
|
||||||
|
"usedAsCover": "Cover image"
|
||||||
},
|
},
|
||||||
"comment": {
|
"comment": {
|
||||||
"title": "Commentaires",
|
"title": "Commentaires",
|
||||||
|
@ -839,6 +853,12 @@
|
||||||
"text1": "Retirer cette personne de l’équipe ?",
|
"text1": "Retirer cette personne de l’équipe ?",
|
||||||
"text2": "Ils perdront l'accès à toutes les listes et espaces de noms auxquels cette équipe a accès. Ceci NE PEUT PAS ÊTRE ANNULÉ !",
|
"text2": "Ils perdront l'accès à toutes les listes et espaces de noms auxquels cette équipe a accès. Ceci NE PEUT PAS ÊTRE ANNULÉ !",
|
||||||
"success": "Utilisateur·rice retiré·e de l’équipe."
|
"success": "Utilisateur·rice retiré·e de l’équipe."
|
||||||
|
},
|
||||||
|
"leave": {
|
||||||
|
"title": "Leave team",
|
||||||
|
"text1": "Are you sure you want to leave this team?",
|
||||||
|
"text2": "You will loose access to all lists and namespaces this team has access to. If you change your mind you'll need a team admin to add you again.",
|
||||||
|
"success": "You have successfully left the team."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"attributes": {
|
"attributes": {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
{
|
{
|
||||||
"home": {
|
"home": {
|
||||||
"welcomeNight": "Buonanotte {username}",
|
"welcomeNight": "Good Night {username}!",
|
||||||
"welcomeMorning": "Buongiorno {username}",
|
"welcomeMorning": "Good Morning {username}!",
|
||||||
"welcomeDay": "Ciao {username}",
|
"welcomeDay": "Hi {username}!",
|
||||||
"welcomeEvening": "Buonasera {username}",
|
"welcomeEvening": "Good Evening {username}!",
|
||||||
"lastViewed": "Ultima visualizzazione",
|
"lastViewed": "Ultima visualizzazione",
|
||||||
"list": {
|
"list": {
|
||||||
"newText": "È possibile creare una nuova lista per le nuove attività:",
|
"newText": "È possibile creare una nuova lista per le nuove attività:",
|
||||||
|
@ -169,6 +169,14 @@
|
||||||
"title": "Titolo della Lista",
|
"title": "Titolo della Lista",
|
||||||
"color": "Colore",
|
"color": "Colore",
|
||||||
"lists": "Liste",
|
"lists": "Liste",
|
||||||
|
"list": {
|
||||||
|
"title": "Lista",
|
||||||
|
"add": "Aggiungi",
|
||||||
|
"addPlaceholder": "Aggiungi una nuova attività…",
|
||||||
|
"empty": "Questa lista è attualmente vuota.",
|
||||||
|
"newTaskCta": "Crea una nuova attività.",
|
||||||
|
"editTask": "Modifica Attività"
|
||||||
|
},
|
||||||
"search": "Digita per cercare una lista…",
|
"search": "Digita per cercare una lista…",
|
||||||
"searchSelect": "Fare clic o premere invio per selezionare questa lista",
|
"searchSelect": "Fare clic o premere invio per selezionare questa lista",
|
||||||
"shared": "Liste Condivise",
|
"shared": "Liste Condivise",
|
||||||
|
@ -270,14 +278,6 @@
|
||||||
"delete": "Elimina"
|
"delete": "Elimina"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"list": {
|
|
||||||
"title": "Lista",
|
|
||||||
"add": "Aggiungi",
|
|
||||||
"addPlaceholder": "Aggiungi una nuova attività…",
|
|
||||||
"empty": "Questa lista è attualmente vuota.",
|
|
||||||
"newTaskCta": "Crea una nuova attività.",
|
|
||||||
"editTask": "Modifica Attività"
|
|
||||||
},
|
|
||||||
"gantt": {
|
"gantt": {
|
||||||
"title": "Gantt",
|
"title": "Gantt",
|
||||||
"showTasksWithoutDates": "Mostra attività che non hanno date impostate",
|
"showTasksWithoutDates": "Mostra attività che non hanno date impostate",
|
||||||
|
@ -672,13 +672,23 @@
|
||||||
"updated": "Aggiornato"
|
"updated": "Aggiornato"
|
||||||
},
|
},
|
||||||
"subscription": {
|
"subscription": {
|
||||||
"subscribedThroughParent": "Non puoi annullare l'iscrizione qui perché sei iscritto a questo {entity} attraverso il suo {parent}.",
|
"subscribedListThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this list through its namespace.",
|
||||||
"subscribed": "Sei attualmente iscritto a questo {entity} e riceverai notifiche per le modifiche.",
|
"subscribedTaskThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this task through its namespace.",
|
||||||
"notSubscribed": "Non sei iscritto a questo {entity} e non riceverai notifiche per le modifiche.",
|
"subscribedTaskThroughParentList": "You can't unsubscribe here because you are subscribed to this task through its list.",
|
||||||
|
"subscribedNamespace": "You are currently subscribed to this namespace and will receive notifications for changes.",
|
||||||
|
"notSubscribedNamespace": "You are not subscribed to this namespace and won't receive notifications for changes.",
|
||||||
|
"subscribedList": "You are currently subscribed to this list and will receive notifications for changes.",
|
||||||
|
"notSubscribedList": "You are not subscribed to this list and won't receive notifications for changes.",
|
||||||
|
"subscribedTask": "You are currently subscribed to this task and will receive notifications for changes.",
|
||||||
|
"notSubscribedTask": "You are not subscribed to this task and won't receive notifications for changes.",
|
||||||
"subscribe": "Iscriviti",
|
"subscribe": "Iscriviti",
|
||||||
"unsubscribe": "Disiscriviti",
|
"unsubscribe": "Disiscriviti",
|
||||||
"subscribeSuccess": "Ti sei iscritto a questo {entity}",
|
"subscribeSuccessNamespace": "You are now subscribed to this namespace",
|
||||||
"unsubscribeSuccess": "Ti sei disiscritto a questo {entity}"
|
"unsubscribeSuccessNamespace": "You are now unsubscribed to this namespace",
|
||||||
|
"subscribeSuccessList": "You are now subscribed to this list",
|
||||||
|
"unsubscribeSuccessList": "You are now unsubscribed to this list",
|
||||||
|
"subscribeSuccessTask": "You are now subscribed to this task",
|
||||||
|
"unsubscribeSuccessTask": "You are now unsubscribed to this task"
|
||||||
},
|
},
|
||||||
"attachment": {
|
"attachment": {
|
||||||
"title": "Allegati",
|
"title": "Allegati",
|
||||||
|
@ -690,7 +700,11 @@
|
||||||
"deleteTooltip": "Elimina questo allegato",
|
"deleteTooltip": "Elimina questo allegato",
|
||||||
"deleteText1": "Sei sicuro di voler eliminare l'allegato {filename}?",
|
"deleteText1": "Sei sicuro di voler eliminare l'allegato {filename}?",
|
||||||
"copyUrl": "Copia URL",
|
"copyUrl": "Copia URL",
|
||||||
"copyUrlTooltip": "Copia l'URL di questo allegato per usarlo nel testo"
|
"copyUrlTooltip": "Copia l'URL di questo allegato per usarlo nel testo",
|
||||||
|
"setAsCover": "Make cover",
|
||||||
|
"unsetAsCover": "Remove cover",
|
||||||
|
"successfullyChangedCoverImage": "The cover image was successfully changed.",
|
||||||
|
"usedAsCover": "Cover image"
|
||||||
},
|
},
|
||||||
"comment": {
|
"comment": {
|
||||||
"title": "Commenti",
|
"title": "Commenti",
|
||||||
|
@ -839,6 +853,12 @@
|
||||||
"text1": "Confermi di voler rimuovere questo utente dal gruppo?",
|
"text1": "Confermi di voler rimuovere questo utente dal gruppo?",
|
||||||
"text2": "Perderanno l'accesso a tutte le liste e i namespace a cui questo gruppo ha accesso. NON PUÒ ESSERE RIPRISTINATO!",
|
"text2": "Perderanno l'accesso a tutte le liste e i namespace a cui questo gruppo ha accesso. NON PUÒ ESSERE RIPRISTINATO!",
|
||||||
"success": "Utente rimosso dal gruppo."
|
"success": "Utente rimosso dal gruppo."
|
||||||
|
},
|
||||||
|
"leave": {
|
||||||
|
"title": "Leave team",
|
||||||
|
"text1": "Are you sure you want to leave this team?",
|
||||||
|
"text2": "You will loose access to all lists and namespaces this team has access to. If you change your mind you'll need a team admin to add you again.",
|
||||||
|
"success": "You have successfully left the team."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"attributes": {
|
"attributes": {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
{
|
{
|
||||||
"home": {
|
"home": {
|
||||||
"welcomeNight": "Goede nacht {username}",
|
"welcomeNight": "Good Night {username}!",
|
||||||
"welcomeMorning": "Goedemorgen {username}",
|
"welcomeMorning": "Good Morning {username}!",
|
||||||
"welcomeDay": "Hallo {username}",
|
"welcomeDay": "Hi {username}!",
|
||||||
"welcomeEvening": "Goedenavond {username}",
|
"welcomeEvening": "Good Evening {username}!",
|
||||||
"lastViewed": "Laatst bekeken",
|
"lastViewed": "Laatst bekeken",
|
||||||
"list": {
|
"list": {
|
||||||
"newText": "Je kan een nieuwe lijst maken voor je nieuwe taken:",
|
"newText": "Je kan een nieuwe lijst maken voor je nieuwe taken:",
|
||||||
|
@ -169,6 +169,14 @@
|
||||||
"title": "Lijst titel",
|
"title": "Lijst titel",
|
||||||
"color": "Kleur",
|
"color": "Kleur",
|
||||||
"lists": "Lijsten",
|
"lists": "Lijsten",
|
||||||
|
"list": {
|
||||||
|
"title": "Lijst",
|
||||||
|
"add": "Toevoegen",
|
||||||
|
"addPlaceholder": "Voeg een nieuwe taak toe…",
|
||||||
|
"empty": "Deze lijst is momenteel leeg.",
|
||||||
|
"newTaskCta": "Creëer een nieuwe taak.",
|
||||||
|
"editTask": "Taak bewerken"
|
||||||
|
},
|
||||||
"search": "Typ om naar een lijst te zoeken…",
|
"search": "Typ om naar een lijst te zoeken…",
|
||||||
"searchSelect": "Klik of druk op enter om deze lijst te selecteren",
|
"searchSelect": "Klik of druk op enter om deze lijst te selecteren",
|
||||||
"shared": "Gedeelde lijsten",
|
"shared": "Gedeelde lijsten",
|
||||||
|
@ -270,14 +278,6 @@
|
||||||
"delete": "Verwijderen"
|
"delete": "Verwijderen"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"list": {
|
|
||||||
"title": "Lijst",
|
|
||||||
"add": "Toevoegen",
|
|
||||||
"addPlaceholder": "Voeg een nieuwe taak toe…",
|
|
||||||
"empty": "Deze lijst is momenteel leeg.",
|
|
||||||
"newTaskCta": "Creëer een nieuwe taak.",
|
|
||||||
"editTask": "Taak bewerken"
|
|
||||||
},
|
|
||||||
"gantt": {
|
"gantt": {
|
||||||
"title": "Gantt",
|
"title": "Gantt",
|
||||||
"showTasksWithoutDates": "Toon taken waarvoor geen datums zijn ingesteld",
|
"showTasksWithoutDates": "Toon taken waarvoor geen datums zijn ingesteld",
|
||||||
|
@ -672,13 +672,23 @@
|
||||||
"updated": "Bijgewerkt"
|
"updated": "Bijgewerkt"
|
||||||
},
|
},
|
||||||
"subscription": {
|
"subscription": {
|
||||||
"subscribedThroughParent": "You can't unsubscribe here because you are subscribed to this {entity} through its {parent}.",
|
"subscribedListThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this list through its namespace.",
|
||||||
"subscribed": "You are currently subscribed to this {entity} and will receive notifications for changes.",
|
"subscribedTaskThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this task through its namespace.",
|
||||||
"notSubscribed": "You are not subscribed to this {entity} and won't receive notifications for changes.",
|
"subscribedTaskThroughParentList": "You can't unsubscribe here because you are subscribed to this task through its list.",
|
||||||
|
"subscribedNamespace": "You are currently subscribed to this namespace and will receive notifications for changes.",
|
||||||
|
"notSubscribedNamespace": "You are not subscribed to this namespace and won't receive notifications for changes.",
|
||||||
|
"subscribedList": "You are currently subscribed to this list and will receive notifications for changes.",
|
||||||
|
"notSubscribedList": "You are not subscribed to this list and won't receive notifications for changes.",
|
||||||
|
"subscribedTask": "You are currently subscribed to this task and will receive notifications for changes.",
|
||||||
|
"notSubscribedTask": "You are not subscribed to this task and won't receive notifications for changes.",
|
||||||
"subscribe": "Subscribe",
|
"subscribe": "Subscribe",
|
||||||
"unsubscribe": "Unsubscribe",
|
"unsubscribe": "Unsubscribe",
|
||||||
"subscribeSuccess": "You are now subscribed to this {entity}",
|
"subscribeSuccessNamespace": "You are now subscribed to this namespace",
|
||||||
"unsubscribeSuccess": "You are now unsubscribed to this {entity}"
|
"unsubscribeSuccessNamespace": "You are now unsubscribed to this namespace",
|
||||||
|
"subscribeSuccessList": "You are now subscribed to this list",
|
||||||
|
"unsubscribeSuccessList": "You are now unsubscribed to this list",
|
||||||
|
"subscribeSuccessTask": "You are now subscribed to this task",
|
||||||
|
"unsubscribeSuccessTask": "You are now unsubscribed to this task"
|
||||||
},
|
},
|
||||||
"attachment": {
|
"attachment": {
|
||||||
"title": "Bijlagen",
|
"title": "Bijlagen",
|
||||||
|
@ -690,7 +700,11 @@
|
||||||
"deleteTooltip": "Verwijder deze bijlage",
|
"deleteTooltip": "Verwijder deze bijlage",
|
||||||
"deleteText1": "Weet je zeker dat je de bijlage {filename} wilt verwijderen?",
|
"deleteText1": "Weet je zeker dat je de bijlage {filename} wilt verwijderen?",
|
||||||
"copyUrl": "URL kopiëren",
|
"copyUrl": "URL kopiëren",
|
||||||
"copyUrlTooltip": "Copy the url of this attachment for usage in text"
|
"copyUrlTooltip": "Copy the url of this attachment for usage in text",
|
||||||
|
"setAsCover": "Make cover",
|
||||||
|
"unsetAsCover": "Remove cover",
|
||||||
|
"successfullyChangedCoverImage": "The cover image was successfully changed.",
|
||||||
|
"usedAsCover": "Cover image"
|
||||||
},
|
},
|
||||||
"comment": {
|
"comment": {
|
||||||
"title": "Reacties",
|
"title": "Reacties",
|
||||||
|
@ -839,6 +853,12 @@
|
||||||
"text1": "Weet je zeker dat je deze gebruiker wilt verwijderen uit het team?",
|
"text1": "Weet je zeker dat je deze gebruiker wilt verwijderen uit het team?",
|
||||||
"text2": "They will lose access to all lists and namespaces this team has access to. This CANNOT BE UNDONE!",
|
"text2": "They will lose access to all lists and namespaces this team has access to. This CANNOT BE UNDONE!",
|
||||||
"success": "The user was successfully deleted from the team."
|
"success": "The user was successfully deleted from the team."
|
||||||
|
},
|
||||||
|
"leave": {
|
||||||
|
"title": "Leave team",
|
||||||
|
"text1": "Are you sure you want to leave this team?",
|
||||||
|
"text2": "You will loose access to all lists and namespaces this team has access to. If you change your mind you'll need a team admin to add you again.",
|
||||||
|
"success": "You have successfully left the team."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"attributes": {
|
"attributes": {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
{
|
{
|
||||||
"home": {
|
"home": {
|
||||||
"welcomeNight": "Dobrej nocy {username}",
|
"welcomeNight": "Good Night {username}!",
|
||||||
"welcomeMorning": "Dzień dobry {username}",
|
"welcomeMorning": "Good Morning {username}!",
|
||||||
"welcomeDay": "Cześć {username}",
|
"welcomeDay": "Hi {username}!",
|
||||||
"welcomeEvening": "Dobry wieczór {username}",
|
"welcomeEvening": "Good Evening {username}!",
|
||||||
"lastViewed": "Ostatnio oglądane",
|
"lastViewed": "Ostatnio oglądane",
|
||||||
"list": {
|
"list": {
|
||||||
"newText": "Możesz stworzyć nową listę dla swoich nowych zadań:",
|
"newText": "Możesz stworzyć nową listę dla swoich nowych zadań:",
|
||||||
|
@ -169,6 +169,14 @@
|
||||||
"title": "Tytuł listy",
|
"title": "Tytuł listy",
|
||||||
"color": "Kolor",
|
"color": "Kolor",
|
||||||
"lists": "Listy",
|
"lists": "Listy",
|
||||||
|
"list": {
|
||||||
|
"title": "Lista",
|
||||||
|
"add": "Dodaj",
|
||||||
|
"addPlaceholder": "Dodaj nowe zadanie…",
|
||||||
|
"empty": "Ta lista jest obecnie pusta.",
|
||||||
|
"newTaskCta": "Utwórz nowe zadanie.",
|
||||||
|
"editTask": "Edytuj zadanie"
|
||||||
|
},
|
||||||
"search": "Wpisz, aby wyszukać listę…",
|
"search": "Wpisz, aby wyszukać listę…",
|
||||||
"searchSelect": "Kliknij lub naciśnij Enter, aby wybrać tę listę",
|
"searchSelect": "Kliknij lub naciśnij Enter, aby wybrać tę listę",
|
||||||
"shared": "Współdzielone listy",
|
"shared": "Współdzielone listy",
|
||||||
|
@ -270,14 +278,6 @@
|
||||||
"delete": "Usuń"
|
"delete": "Usuń"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"list": {
|
|
||||||
"title": "Lista",
|
|
||||||
"add": "Dodaj",
|
|
||||||
"addPlaceholder": "Dodaj nowe zadanie…",
|
|
||||||
"empty": "Ta lista jest obecnie pusta.",
|
|
||||||
"newTaskCta": "Utwórz nowe zadanie.",
|
|
||||||
"editTask": "Edytuj zadanie"
|
|
||||||
},
|
|
||||||
"gantt": {
|
"gantt": {
|
||||||
"title": "Gantt",
|
"title": "Gantt",
|
||||||
"showTasksWithoutDates": "Pokaż zadania, które nie mają ustawionych dat",
|
"showTasksWithoutDates": "Pokaż zadania, które nie mają ustawionych dat",
|
||||||
|
@ -672,13 +672,23 @@
|
||||||
"updated": "Zaktualizowano"
|
"updated": "Zaktualizowano"
|
||||||
},
|
},
|
||||||
"subscription": {
|
"subscription": {
|
||||||
"subscribedThroughParent": "Nie możesz zrezygnować z subskrypcji, ponieważ subskrybujesz {entity} za pośrednictwem {parent}.",
|
"subscribedListThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this list through its namespace.",
|
||||||
"subscribed": "Obecnie subskrybujesz {entity} i będziesz otrzymywać powiadomienia o zmianach.",
|
"subscribedTaskThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this task through its namespace.",
|
||||||
"notSubscribed": "Nie subskrybujesz {entity} i nie będziesz otrzymywać powiadomień o zmianach.",
|
"subscribedTaskThroughParentList": "You can't unsubscribe here because you are subscribed to this task through its list.",
|
||||||
|
"subscribedNamespace": "You are currently subscribed to this namespace and will receive notifications for changes.",
|
||||||
|
"notSubscribedNamespace": "You are not subscribed to this namespace and won't receive notifications for changes.",
|
||||||
|
"subscribedList": "You are currently subscribed to this list and will receive notifications for changes.",
|
||||||
|
"notSubscribedList": "You are not subscribed to this list and won't receive notifications for changes.",
|
||||||
|
"subscribedTask": "You are currently subscribed to this task and will receive notifications for changes.",
|
||||||
|
"notSubscribedTask": "You are not subscribed to this task and won't receive notifications for changes.",
|
||||||
"subscribe": "Subskrybuj",
|
"subscribe": "Subskrybuj",
|
||||||
"unsubscribe": "Anuluj subskrypcję",
|
"unsubscribe": "Anuluj subskrypcję",
|
||||||
"subscribeSuccess": "Od teraz subskrybujesz {entity}",
|
"subscribeSuccessNamespace": "You are now subscribed to this namespace",
|
||||||
"unsubscribeSuccess": "Już nie subskrybujesz {entity}"
|
"unsubscribeSuccessNamespace": "You are now unsubscribed to this namespace",
|
||||||
|
"subscribeSuccessList": "You are now subscribed to this list",
|
||||||
|
"unsubscribeSuccessList": "You are now unsubscribed to this list",
|
||||||
|
"subscribeSuccessTask": "You are now subscribed to this task",
|
||||||
|
"unsubscribeSuccessTask": "You are now unsubscribed to this task"
|
||||||
},
|
},
|
||||||
"attachment": {
|
"attachment": {
|
||||||
"title": "Załączniki",
|
"title": "Załączniki",
|
||||||
|
@ -690,7 +700,11 @@
|
||||||
"deleteTooltip": "Usuń ten załącznik",
|
"deleteTooltip": "Usuń ten załącznik",
|
||||||
"deleteText1": "Czy na pewno chcesz usunąć załącznik {filename}?",
|
"deleteText1": "Czy na pewno chcesz usunąć załącznik {filename}?",
|
||||||
"copyUrl": "Kopiuj URL",
|
"copyUrl": "Kopiuj URL",
|
||||||
"copyUrlTooltip": "Skopiuj adres URL tego załącznika do użycia w tekście"
|
"copyUrlTooltip": "Skopiuj adres URL tego załącznika do użycia w tekście",
|
||||||
|
"setAsCover": "Make cover",
|
||||||
|
"unsetAsCover": "Remove cover",
|
||||||
|
"successfullyChangedCoverImage": "The cover image was successfully changed.",
|
||||||
|
"usedAsCover": "Cover image"
|
||||||
},
|
},
|
||||||
"comment": {
|
"comment": {
|
||||||
"title": "Komentarze",
|
"title": "Komentarze",
|
||||||
|
@ -839,6 +853,12 @@
|
||||||
"text1": "Czy na pewno chcesz usunąć tego użytkownika z zespołu?",
|
"text1": "Czy na pewno chcesz usunąć tego użytkownika z zespołu?",
|
||||||
"text2": "Utraci on dostęp do wszystkich list i sekcji, do których ma dostęp ten zespół. Tego NIE DA SIĘ COFNĄĆ!",
|
"text2": "Utraci on dostęp do wszystkich list i sekcji, do których ma dostęp ten zespół. Tego NIE DA SIĘ COFNĄĆ!",
|
||||||
"success": "Użytkownik został pomyślnie usunięty z zespołu."
|
"success": "Użytkownik został pomyślnie usunięty z zespołu."
|
||||||
|
},
|
||||||
|
"leave": {
|
||||||
|
"title": "Leave team",
|
||||||
|
"text1": "Are you sure you want to leave this team?",
|
||||||
|
"text2": "You will loose access to all lists and namespaces this team has access to. If you change your mind you'll need a team admin to add you again.",
|
||||||
|
"success": "You have successfully left the team."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"attributes": {
|
"attributes": {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
{
|
{
|
||||||
"home": {
|
"home": {
|
||||||
"welcomeNight": "Good Night {username}",
|
"welcomeNight": "Good Night {username}!",
|
||||||
"welcomeMorning": "Good Morning {username}",
|
"welcomeMorning": "Good Morning {username}!",
|
||||||
"welcomeDay": "Hi {username}",
|
"welcomeDay": "Hi {username}!",
|
||||||
"welcomeEvening": "Good Evening {username}",
|
"welcomeEvening": "Good Evening {username}!",
|
||||||
"lastViewed": "Last viewed",
|
"lastViewed": "Last viewed",
|
||||||
"list": {
|
"list": {
|
||||||
"newText": "You can create a new list for your new tasks:",
|
"newText": "You can create a new list for your new tasks:",
|
||||||
|
@ -169,6 +169,14 @@
|
||||||
"title": "List Title",
|
"title": "List Title",
|
||||||
"color": "Color",
|
"color": "Color",
|
||||||
"lists": "Lists",
|
"lists": "Lists",
|
||||||
|
"list": {
|
||||||
|
"title": "List",
|
||||||
|
"add": "Add",
|
||||||
|
"addPlaceholder": "Add a new task…",
|
||||||
|
"empty": "This list is currently empty.",
|
||||||
|
"newTaskCta": "Create a new task.",
|
||||||
|
"editTask": "Edit Task"
|
||||||
|
},
|
||||||
"search": "Type to search for a list…",
|
"search": "Type to search for a list…",
|
||||||
"searchSelect": "Click or press enter to select this list",
|
"searchSelect": "Click or press enter to select this list",
|
||||||
"shared": "Shared Lists",
|
"shared": "Shared Lists",
|
||||||
|
@ -270,14 +278,6 @@
|
||||||
"delete": "Delete"
|
"delete": "Delete"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"list": {
|
|
||||||
"title": "List",
|
|
||||||
"add": "Add",
|
|
||||||
"addPlaceholder": "Add a new task…",
|
|
||||||
"empty": "This list is currently empty.",
|
|
||||||
"newTaskCta": "Create a new task.",
|
|
||||||
"editTask": "Edit Task"
|
|
||||||
},
|
|
||||||
"gantt": {
|
"gantt": {
|
||||||
"title": "Gantt",
|
"title": "Gantt",
|
||||||
"showTasksWithoutDates": "Show tasks which don't have dates set",
|
"showTasksWithoutDates": "Show tasks which don't have dates set",
|
||||||
|
@ -672,13 +672,23 @@
|
||||||
"updated": "Updated"
|
"updated": "Updated"
|
||||||
},
|
},
|
||||||
"subscription": {
|
"subscription": {
|
||||||
"subscribedThroughParent": "You can't unsubscribe here because you are subscribed to this {entity} through its {parent}.",
|
"subscribedListThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this list through its namespace.",
|
||||||
"subscribed": "You are currently subscribed to this {entity} and will receive notifications for changes.",
|
"subscribedTaskThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this task through its namespace.",
|
||||||
"notSubscribed": "You are not subscribed to this {entity} and won't receive notifications for changes.",
|
"subscribedTaskThroughParentList": "You can't unsubscribe here because you are subscribed to this task through its list.",
|
||||||
|
"subscribedNamespace": "You are currently subscribed to this namespace and will receive notifications for changes.",
|
||||||
|
"notSubscribedNamespace": "You are not subscribed to this namespace and won't receive notifications for changes.",
|
||||||
|
"subscribedList": "You are currently subscribed to this list and will receive notifications for changes.",
|
||||||
|
"notSubscribedList": "You are not subscribed to this list and won't receive notifications for changes.",
|
||||||
|
"subscribedTask": "You are currently subscribed to this task and will receive notifications for changes.",
|
||||||
|
"notSubscribedTask": "You are not subscribed to this task and won't receive notifications for changes.",
|
||||||
"subscribe": "Subscribe",
|
"subscribe": "Subscribe",
|
||||||
"unsubscribe": "Unsubscribe",
|
"unsubscribe": "Unsubscribe",
|
||||||
"subscribeSuccess": "You are now subscribed to this {entity}",
|
"subscribeSuccessNamespace": "You are now subscribed to this namespace",
|
||||||
"unsubscribeSuccess": "You are now unsubscribed to this {entity}"
|
"unsubscribeSuccessNamespace": "You are now unsubscribed to this namespace",
|
||||||
|
"subscribeSuccessList": "You are now subscribed to this list",
|
||||||
|
"unsubscribeSuccessList": "You are now unsubscribed to this list",
|
||||||
|
"subscribeSuccessTask": "You are now subscribed to this task",
|
||||||
|
"unsubscribeSuccessTask": "You are now unsubscribed to this task"
|
||||||
},
|
},
|
||||||
"attachment": {
|
"attachment": {
|
||||||
"title": "Attachments",
|
"title": "Attachments",
|
||||||
|
@ -690,7 +700,11 @@
|
||||||
"deleteTooltip": "Delete this attachment",
|
"deleteTooltip": "Delete this attachment",
|
||||||
"deleteText1": "Are you sure you want to delete the attachment {filename}?",
|
"deleteText1": "Are you sure you want to delete the attachment {filename}?",
|
||||||
"copyUrl": "Copy URL",
|
"copyUrl": "Copy URL",
|
||||||
"copyUrlTooltip": "Copy the url of this attachment for usage in text"
|
"copyUrlTooltip": "Copy the url of this attachment for usage in text",
|
||||||
|
"setAsCover": "Make cover",
|
||||||
|
"unsetAsCover": "Remove cover",
|
||||||
|
"successfullyChangedCoverImage": "The cover image was successfully changed.",
|
||||||
|
"usedAsCover": "Cover image"
|
||||||
},
|
},
|
||||||
"comment": {
|
"comment": {
|
||||||
"title": "Comments",
|
"title": "Comments",
|
||||||
|
@ -839,6 +853,12 @@
|
||||||
"text1": "Are you sure you want to remove this user from the team?",
|
"text1": "Are you sure you want to remove this user from the team?",
|
||||||
"text2": "They will lose access to all lists and namespaces this team has access to. This CANNOT BE UNDONE!",
|
"text2": "They will lose access to all lists and namespaces this team has access to. This CANNOT BE UNDONE!",
|
||||||
"success": "The user was successfully deleted from the team."
|
"success": "The user was successfully deleted from the team."
|
||||||
|
},
|
||||||
|
"leave": {
|
||||||
|
"title": "Leave team",
|
||||||
|
"text1": "Are you sure you want to leave this team?",
|
||||||
|
"text2": "You will loose access to all lists and namespaces this team has access to. If you change your mind you'll need a team admin to add you again.",
|
||||||
|
"success": "You have successfully left the team."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"attributes": {
|
"attributes": {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
{
|
{
|
||||||
"home": {
|
"home": {
|
||||||
"welcomeNight": "Boa Noite {username}",
|
"welcomeNight": "Boa Noite {username}!",
|
||||||
"welcomeMorning": "Bom Dia {username}",
|
"welcomeMorning": "Bom Dia {username}!",
|
||||||
"welcomeDay": "Olá {username}",
|
"welcomeDay": "Olá {username}!",
|
||||||
"welcomeEvening": "Boa Tarde {username}",
|
"welcomeEvening": "Boa Tarde {username}!",
|
||||||
"lastViewed": "Visto recentemente",
|
"lastViewed": "Visto recentemente",
|
||||||
"list": {
|
"list": {
|
||||||
"newText": "Podes criar uma nova lista para as tuas novas tarefas:",
|
"newText": "Podes criar uma nova lista para as tuas novas tarefas:",
|
||||||
|
@ -169,6 +169,14 @@
|
||||||
"title": "Título da Lista",
|
"title": "Título da Lista",
|
||||||
"color": "Cor",
|
"color": "Cor",
|
||||||
"lists": "Listas",
|
"lists": "Listas",
|
||||||
|
"list": {
|
||||||
|
"title": "Lista",
|
||||||
|
"add": "Adicionar",
|
||||||
|
"addPlaceholder": "Adicionar uma nova tarefa…",
|
||||||
|
"empty": "Esta lista está atualmente vazia.",
|
||||||
|
"newTaskCta": "Cria uma nova tarefa.",
|
||||||
|
"editTask": "Editar Tarefa"
|
||||||
|
},
|
||||||
"search": "Escreve para pesquisar por uma lista…",
|
"search": "Escreve para pesquisar por uma lista…",
|
||||||
"searchSelect": "Clica ou pressiona Enter para selecionar esta lista",
|
"searchSelect": "Clica ou pressiona Enter para selecionar esta lista",
|
||||||
"shared": "Listas Partilhadas",
|
"shared": "Listas Partilhadas",
|
||||||
|
@ -270,14 +278,6 @@
|
||||||
"delete": "Eliminar"
|
"delete": "Eliminar"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"list": {
|
|
||||||
"title": "Lista",
|
|
||||||
"add": "Adicionar",
|
|
||||||
"addPlaceholder": "Adicionar uma nova tarefa…",
|
|
||||||
"empty": "Esta lista está atualmente vazia.",
|
|
||||||
"newTaskCta": "Cria uma nova tarefa.",
|
|
||||||
"editTask": "Editar Tarefa"
|
|
||||||
},
|
|
||||||
"gantt": {
|
"gantt": {
|
||||||
"title": "Gantt",
|
"title": "Gantt",
|
||||||
"showTasksWithoutDates": "Mostrar tarefas que não têm datas atríbuidas",
|
"showTasksWithoutDates": "Mostrar tarefas que não têm datas atríbuidas",
|
||||||
|
@ -672,13 +672,23 @@
|
||||||
"updated": "Atualizado"
|
"updated": "Atualizado"
|
||||||
},
|
},
|
||||||
"subscription": {
|
"subscription": {
|
||||||
"subscribedThroughParent": "Não podes cancelar a tua subscrição aqui porque estás subscrito nesta {entity} através de {parent}.",
|
"subscribedListThroughParentNamespace": "Não podes cancelar a tua subscrição aqui porque estás subscrito nesta lista através do seu espaço.",
|
||||||
"subscribed": "Estás atualmente subscrito a esta {entity} e serás notificado de alterações.",
|
"subscribedTaskThroughParentNamespace": "Não podes cancelar a tua subscrição aqui porque estás subscrito nesta tarefa através do seu espaço.",
|
||||||
"notSubscribed": "Não estás subscrito a esta {entity} e não serás notificado de alterações.",
|
"subscribedTaskThroughParentList": "Não podes cancelar a tua subscrição aqui porque estás subscrito nesta tarefa através da sua lista.",
|
||||||
|
"subscribedNamespace": "Estás atualmente subscrito a este espaço e serás notificado de alterações.",
|
||||||
|
"notSubscribedNamespace": "Não estás subscrito a este espaço e não serás notificado de alterações.",
|
||||||
|
"subscribedList": "Estás atualmente subscrito a esta lista e serás notificado de alterações.",
|
||||||
|
"notSubscribedList": "Não estás subscrito a esta lista e não serás notificado de alterações.",
|
||||||
|
"subscribedTask": "Estás atualmente subscrito a esta tarefa e serás notificado de alterações.",
|
||||||
|
"notSubscribedTask": "Não estás subscrito a esta tarefa e não serás notificado de alterações.",
|
||||||
"subscribe": "Subscrever",
|
"subscribe": "Subscrever",
|
||||||
"unsubscribe": "Remover Subscrição",
|
"unsubscribe": "Remover Subscrição",
|
||||||
"subscribeSuccess": "Estás agora subscrito a esta {entity}",
|
"subscribeSuccessNamespace": "Estás agora subscrito a este espaço",
|
||||||
"unsubscribeSuccess": "Não estás mais subcrito a esta {entity}"
|
"unsubscribeSuccessNamespace": "Não estás mais subcrito a este espaço",
|
||||||
|
"subscribeSuccessList": "Estás agora subscrito a esta lista",
|
||||||
|
"unsubscribeSuccessList": "Não estás mais subcrito a esta lista",
|
||||||
|
"subscribeSuccessTask": "Estás agora subscrito a esta tarefa",
|
||||||
|
"unsubscribeSuccessTask": "Não estás mais subcrito a esta tarefa"
|
||||||
},
|
},
|
||||||
"attachment": {
|
"attachment": {
|
||||||
"title": "Anexos",
|
"title": "Anexos",
|
||||||
|
@ -690,7 +700,11 @@
|
||||||
"deleteTooltip": "Eliminar este anexo",
|
"deleteTooltip": "Eliminar este anexo",
|
||||||
"deleteText1": "Tens a certeza que pretendes eliminar o anexo {filename}?",
|
"deleteText1": "Tens a certeza que pretendes eliminar o anexo {filename}?",
|
||||||
"copyUrl": "Copiar URL",
|
"copyUrl": "Copiar URL",
|
||||||
"copyUrlTooltip": "Copia o url deste anexo para o utilizar no texto"
|
"copyUrlTooltip": "Copia o url deste anexo para o utilizar no texto",
|
||||||
|
"setAsCover": "Criar capa",
|
||||||
|
"unsetAsCover": "Remover capa",
|
||||||
|
"successfullyChangedCoverImage": "A imagem de capa foi alterada com sucesso.",
|
||||||
|
"usedAsCover": "Imagem de capa"
|
||||||
},
|
},
|
||||||
"comment": {
|
"comment": {
|
||||||
"title": "Comentários",
|
"title": "Comentários",
|
||||||
|
@ -839,6 +853,12 @@
|
||||||
"text1": "Tens a certeza que pretendes remover este utilizador da equipa?",
|
"text1": "Tens a certeza que pretendes remover este utilizador da equipa?",
|
||||||
"text2": "Eles perderão o acesso a todas as listas e espaços a que esta equipa tem acesso. Isto NÃO PODER SER REVERTIDO!",
|
"text2": "Eles perderão o acesso a todas as listas e espaços a que esta equipa tem acesso. Isto NÃO PODER SER REVERTIDO!",
|
||||||
"success": "O utilizador foi removido da equipa com sucesso."
|
"success": "O utilizador foi removido da equipa com sucesso."
|
||||||
|
},
|
||||||
|
"leave": {
|
||||||
|
"title": "Sair da equipa",
|
||||||
|
"text1": "Tens a certeza de que queres sair desta equipa?",
|
||||||
|
"text2": "Vais perder acesso a todas as listas e espaços a que esta equipa tem acesso. Se mudares de ideias, vais necessitar que um administrador da equipa te adicione novamente.",
|
||||||
|
"success": "Saíste da equipa com sucesso."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"attributes": {
|
"attributes": {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
{
|
{
|
||||||
"home": {
|
"home": {
|
||||||
"welcomeNight": "Good Night {username}",
|
"welcomeNight": "Good Night {username}!",
|
||||||
"welcomeMorning": "Good Morning {username}",
|
"welcomeMorning": "Good Morning {username}!",
|
||||||
"welcomeDay": "Hi {username}",
|
"welcomeDay": "Hi {username}!",
|
||||||
"welcomeEvening": "Good Evening {username}",
|
"welcomeEvening": "Good Evening {username}!",
|
||||||
"lastViewed": "Last viewed",
|
"lastViewed": "Last viewed",
|
||||||
"list": {
|
"list": {
|
||||||
"newText": "You can create a new list for your new tasks:",
|
"newText": "You can create a new list for your new tasks:",
|
||||||
|
@ -169,6 +169,14 @@
|
||||||
"title": "List Title",
|
"title": "List Title",
|
||||||
"color": "Color",
|
"color": "Color",
|
||||||
"lists": "Lists",
|
"lists": "Lists",
|
||||||
|
"list": {
|
||||||
|
"title": "List",
|
||||||
|
"add": "Add",
|
||||||
|
"addPlaceholder": "Add a new task…",
|
||||||
|
"empty": "This list is currently empty.",
|
||||||
|
"newTaskCta": "Create a new task.",
|
||||||
|
"editTask": "Edit Task"
|
||||||
|
},
|
||||||
"search": "Type to search for a list…",
|
"search": "Type to search for a list…",
|
||||||
"searchSelect": "Click or press enter to select this list",
|
"searchSelect": "Click or press enter to select this list",
|
||||||
"shared": "Shared Lists",
|
"shared": "Shared Lists",
|
||||||
|
@ -270,14 +278,6 @@
|
||||||
"delete": "Delete"
|
"delete": "Delete"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"list": {
|
|
||||||
"title": "List",
|
|
||||||
"add": "Add",
|
|
||||||
"addPlaceholder": "Add a new task…",
|
|
||||||
"empty": "This list is currently empty.",
|
|
||||||
"newTaskCta": "Create a new task.",
|
|
||||||
"editTask": "Edit Task"
|
|
||||||
},
|
|
||||||
"gantt": {
|
"gantt": {
|
||||||
"title": "Gantt",
|
"title": "Gantt",
|
||||||
"showTasksWithoutDates": "Show tasks which don't have dates set",
|
"showTasksWithoutDates": "Show tasks which don't have dates set",
|
||||||
|
@ -672,13 +672,23 @@
|
||||||
"updated": "Updated"
|
"updated": "Updated"
|
||||||
},
|
},
|
||||||
"subscription": {
|
"subscription": {
|
||||||
"subscribedThroughParent": "You can't unsubscribe here because you are subscribed to this {entity} through its {parent}.",
|
"subscribedListThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this list through its namespace.",
|
||||||
"subscribed": "You are currently subscribed to this {entity} and will receive notifications for changes.",
|
"subscribedTaskThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this task through its namespace.",
|
||||||
"notSubscribed": "You are not subscribed to this {entity} and won't receive notifications for changes.",
|
"subscribedTaskThroughParentList": "You can't unsubscribe here because you are subscribed to this task through its list.",
|
||||||
|
"subscribedNamespace": "You are currently subscribed to this namespace and will receive notifications for changes.",
|
||||||
|
"notSubscribedNamespace": "You are not subscribed to this namespace and won't receive notifications for changes.",
|
||||||
|
"subscribedList": "You are currently subscribed to this list and will receive notifications for changes.",
|
||||||
|
"notSubscribedList": "You are not subscribed to this list and won't receive notifications for changes.",
|
||||||
|
"subscribedTask": "You are currently subscribed to this task and will receive notifications for changes.",
|
||||||
|
"notSubscribedTask": "You are not subscribed to this task and won't receive notifications for changes.",
|
||||||
"subscribe": "Subscribe",
|
"subscribe": "Subscribe",
|
||||||
"unsubscribe": "Unsubscribe",
|
"unsubscribe": "Unsubscribe",
|
||||||
"subscribeSuccess": "You are now subscribed to this {entity}",
|
"subscribeSuccessNamespace": "You are now subscribed to this namespace",
|
||||||
"unsubscribeSuccess": "You are now unsubscribed to this {entity}"
|
"unsubscribeSuccessNamespace": "You are now unsubscribed to this namespace",
|
||||||
|
"subscribeSuccessList": "You are now subscribed to this list",
|
||||||
|
"unsubscribeSuccessList": "You are now unsubscribed to this list",
|
||||||
|
"subscribeSuccessTask": "You are now subscribed to this task",
|
||||||
|
"unsubscribeSuccessTask": "You are now unsubscribed to this task"
|
||||||
},
|
},
|
||||||
"attachment": {
|
"attachment": {
|
||||||
"title": "Attachments",
|
"title": "Attachments",
|
||||||
|
@ -690,7 +700,11 @@
|
||||||
"deleteTooltip": "Delete this attachment",
|
"deleteTooltip": "Delete this attachment",
|
||||||
"deleteText1": "Are you sure you want to delete the attachment {filename}?",
|
"deleteText1": "Are you sure you want to delete the attachment {filename}?",
|
||||||
"copyUrl": "Copy URL",
|
"copyUrl": "Copy URL",
|
||||||
"copyUrlTooltip": "Copy the url of this attachment for usage in text"
|
"copyUrlTooltip": "Copy the url of this attachment for usage in text",
|
||||||
|
"setAsCover": "Make cover",
|
||||||
|
"unsetAsCover": "Remove cover",
|
||||||
|
"successfullyChangedCoverImage": "The cover image was successfully changed.",
|
||||||
|
"usedAsCover": "Cover image"
|
||||||
},
|
},
|
||||||
"comment": {
|
"comment": {
|
||||||
"title": "Comments",
|
"title": "Comments",
|
||||||
|
@ -839,6 +853,12 @@
|
||||||
"text1": "Are you sure you want to remove this user from the team?",
|
"text1": "Are you sure you want to remove this user from the team?",
|
||||||
"text2": "They will lose access to all lists and namespaces this team has access to. This CANNOT BE UNDONE!",
|
"text2": "They will lose access to all lists and namespaces this team has access to. This CANNOT BE UNDONE!",
|
||||||
"success": "The user was successfully deleted from the team."
|
"success": "The user was successfully deleted from the team."
|
||||||
|
},
|
||||||
|
"leave": {
|
||||||
|
"title": "Leave team",
|
||||||
|
"text1": "Are you sure you want to leave this team?",
|
||||||
|
"text2": "You will loose access to all lists and namespaces this team has access to. If you change your mind you'll need a team admin to add you again.",
|
||||||
|
"success": "You have successfully left the team."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"attributes": {
|
"attributes": {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
{
|
{
|
||||||
"home": {
|
"home": {
|
||||||
"welcomeNight": "Доброй ночи, {username}",
|
"welcomeNight": "Good Night {username}!",
|
||||||
"welcomeMorning": "Доброе утро, {username}",
|
"welcomeMorning": "Good Morning {username}!",
|
||||||
"welcomeDay": "Привет, {username}",
|
"welcomeDay": "Hi {username}!",
|
||||||
"welcomeEvening": "Добрый вечер, {username}",
|
"welcomeEvening": "Good Evening {username}!",
|
||||||
"lastViewed": "Последние просмотренные",
|
"lastViewed": "Последние просмотренные",
|
||||||
"list": {
|
"list": {
|
||||||
"newText": "Ты можешь создать новый список для своих задач:",
|
"newText": "Ты можешь создать новый список для своих задач:",
|
||||||
|
@ -169,6 +169,14 @@
|
||||||
"title": "Название списка",
|
"title": "Название списка",
|
||||||
"color": "Цвет",
|
"color": "Цвет",
|
||||||
"lists": "Списки",
|
"lists": "Списки",
|
||||||
|
"list": {
|
||||||
|
"title": "Список",
|
||||||
|
"add": "Добавить",
|
||||||
|
"addPlaceholder": "Добавить новую задачу…",
|
||||||
|
"empty": "Список сейчас пуст.",
|
||||||
|
"newTaskCta": "Создать новую задачу.",
|
||||||
|
"editTask": "Изменить задачу"
|
||||||
|
},
|
||||||
"search": "Введи запрос для поиска списка…",
|
"search": "Введи запрос для поиска списка…",
|
||||||
"searchSelect": "Кликни или нажми Enter для выбора этого списка",
|
"searchSelect": "Кликни или нажми Enter для выбора этого списка",
|
||||||
"shared": "Общие списки",
|
"shared": "Общие списки",
|
||||||
|
@ -270,14 +278,6 @@
|
||||||
"delete": "Удалить"
|
"delete": "Удалить"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"list": {
|
|
||||||
"title": "Список",
|
|
||||||
"add": "Добавить",
|
|
||||||
"addPlaceholder": "Добавить новую задачу…",
|
|
||||||
"empty": "Список сейчас пуст.",
|
|
||||||
"newTaskCta": "Создать новую задачу.",
|
|
||||||
"editTask": "Изменить задачу"
|
|
||||||
},
|
|
||||||
"gantt": {
|
"gantt": {
|
||||||
"title": "Гант",
|
"title": "Гант",
|
||||||
"showTasksWithoutDates": "Показать задачи без установленной даты",
|
"showTasksWithoutDates": "Показать задачи без установленной даты",
|
||||||
|
@ -672,13 +672,23 @@
|
||||||
"updated": "Дата изменения"
|
"updated": "Дата изменения"
|
||||||
},
|
},
|
||||||
"subscription": {
|
"subscription": {
|
||||||
"subscribedThroughParent": "Ты не можешь отписаться здесь, потому что ты подписан на {entity} через {parent}.",
|
"subscribedListThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this list through its namespace.",
|
||||||
"subscribed": "Ты подписан на {entity} и будешь получать уведомления об изменениях.",
|
"subscribedTaskThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this task through its namespace.",
|
||||||
"notSubscribed": "Ты не подписан на {entity} и не будешь получать уведомления об изменениях.",
|
"subscribedTaskThroughParentList": "You can't unsubscribe here because you are subscribed to this task through its list.",
|
||||||
|
"subscribedNamespace": "You are currently subscribed to this namespace and will receive notifications for changes.",
|
||||||
|
"notSubscribedNamespace": "You are not subscribed to this namespace and won't receive notifications for changes.",
|
||||||
|
"subscribedList": "You are currently subscribed to this list and will receive notifications for changes.",
|
||||||
|
"notSubscribedList": "You are not subscribed to this list and won't receive notifications for changes.",
|
||||||
|
"subscribedTask": "You are currently subscribed to this task and will receive notifications for changes.",
|
||||||
|
"notSubscribedTask": "You are not subscribed to this task and won't receive notifications for changes.",
|
||||||
"subscribe": "Подписаться",
|
"subscribe": "Подписаться",
|
||||||
"unsubscribe": "Отписаться",
|
"unsubscribe": "Отписаться",
|
||||||
"subscribeSuccess": "Ты подписался на {entity}",
|
"subscribeSuccessNamespace": "You are now subscribed to this namespace",
|
||||||
"unsubscribeSuccess": "Ты отписался от {entity}"
|
"unsubscribeSuccessNamespace": "You are now unsubscribed to this namespace",
|
||||||
|
"subscribeSuccessList": "You are now subscribed to this list",
|
||||||
|
"unsubscribeSuccessList": "You are now unsubscribed to this list",
|
||||||
|
"subscribeSuccessTask": "You are now subscribed to this task",
|
||||||
|
"unsubscribeSuccessTask": "You are now unsubscribed to this task"
|
||||||
},
|
},
|
||||||
"attachment": {
|
"attachment": {
|
||||||
"title": "Вложения",
|
"title": "Вложения",
|
||||||
|
@ -690,7 +700,11 @@
|
||||||
"deleteTooltip": "Удалить это вложение",
|
"deleteTooltip": "Удалить это вложение",
|
||||||
"deleteText1": "Удалить вложение {filename}?",
|
"deleteText1": "Удалить вложение {filename}?",
|
||||||
"copyUrl": "Скопировать URL",
|
"copyUrl": "Скопировать URL",
|
||||||
"copyUrlTooltip": "Скопировать ссылку на это вложение для использования в тексте"
|
"copyUrlTooltip": "Скопировать ссылку на это вложение для использования в тексте",
|
||||||
|
"setAsCover": "Make cover",
|
||||||
|
"unsetAsCover": "Remove cover",
|
||||||
|
"successfullyChangedCoverImage": "The cover image was successfully changed.",
|
||||||
|
"usedAsCover": "Cover image"
|
||||||
},
|
},
|
||||||
"comment": {
|
"comment": {
|
||||||
"title": "Комментарии",
|
"title": "Комментарии",
|
||||||
|
@ -839,6 +853,12 @@
|
||||||
"text1": "Удалить этого пользователя из команды?",
|
"text1": "Удалить этого пользователя из команды?",
|
||||||
"text2": "Пользователь потеряет доступ ко всем спискам и пространствам имён, к котором есть доступ у команды. Это действие отменить нельзя!",
|
"text2": "Пользователь потеряет доступ ко всем спискам и пространствам имён, к котором есть доступ у команды. Это действие отменить нельзя!",
|
||||||
"success": "Пользователь удалён из команды."
|
"success": "Пользователь удалён из команды."
|
||||||
|
},
|
||||||
|
"leave": {
|
||||||
|
"title": "Leave team",
|
||||||
|
"text1": "Are you sure you want to leave this team?",
|
||||||
|
"text2": "You will loose access to all lists and namespaces this team has access to. If you change your mind you'll need a team admin to add you again.",
|
||||||
|
"success": "You have successfully left the team."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"attributes": {
|
"attributes": {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
{
|
{
|
||||||
"home": {
|
"home": {
|
||||||
"welcomeNight": "Good Night {username}",
|
"welcomeNight": "Good Night {username}!",
|
||||||
"welcomeMorning": "Good Morning {username}",
|
"welcomeMorning": "Good Morning {username}!",
|
||||||
"welcomeDay": "Hi {username}",
|
"welcomeDay": "Hi {username}!",
|
||||||
"welcomeEvening": "Good Evening {username}",
|
"welcomeEvening": "Good Evening {username}!",
|
||||||
"lastViewed": "Last viewed",
|
"lastViewed": "Last viewed",
|
||||||
"list": {
|
"list": {
|
||||||
"newText": "You can create a new list for your new tasks:",
|
"newText": "You can create a new list for your new tasks:",
|
||||||
|
@ -169,6 +169,14 @@
|
||||||
"title": "List Title",
|
"title": "List Title",
|
||||||
"color": "Color",
|
"color": "Color",
|
||||||
"lists": "Lists",
|
"lists": "Lists",
|
||||||
|
"list": {
|
||||||
|
"title": "List",
|
||||||
|
"add": "Add",
|
||||||
|
"addPlaceholder": "Add a new task…",
|
||||||
|
"empty": "This list is currently empty.",
|
||||||
|
"newTaskCta": "Create a new task.",
|
||||||
|
"editTask": "Edit Task"
|
||||||
|
},
|
||||||
"search": "Type to search for a list…",
|
"search": "Type to search for a list…",
|
||||||
"searchSelect": "Click or press enter to select this list",
|
"searchSelect": "Click or press enter to select this list",
|
||||||
"shared": "Shared Lists",
|
"shared": "Shared Lists",
|
||||||
|
@ -270,14 +278,6 @@
|
||||||
"delete": "Delete"
|
"delete": "Delete"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"list": {
|
|
||||||
"title": "List",
|
|
||||||
"add": "Add",
|
|
||||||
"addPlaceholder": "Add a new task…",
|
|
||||||
"empty": "This list is currently empty.",
|
|
||||||
"newTaskCta": "Create a new task.",
|
|
||||||
"editTask": "Edit Task"
|
|
||||||
},
|
|
||||||
"gantt": {
|
"gantt": {
|
||||||
"title": "Gantt",
|
"title": "Gantt",
|
||||||
"showTasksWithoutDates": "Show tasks which don't have dates set",
|
"showTasksWithoutDates": "Show tasks which don't have dates set",
|
||||||
|
@ -672,13 +672,23 @@
|
||||||
"updated": "Updated"
|
"updated": "Updated"
|
||||||
},
|
},
|
||||||
"subscription": {
|
"subscription": {
|
||||||
"subscribedThroughParent": "You can't unsubscribe here because you are subscribed to this {entity} through its {parent}.",
|
"subscribedListThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this list through its namespace.",
|
||||||
"subscribed": "You are currently subscribed to this {entity} and will receive notifications for changes.",
|
"subscribedTaskThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this task through its namespace.",
|
||||||
"notSubscribed": "You are not subscribed to this {entity} and won't receive notifications for changes.",
|
"subscribedTaskThroughParentList": "You can't unsubscribe here because you are subscribed to this task through its list.",
|
||||||
|
"subscribedNamespace": "You are currently subscribed to this namespace and will receive notifications for changes.",
|
||||||
|
"notSubscribedNamespace": "You are not subscribed to this namespace and won't receive notifications for changes.",
|
||||||
|
"subscribedList": "You are currently subscribed to this list and will receive notifications for changes.",
|
||||||
|
"notSubscribedList": "You are not subscribed to this list and won't receive notifications for changes.",
|
||||||
|
"subscribedTask": "You are currently subscribed to this task and will receive notifications for changes.",
|
||||||
|
"notSubscribedTask": "You are not subscribed to this task and won't receive notifications for changes.",
|
||||||
"subscribe": "Subscribe",
|
"subscribe": "Subscribe",
|
||||||
"unsubscribe": "Unsubscribe",
|
"unsubscribe": "Unsubscribe",
|
||||||
"subscribeSuccess": "You are now subscribed to this {entity}",
|
"subscribeSuccessNamespace": "You are now subscribed to this namespace",
|
||||||
"unsubscribeSuccess": "You are now unsubscribed to this {entity}"
|
"unsubscribeSuccessNamespace": "You are now unsubscribed to this namespace",
|
||||||
|
"subscribeSuccessList": "You are now subscribed to this list",
|
||||||
|
"unsubscribeSuccessList": "You are now unsubscribed to this list",
|
||||||
|
"subscribeSuccessTask": "You are now subscribed to this task",
|
||||||
|
"unsubscribeSuccessTask": "You are now unsubscribed to this task"
|
||||||
},
|
},
|
||||||
"attachment": {
|
"attachment": {
|
||||||
"title": "Attachments",
|
"title": "Attachments",
|
||||||
|
@ -690,7 +700,11 @@
|
||||||
"deleteTooltip": "Delete this attachment",
|
"deleteTooltip": "Delete this attachment",
|
||||||
"deleteText1": "Are you sure you want to delete the attachment {filename}?",
|
"deleteText1": "Are you sure you want to delete the attachment {filename}?",
|
||||||
"copyUrl": "Copy URL",
|
"copyUrl": "Copy URL",
|
||||||
"copyUrlTooltip": "Copy the url of this attachment for usage in text"
|
"copyUrlTooltip": "Copy the url of this attachment for usage in text",
|
||||||
|
"setAsCover": "Make cover",
|
||||||
|
"unsetAsCover": "Remove cover",
|
||||||
|
"successfullyChangedCoverImage": "The cover image was successfully changed.",
|
||||||
|
"usedAsCover": "Cover image"
|
||||||
},
|
},
|
||||||
"comment": {
|
"comment": {
|
||||||
"title": "Comments",
|
"title": "Comments",
|
||||||
|
@ -839,6 +853,12 @@
|
||||||
"text1": "Are you sure you want to remove this user from the team?",
|
"text1": "Are you sure you want to remove this user from the team?",
|
||||||
"text2": "They will lose access to all lists and namespaces this team has access to. This CANNOT BE UNDONE!",
|
"text2": "They will lose access to all lists and namespaces this team has access to. This CANNOT BE UNDONE!",
|
||||||
"success": "The user was successfully deleted from the team."
|
"success": "The user was successfully deleted from the team."
|
||||||
|
},
|
||||||
|
"leave": {
|
||||||
|
"title": "Leave team",
|
||||||
|
"text1": "Are you sure you want to leave this team?",
|
||||||
|
"text2": "You will loose access to all lists and namespaces this team has access to. If you change your mind you'll need a team admin to add you again.",
|
||||||
|
"success": "You have successfully left the team."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"attributes": {
|
"attributes": {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
{
|
{
|
||||||
"home": {
|
"home": {
|
||||||
"welcomeNight": "Good Night {username}",
|
"welcomeNight": "Good Night {username}!",
|
||||||
"welcomeMorning": "Good Morning {username}",
|
"welcomeMorning": "Good Morning {username}!",
|
||||||
"welcomeDay": "Hi {username}",
|
"welcomeDay": "Hi {username}!",
|
||||||
"welcomeEvening": "Good Evening {username}",
|
"welcomeEvening": "Good Evening {username}!",
|
||||||
"lastViewed": "Last viewed",
|
"lastViewed": "Last viewed",
|
||||||
"list": {
|
"list": {
|
||||||
"newText": "You can create a new list for your new tasks:",
|
"newText": "You can create a new list for your new tasks:",
|
||||||
|
@ -169,6 +169,14 @@
|
||||||
"title": "List Title",
|
"title": "List Title",
|
||||||
"color": "Color",
|
"color": "Color",
|
||||||
"lists": "Lists",
|
"lists": "Lists",
|
||||||
|
"list": {
|
||||||
|
"title": "List",
|
||||||
|
"add": "Add",
|
||||||
|
"addPlaceholder": "Add a new task…",
|
||||||
|
"empty": "This list is currently empty.",
|
||||||
|
"newTaskCta": "Create a new task.",
|
||||||
|
"editTask": "Edit Task"
|
||||||
|
},
|
||||||
"search": "Type to search for a list…",
|
"search": "Type to search for a list…",
|
||||||
"searchSelect": "Click or press enter to select this list",
|
"searchSelect": "Click or press enter to select this list",
|
||||||
"shared": "Shared Lists",
|
"shared": "Shared Lists",
|
||||||
|
@ -270,14 +278,6 @@
|
||||||
"delete": "Delete"
|
"delete": "Delete"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"list": {
|
|
||||||
"title": "List",
|
|
||||||
"add": "Add",
|
|
||||||
"addPlaceholder": "Add a new task…",
|
|
||||||
"empty": "This list is currently empty.",
|
|
||||||
"newTaskCta": "Create a new task.",
|
|
||||||
"editTask": "Edit Task"
|
|
||||||
},
|
|
||||||
"gantt": {
|
"gantt": {
|
||||||
"title": "Gantt",
|
"title": "Gantt",
|
||||||
"showTasksWithoutDates": "Show tasks which don't have dates set",
|
"showTasksWithoutDates": "Show tasks which don't have dates set",
|
||||||
|
@ -672,13 +672,23 @@
|
||||||
"updated": "Updated"
|
"updated": "Updated"
|
||||||
},
|
},
|
||||||
"subscription": {
|
"subscription": {
|
||||||
"subscribedThroughParent": "You can't unsubscribe here because you are subscribed to this {entity} through its {parent}.",
|
"subscribedListThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this list through its namespace.",
|
||||||
"subscribed": "You are currently subscribed to this {entity} and will receive notifications for changes.",
|
"subscribedTaskThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this task through its namespace.",
|
||||||
"notSubscribed": "You are not subscribed to this {entity} and won't receive notifications for changes.",
|
"subscribedTaskThroughParentList": "You can't unsubscribe here because you are subscribed to this task through its list.",
|
||||||
|
"subscribedNamespace": "You are currently subscribed to this namespace and will receive notifications for changes.",
|
||||||
|
"notSubscribedNamespace": "You are not subscribed to this namespace and won't receive notifications for changes.",
|
||||||
|
"subscribedList": "You are currently subscribed to this list and will receive notifications for changes.",
|
||||||
|
"notSubscribedList": "You are not subscribed to this list and won't receive notifications for changes.",
|
||||||
|
"subscribedTask": "You are currently subscribed to this task and will receive notifications for changes.",
|
||||||
|
"notSubscribedTask": "You are not subscribed to this task and won't receive notifications for changes.",
|
||||||
"subscribe": "Subscribe",
|
"subscribe": "Subscribe",
|
||||||
"unsubscribe": "Unsubscribe",
|
"unsubscribe": "Unsubscribe",
|
||||||
"subscribeSuccess": "You are now subscribed to this {entity}",
|
"subscribeSuccessNamespace": "You are now subscribed to this namespace",
|
||||||
"unsubscribeSuccess": "You are now unsubscribed to this {entity}"
|
"unsubscribeSuccessNamespace": "You are now unsubscribed to this namespace",
|
||||||
|
"subscribeSuccessList": "You are now subscribed to this list",
|
||||||
|
"unsubscribeSuccessList": "You are now unsubscribed to this list",
|
||||||
|
"subscribeSuccessTask": "You are now subscribed to this task",
|
||||||
|
"unsubscribeSuccessTask": "You are now unsubscribed to this task"
|
||||||
},
|
},
|
||||||
"attachment": {
|
"attachment": {
|
||||||
"title": "Attachments",
|
"title": "Attachments",
|
||||||
|
@ -690,7 +700,11 @@
|
||||||
"deleteTooltip": "Delete this attachment",
|
"deleteTooltip": "Delete this attachment",
|
||||||
"deleteText1": "Are you sure you want to delete the attachment {filename}?",
|
"deleteText1": "Are you sure you want to delete the attachment {filename}?",
|
||||||
"copyUrl": "Copy URL",
|
"copyUrl": "Copy URL",
|
||||||
"copyUrlTooltip": "Copy the url of this attachment for usage in text"
|
"copyUrlTooltip": "Copy the url of this attachment for usage in text",
|
||||||
|
"setAsCover": "Make cover",
|
||||||
|
"unsetAsCover": "Remove cover",
|
||||||
|
"successfullyChangedCoverImage": "The cover image was successfully changed.",
|
||||||
|
"usedAsCover": "Cover image"
|
||||||
},
|
},
|
||||||
"comment": {
|
"comment": {
|
||||||
"title": "Comments",
|
"title": "Comments",
|
||||||
|
@ -839,6 +853,12 @@
|
||||||
"text1": "Are you sure you want to remove this user from the team?",
|
"text1": "Are you sure you want to remove this user from the team?",
|
||||||
"text2": "They will lose access to all lists and namespaces this team has access to. This CANNOT BE UNDONE!",
|
"text2": "They will lose access to all lists and namespaces this team has access to. This CANNOT BE UNDONE!",
|
||||||
"success": "The user was successfully deleted from the team."
|
"success": "The user was successfully deleted from the team."
|
||||||
|
},
|
||||||
|
"leave": {
|
||||||
|
"title": "Leave team",
|
||||||
|
"text1": "Are you sure you want to leave this team?",
|
||||||
|
"text2": "You will loose access to all lists and namespaces this team has access to. If you change your mind you'll need a team admin to add you again.",
|
||||||
|
"success": "You have successfully left the team."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"attributes": {
|
"attributes": {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
{
|
{
|
||||||
"home": {
|
"home": {
|
||||||
"welcomeNight": "Good Night {username}",
|
"welcomeNight": "Good Night {username}!",
|
||||||
"welcomeMorning": "Good Morning {username}",
|
"welcomeMorning": "Good Morning {username}!",
|
||||||
"welcomeDay": "Hi {username}",
|
"welcomeDay": "Hi {username}!",
|
||||||
"welcomeEvening": "Good Evening {username}",
|
"welcomeEvening": "Good Evening {username}!",
|
||||||
"lastViewed": "Last viewed",
|
"lastViewed": "Last viewed",
|
||||||
"list": {
|
"list": {
|
||||||
"newText": "You can create a new list for your new tasks:",
|
"newText": "You can create a new list for your new tasks:",
|
||||||
|
@ -169,6 +169,14 @@
|
||||||
"title": "List Title",
|
"title": "List Title",
|
||||||
"color": "Color",
|
"color": "Color",
|
||||||
"lists": "Lists",
|
"lists": "Lists",
|
||||||
|
"list": {
|
||||||
|
"title": "List",
|
||||||
|
"add": "Add",
|
||||||
|
"addPlaceholder": "Add a new task…",
|
||||||
|
"empty": "This list is currently empty.",
|
||||||
|
"newTaskCta": "Create a new task.",
|
||||||
|
"editTask": "Edit Task"
|
||||||
|
},
|
||||||
"search": "Type to search for a list…",
|
"search": "Type to search for a list…",
|
||||||
"searchSelect": "Click or press enter to select this list",
|
"searchSelect": "Click or press enter to select this list",
|
||||||
"shared": "Shared Lists",
|
"shared": "Shared Lists",
|
||||||
|
@ -270,14 +278,6 @@
|
||||||
"delete": "Delete"
|
"delete": "Delete"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"list": {
|
|
||||||
"title": "List",
|
|
||||||
"add": "Add",
|
|
||||||
"addPlaceholder": "Add a new task…",
|
|
||||||
"empty": "This list is currently empty.",
|
|
||||||
"newTaskCta": "Create a new task.",
|
|
||||||
"editTask": "Edit Task"
|
|
||||||
},
|
|
||||||
"gantt": {
|
"gantt": {
|
||||||
"title": "Gantt",
|
"title": "Gantt",
|
||||||
"showTasksWithoutDates": "Show tasks which don't have dates set",
|
"showTasksWithoutDates": "Show tasks which don't have dates set",
|
||||||
|
@ -672,13 +672,23 @@
|
||||||
"updated": "Updated"
|
"updated": "Updated"
|
||||||
},
|
},
|
||||||
"subscription": {
|
"subscription": {
|
||||||
"subscribedThroughParent": "You can't unsubscribe here because you are subscribed to this {entity} through its {parent}.",
|
"subscribedListThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this list through its namespace.",
|
||||||
"subscribed": "You are currently subscribed to this {entity} and will receive notifications for changes.",
|
"subscribedTaskThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this task through its namespace.",
|
||||||
"notSubscribed": "You are not subscribed to this {entity} and won't receive notifications for changes.",
|
"subscribedTaskThroughParentList": "You can't unsubscribe here because you are subscribed to this task through its list.",
|
||||||
|
"subscribedNamespace": "You are currently subscribed to this namespace and will receive notifications for changes.",
|
||||||
|
"notSubscribedNamespace": "You are not subscribed to this namespace and won't receive notifications for changes.",
|
||||||
|
"subscribedList": "You are currently subscribed to this list and will receive notifications for changes.",
|
||||||
|
"notSubscribedList": "You are not subscribed to this list and won't receive notifications for changes.",
|
||||||
|
"subscribedTask": "You are currently subscribed to this task and will receive notifications for changes.",
|
||||||
|
"notSubscribedTask": "You are not subscribed to this task and won't receive notifications for changes.",
|
||||||
"subscribe": "Subscribe",
|
"subscribe": "Subscribe",
|
||||||
"unsubscribe": "Unsubscribe",
|
"unsubscribe": "Unsubscribe",
|
||||||
"subscribeSuccess": "You are now subscribed to this {entity}",
|
"subscribeSuccessNamespace": "You are now subscribed to this namespace",
|
||||||
"unsubscribeSuccess": "You are now unsubscribed to this {entity}"
|
"unsubscribeSuccessNamespace": "You are now unsubscribed to this namespace",
|
||||||
|
"subscribeSuccessList": "You are now subscribed to this list",
|
||||||
|
"unsubscribeSuccessList": "You are now unsubscribed to this list",
|
||||||
|
"subscribeSuccessTask": "You are now subscribed to this task",
|
||||||
|
"unsubscribeSuccessTask": "You are now unsubscribed to this task"
|
||||||
},
|
},
|
||||||
"attachment": {
|
"attachment": {
|
||||||
"title": "Attachments",
|
"title": "Attachments",
|
||||||
|
@ -690,7 +700,11 @@
|
||||||
"deleteTooltip": "Delete this attachment",
|
"deleteTooltip": "Delete this attachment",
|
||||||
"deleteText1": "Are you sure you want to delete the attachment {filename}?",
|
"deleteText1": "Are you sure you want to delete the attachment {filename}?",
|
||||||
"copyUrl": "Copy URL",
|
"copyUrl": "Copy URL",
|
||||||
"copyUrlTooltip": "Copy the url of this attachment for usage in text"
|
"copyUrlTooltip": "Copy the url of this attachment for usage in text",
|
||||||
|
"setAsCover": "Make cover",
|
||||||
|
"unsetAsCover": "Remove cover",
|
||||||
|
"successfullyChangedCoverImage": "The cover image was successfully changed.",
|
||||||
|
"usedAsCover": "Cover image"
|
||||||
},
|
},
|
||||||
"comment": {
|
"comment": {
|
||||||
"title": "Comments",
|
"title": "Comments",
|
||||||
|
@ -839,6 +853,12 @@
|
||||||
"text1": "Are you sure you want to remove this user from the team?",
|
"text1": "Are you sure you want to remove this user from the team?",
|
||||||
"text2": "They will lose access to all lists and namespaces this team has access to. This CANNOT BE UNDONE!",
|
"text2": "They will lose access to all lists and namespaces this team has access to. This CANNOT BE UNDONE!",
|
||||||
"success": "The user was successfully deleted from the team."
|
"success": "The user was successfully deleted from the team."
|
||||||
|
},
|
||||||
|
"leave": {
|
||||||
|
"title": "Leave team",
|
||||||
|
"text1": "Are you sure you want to leave this team?",
|
||||||
|
"text2": "You will loose access to all lists and namespaces this team has access to. If you change your mind you'll need a team admin to add you again.",
|
||||||
|
"success": "You have successfully left the team."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"attributes": {
|
"attributes": {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
{
|
{
|
||||||
"home": {
|
"home": {
|
||||||
"welcomeNight": "Ngủ ngon nhé, {username}",
|
"welcomeNight": "Good Night {username}!",
|
||||||
"welcomeMorning": "Chào buổi sáng, {username}",
|
"welcomeMorning": "Good Morning {username}!",
|
||||||
"welcomeDay": "Hi {username}",
|
"welcomeDay": "Hi {username}!",
|
||||||
"welcomeEvening": "Chào buổi tối, {username}",
|
"welcomeEvening": "Good Evening {username}!",
|
||||||
"lastViewed": "Xem gần đây",
|
"lastViewed": "Xem gần đây",
|
||||||
"list": {
|
"list": {
|
||||||
"newText": "Bạn có thể tạo một danh sách công việc mới cho mình:",
|
"newText": "Bạn có thể tạo một danh sách công việc mới cho mình:",
|
||||||
|
@ -169,6 +169,14 @@
|
||||||
"title": "Tên Danh sách",
|
"title": "Tên Danh sách",
|
||||||
"color": "Màu sắc",
|
"color": "Màu sắc",
|
||||||
"lists": "Danh sách",
|
"lists": "Danh sách",
|
||||||
|
"list": {
|
||||||
|
"title": "Danh sách",
|
||||||
|
"add": "Thêm",
|
||||||
|
"addPlaceholder": "Thêm việc cần làm…",
|
||||||
|
"empty": "Danh sách này đang trống trơn.",
|
||||||
|
"newTaskCta": "Thêm một công việc mới.",
|
||||||
|
"editTask": "Chỉnh sửa Công việc"
|
||||||
|
},
|
||||||
"search": "Gõ để tìm kiếm danh sách…",
|
"search": "Gõ để tìm kiếm danh sách…",
|
||||||
"searchSelect": "Nhấp hoặc nhấn enter để chọn danh sách này",
|
"searchSelect": "Nhấp hoặc nhấn enter để chọn danh sách này",
|
||||||
"shared": "Đang tham gia",
|
"shared": "Đang tham gia",
|
||||||
|
@ -270,14 +278,6 @@
|
||||||
"delete": "Xóa"
|
"delete": "Xóa"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"list": {
|
|
||||||
"title": "Danh sách",
|
|
||||||
"add": "Thêm",
|
|
||||||
"addPlaceholder": "Thêm việc cần làm…",
|
|
||||||
"empty": "Danh sách này đang trống trơn.",
|
|
||||||
"newTaskCta": "Thêm một công việc mới.",
|
|
||||||
"editTask": "Chỉnh sửa Công việc"
|
|
||||||
},
|
|
||||||
"gantt": {
|
"gantt": {
|
||||||
"title": "Biểu đồ Gantt",
|
"title": "Biểu đồ Gantt",
|
||||||
"showTasksWithoutDates": "Hiển thị các nhiệm vụ không cài đặt ngày",
|
"showTasksWithoutDates": "Hiển thị các nhiệm vụ không cài đặt ngày",
|
||||||
|
@ -672,13 +672,23 @@
|
||||||
"updated": "Đã cập nhật"
|
"updated": "Đã cập nhật"
|
||||||
},
|
},
|
||||||
"subscription": {
|
"subscription": {
|
||||||
"subscribedThroughParent": "Bạn không thể hủy theo dõi ở đây vì bạn đã theo dõi {entity} này thông qua {parent} của nó.",
|
"subscribedListThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this list through its namespace.",
|
||||||
"subscribed": "Bạn đang theo dõi {entity} này và sẽ nhận được thông báo về các thay đổi.",
|
"subscribedTaskThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this task through its namespace.",
|
||||||
"notSubscribed": "Bạn chưa theo dõi {entity} này và sẽ không nhận được thông báo về các thay đổi.",
|
"subscribedTaskThroughParentList": "You can't unsubscribe here because you are subscribed to this task through its list.",
|
||||||
|
"subscribedNamespace": "You are currently subscribed to this namespace and will receive notifications for changes.",
|
||||||
|
"notSubscribedNamespace": "You are not subscribed to this namespace and won't receive notifications for changes.",
|
||||||
|
"subscribedList": "You are currently subscribed to this list and will receive notifications for changes.",
|
||||||
|
"notSubscribedList": "You are not subscribed to this list and won't receive notifications for changes.",
|
||||||
|
"subscribedTask": "You are currently subscribed to this task and will receive notifications for changes.",
|
||||||
|
"notSubscribedTask": "You are not subscribed to this task and won't receive notifications for changes.",
|
||||||
"subscribe": "Theo dõi",
|
"subscribe": "Theo dõi",
|
||||||
"unsubscribe": "Bỏ theo dõi",
|
"unsubscribe": "Bỏ theo dõi",
|
||||||
"subscribeSuccess": "Bạn hiện đã theo dõi {entity} này",
|
"subscribeSuccessNamespace": "You are now subscribed to this namespace",
|
||||||
"unsubscribeSuccess": "Bạn đã bỏ theo dõi {entity} này"
|
"unsubscribeSuccessNamespace": "You are now unsubscribed to this namespace",
|
||||||
|
"subscribeSuccessList": "You are now subscribed to this list",
|
||||||
|
"unsubscribeSuccessList": "You are now unsubscribed to this list",
|
||||||
|
"subscribeSuccessTask": "You are now subscribed to this task",
|
||||||
|
"unsubscribeSuccessTask": "You are now unsubscribed to this task"
|
||||||
},
|
},
|
||||||
"attachment": {
|
"attachment": {
|
||||||
"title": "Tệp đính kèm",
|
"title": "Tệp đính kèm",
|
||||||
|
@ -690,7 +700,11 @@
|
||||||
"deleteTooltip": "Xóa tệp đính kèm này",
|
"deleteTooltip": "Xóa tệp đính kèm này",
|
||||||
"deleteText1": "Bạn có chắc chắn muốn xóa tệp đính kèm {filename} không?",
|
"deleteText1": "Bạn có chắc chắn muốn xóa tệp đính kèm {filename} không?",
|
||||||
"copyUrl": "Sao chép URL",
|
"copyUrl": "Sao chép URL",
|
||||||
"copyUrlTooltip": "Sao chép url của tệp đính kèm này để sử dụng trong văn bản"
|
"copyUrlTooltip": "Sao chép url của tệp đính kèm này để sử dụng trong văn bản",
|
||||||
|
"setAsCover": "Make cover",
|
||||||
|
"unsetAsCover": "Remove cover",
|
||||||
|
"successfullyChangedCoverImage": "The cover image was successfully changed.",
|
||||||
|
"usedAsCover": "Cover image"
|
||||||
},
|
},
|
||||||
"comment": {
|
"comment": {
|
||||||
"title": "Bình luận",
|
"title": "Bình luận",
|
||||||
|
@ -839,6 +853,12 @@
|
||||||
"text1": "Bạn có chắc muốn đưa thành viên này ra khỏi Team không?",
|
"text1": "Bạn có chắc muốn đưa thành viên này ra khỏi Team không?",
|
||||||
"text2": "Họ sẽ mất quyền truy cập vào tất cả danh sách và góc làm việc mà Team này có quyền truy cập. Điều đó KHÔNG THỂ HOÀN TÁC!",
|
"text2": "Họ sẽ mất quyền truy cập vào tất cả danh sách và góc làm việc mà Team này có quyền truy cập. Điều đó KHÔNG THỂ HOÀN TÁC!",
|
||||||
"success": "Thành viên đã rời khỏi Team."
|
"success": "Thành viên đã rời khỏi Team."
|
||||||
|
},
|
||||||
|
"leave": {
|
||||||
|
"title": "Leave team",
|
||||||
|
"text1": "Are you sure you want to leave this team?",
|
||||||
|
"text2": "You will loose access to all lists and namespaces this team has access to. If you change your mind you'll need a team admin to add you again.",
|
||||||
|
"success": "You have successfully left the team."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"attributes": {
|
"attributes": {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
{
|
{
|
||||||
"home": {
|
"home": {
|
||||||
"welcomeNight": "Good Night {username}",
|
"welcomeNight": "Good Night {username}!",
|
||||||
"welcomeMorning": "Good Morning {username}",
|
"welcomeMorning": "Good Morning {username}!",
|
||||||
"welcomeDay": "Hi {username}",
|
"welcomeDay": "Hi {username}!",
|
||||||
"welcomeEvening": "Good Evening {username}",
|
"welcomeEvening": "Good Evening {username}!",
|
||||||
"lastViewed": "Last viewed",
|
"lastViewed": "Last viewed",
|
||||||
"list": {
|
"list": {
|
||||||
"newText": "You can create a new list for your new tasks:",
|
"newText": "You can create a new list for your new tasks:",
|
||||||
|
@ -169,6 +169,14 @@
|
||||||
"title": "List Title",
|
"title": "List Title",
|
||||||
"color": "Color",
|
"color": "Color",
|
||||||
"lists": "Lists",
|
"lists": "Lists",
|
||||||
|
"list": {
|
||||||
|
"title": "List",
|
||||||
|
"add": "Add",
|
||||||
|
"addPlaceholder": "Add a new task…",
|
||||||
|
"empty": "This list is currently empty.",
|
||||||
|
"newTaskCta": "Create a new task.",
|
||||||
|
"editTask": "Edit Task"
|
||||||
|
},
|
||||||
"search": "Type to search for a list…",
|
"search": "Type to search for a list…",
|
||||||
"searchSelect": "Click or press enter to select this list",
|
"searchSelect": "Click or press enter to select this list",
|
||||||
"shared": "Shared Lists",
|
"shared": "Shared Lists",
|
||||||
|
@ -270,14 +278,6 @@
|
||||||
"delete": "Delete"
|
"delete": "Delete"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"list": {
|
|
||||||
"title": "List",
|
|
||||||
"add": "Add",
|
|
||||||
"addPlaceholder": "Add a new task…",
|
|
||||||
"empty": "This list is currently empty.",
|
|
||||||
"newTaskCta": "Create a new task.",
|
|
||||||
"editTask": "Edit Task"
|
|
||||||
},
|
|
||||||
"gantt": {
|
"gantt": {
|
||||||
"title": "Gantt",
|
"title": "Gantt",
|
||||||
"showTasksWithoutDates": "Show tasks which don't have dates set",
|
"showTasksWithoutDates": "Show tasks which don't have dates set",
|
||||||
|
@ -672,13 +672,23 @@
|
||||||
"updated": "Updated"
|
"updated": "Updated"
|
||||||
},
|
},
|
||||||
"subscription": {
|
"subscription": {
|
||||||
"subscribedThroughParent": "You can't unsubscribe here because you are subscribed to this {entity} through its {parent}.",
|
"subscribedListThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this list through its namespace.",
|
||||||
"subscribed": "You are currently subscribed to this {entity} and will receive notifications for changes.",
|
"subscribedTaskThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this task through its namespace.",
|
||||||
"notSubscribed": "You are not subscribed to this {entity} and won't receive notifications for changes.",
|
"subscribedTaskThroughParentList": "You can't unsubscribe here because you are subscribed to this task through its list.",
|
||||||
|
"subscribedNamespace": "You are currently subscribed to this namespace and will receive notifications for changes.",
|
||||||
|
"notSubscribedNamespace": "You are not subscribed to this namespace and won't receive notifications for changes.",
|
||||||
|
"subscribedList": "You are currently subscribed to this list and will receive notifications for changes.",
|
||||||
|
"notSubscribedList": "You are not subscribed to this list and won't receive notifications for changes.",
|
||||||
|
"subscribedTask": "You are currently subscribed to this task and will receive notifications for changes.",
|
||||||
|
"notSubscribedTask": "You are not subscribed to this task and won't receive notifications for changes.",
|
||||||
"subscribe": "Subscribe",
|
"subscribe": "Subscribe",
|
||||||
"unsubscribe": "Unsubscribe",
|
"unsubscribe": "Unsubscribe",
|
||||||
"subscribeSuccess": "You are now subscribed to this {entity}",
|
"subscribeSuccessNamespace": "You are now subscribed to this namespace",
|
||||||
"unsubscribeSuccess": "You are now unsubscribed to this {entity}"
|
"unsubscribeSuccessNamespace": "You are now unsubscribed to this namespace",
|
||||||
|
"subscribeSuccessList": "You are now subscribed to this list",
|
||||||
|
"unsubscribeSuccessList": "You are now unsubscribed to this list",
|
||||||
|
"subscribeSuccessTask": "You are now subscribed to this task",
|
||||||
|
"unsubscribeSuccessTask": "You are now unsubscribed to this task"
|
||||||
},
|
},
|
||||||
"attachment": {
|
"attachment": {
|
||||||
"title": "Attachments",
|
"title": "Attachments",
|
||||||
|
@ -690,7 +700,11 @@
|
||||||
"deleteTooltip": "Delete this attachment",
|
"deleteTooltip": "Delete this attachment",
|
||||||
"deleteText1": "Are you sure you want to delete the attachment {filename}?",
|
"deleteText1": "Are you sure you want to delete the attachment {filename}?",
|
||||||
"copyUrl": "Copy URL",
|
"copyUrl": "Copy URL",
|
||||||
"copyUrlTooltip": "Copy the url of this attachment for usage in text"
|
"copyUrlTooltip": "Copy the url of this attachment for usage in text",
|
||||||
|
"setAsCover": "Make cover",
|
||||||
|
"unsetAsCover": "Remove cover",
|
||||||
|
"successfullyChangedCoverImage": "The cover image was successfully changed.",
|
||||||
|
"usedAsCover": "Cover image"
|
||||||
},
|
},
|
||||||
"comment": {
|
"comment": {
|
||||||
"title": "Comments",
|
"title": "Comments",
|
||||||
|
@ -839,6 +853,12 @@
|
||||||
"text1": "Are you sure you want to remove this user from the team?",
|
"text1": "Are you sure you want to remove this user from the team?",
|
||||||
"text2": "They will lose access to all lists and namespaces this team has access to. This CANNOT BE UNDONE!",
|
"text2": "They will lose access to all lists and namespaces this team has access to. This CANNOT BE UNDONE!",
|
||||||
"success": "The user was successfully deleted from the team."
|
"success": "The user was successfully deleted from the team."
|
||||||
|
},
|
||||||
|
"leave": {
|
||||||
|
"title": "Leave team",
|
||||||
|
"text1": "Are you sure you want to leave this team?",
|
||||||
|
"text2": "You will loose access to all lists and namespaces this team has access to. If you change your mind you'll need a team admin to add you again.",
|
||||||
|
"success": "You have successfully left the team."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"attributes": {
|
"attributes": {
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -13,6 +13,7 @@ import type {IRepeatAfter} from '@/types/IRepeatAfter'
|
||||||
import type {IRepeatMode} from '@/types/IRepeatMode'
|
import type {IRepeatMode} from '@/types/IRepeatMode'
|
||||||
|
|
||||||
import type {PartialWithId} from '@/types/PartialWithId'
|
import type {PartialWithId} from '@/types/PartialWithId'
|
||||||
|
|
||||||
export interface ITask extends IAbstract {
|
export interface ITask extends IAbstract {
|
||||||
id: number
|
id: number
|
||||||
title: string
|
title: string
|
||||||
|
@ -33,8 +34,9 @@ export interface ITask extends IAbstract {
|
||||||
parentTaskId: ITask['id']
|
parentTaskId: ITask['id']
|
||||||
hexColor: string
|
hexColor: string
|
||||||
percentDone: number
|
percentDone: number
|
||||||
relatedTasks: Partial<Record<IRelationKind, ITask[]>>,
|
relatedTasks: Partial<Record<IRelationKind, ITask[]>>
|
||||||
attachments: IAttachment[]
|
attachments: IAttachment[]
|
||||||
|
coverImageAttachmentId: IAttachment['id']
|
||||||
identifier: string
|
identifier: string
|
||||||
index: number
|
index: number
|
||||||
isFavorite: boolean
|
isFavorite: boolean
|
||||||
|
|
|
@ -7,7 +7,7 @@ export const AUTH_TYPES = {
|
||||||
'LINK_SHARE': 2,
|
'LINK_SHARE': 2,
|
||||||
} as const
|
} as const
|
||||||
|
|
||||||
type AuthType = typeof AUTH_TYPES[keyof typeof AUTH_TYPES]
|
export type AuthType = typeof AUTH_TYPES[keyof typeof AUTH_TYPES]
|
||||||
|
|
||||||
export interface IUser extends IAbstract {
|
export interface IUser extends IAbstract {
|
||||||
id: number
|
id: number
|
||||||
|
|
|
@ -5,6 +5,8 @@ import type { IUser } from '@/modelTypes/IUser'
|
||||||
import type { IFile } from '@/modelTypes/IFile'
|
import type { IFile } from '@/modelTypes/IFile'
|
||||||
import type { IAttachment } from '@/modelTypes/IAttachment'
|
import type { IAttachment } from '@/modelTypes/IAttachment'
|
||||||
|
|
||||||
|
export const SUPPORTED_IMAGE_SUFFIX = ['.jpg', '.png', '.bmp', '.gif']
|
||||||
|
|
||||||
export default class AttachmentModel extends AbstractModel<IAttachment> implements IAttachment {
|
export default class AttachmentModel extends AbstractModel<IAttachment> implements IAttachment {
|
||||||
id = 0
|
id = 0
|
||||||
taskId = 0
|
taskId = 0
|
||||||
|
|
|
@ -9,6 +9,7 @@ import {setTitle} from '@/helpers/setTitle'
|
||||||
|
|
||||||
import {useListStore} from '@/stores/lists'
|
import {useListStore} from '@/stores/lists'
|
||||||
import {useAuthStore} from '@/stores/auth'
|
import {useAuthStore} from '@/stores/auth'
|
||||||
|
import {useBaseStore} from '@/stores/base'
|
||||||
|
|
||||||
import HomeComponent from '../views/Home.vue'
|
import HomeComponent from '../views/Home.vue'
|
||||||
import NotFoundComponent from '../views/404.vue'
|
import NotFoundComponent from '../views/404.vue'
|
||||||
|
@ -465,11 +466,18 @@ const router = createRouter({
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
export function getAuthForRoute(route: RouteLocation) {
|
export async function getAuthForRoute(route: RouteLocation) {
|
||||||
const authStore = useAuthStore()
|
const authStore = useAuthStore()
|
||||||
if (authStore.authUser || authStore.authLinkShare) {
|
if (authStore.authUser || authStore.authLinkShare) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const baseStore = useBaseStore()
|
||||||
|
// When trying this before the current user was fully loaded we might get a flash of the login screen
|
||||||
|
// in the user shell. To make shure this does not happen we check if everything is ready before trying.
|
||||||
|
if (!baseStore.ready) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Check if the user is already logged in and redirect them to the home page if not
|
// Check if the user is already logged in and redirect them to the home page if not
|
||||||
if (
|
if (
|
||||||
|
@ -482,11 +490,24 @@ export function getAuthForRoute(route: RouteLocation) {
|
||||||
'openid.auth',
|
'openid.auth',
|
||||||
].includes(route.name as string) &&
|
].includes(route.name as string) &&
|
||||||
localStorage.getItem('passwordResetToken') === null &&
|
localStorage.getItem('passwordResetToken') === null &&
|
||||||
localStorage.getItem('emailConfirmToken') === null
|
localStorage.getItem('emailConfirmToken') === null &&
|
||||||
|
!(route.name === 'home' && (typeof route.query.userPasswordReset !== 'undefined' || typeof route.query.userEmailConfirm !== 'undefined'))
|
||||||
) {
|
) {
|
||||||
saveLastVisited(route.name as string, route.params)
|
saveLastVisited(route.name as string, route.params, route.query)
|
||||||
|
return {name: 'user.login'}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(localStorage.getItem('passwordResetToken') !== null && route.name !== 'user.password-reset.reset') {
|
||||||
|
return {name: 'user.password-reset.reset'}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(localStorage.getItem('emailConfirmToken') !== null && route.name !== 'user.login') {
|
||||||
return {name: 'user.login'}
|
return {name: 'user.login'}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
router.beforeEach(async (to) => {
|
||||||
|
return getAuthForRoute(to)
|
||||||
|
})
|
||||||
|
|
||||||
export default router
|
export default router
|
|
@ -183,11 +183,11 @@ export default abstract class AbstractService<Model extends IAbstract = IAbstrac
|
||||||
////////////////
|
////////////////
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The modelFactory returns an model from an object.
|
* The modelFactory returns a model from an object.
|
||||||
* This one here is the default one, usually the service definitions for a model will override this.
|
* This one here is the default one, usually the service definitions for a model will override this.
|
||||||
*/
|
*/
|
||||||
modelFactory(data : Partial<Model>) {
|
modelFactory(data : Partial<Model>) {
|
||||||
return new AbstractModel(data)
|
return data as Model
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -22,7 +22,6 @@ export default class AbstractMigrationFileService extends AbstractService {
|
||||||
}
|
}
|
||||||
|
|
||||||
migrate(file: IFile) {
|
migrate(file: IFile) {
|
||||||
console.log(file)
|
|
||||||
return this.uploadFile(
|
return this.uploadFile(
|
||||||
this.paths.create,
|
this.paths.create,
|
||||||
file,
|
file,
|
||||||
|
|
|
@ -3,7 +3,7 @@ import {defineStore, acceptHMRUpdate} from 'pinia'
|
||||||
import {HTTPFactory, AuthenticatedHTTPFactory} from '@/http-common'
|
import {HTTPFactory, AuthenticatedHTTPFactory} from '@/http-common'
|
||||||
import {i18n, getCurrentLanguage, saveLanguage} from '@/i18n'
|
import {i18n, getCurrentLanguage, saveLanguage} from '@/i18n'
|
||||||
import {objectToSnakeCase} from '@/helpers/case'
|
import {objectToSnakeCase} from '@/helpers/case'
|
||||||
import UserModel, { getAvatarUrl } from '@/models/user'
|
import UserModel, { getAvatarUrl, getDisplayName } from '@/models/user'
|
||||||
import UserSettingsService from '@/services/userSettings'
|
import UserSettingsService from '@/services/userSettings'
|
||||||
import {getToken, refreshToken, removeToken, saveToken} from '@/helpers/auth'
|
import {getToken, refreshToken, removeToken, saveToken} from '@/helpers/auth'
|
||||||
import {setModuleLoading} from '@/stores/helper'
|
import {setModuleLoading} from '@/stores/helper'
|
||||||
|
@ -55,6 +55,9 @@ export const useAuthStore = defineStore('auth', {
|
||||||
state.info.type === AUTH_TYPES.LINK_SHARE
|
state.info.type === AUTH_TYPES.LINK_SHARE
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
userDisplayName(state) {
|
||||||
|
return state.info ? getDisplayName(state.info) : undefined
|
||||||
|
},
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
setIsLoading(isLoading: boolean) {
|
setIsLoading(isLoading: boolean) {
|
||||||
|
@ -115,7 +118,7 @@ export const useAuthStore = defineStore('auth', {
|
||||||
saveToken(response.data.token, true)
|
saveToken(response.data.token, true)
|
||||||
|
|
||||||
// Tell others the user is autheticated
|
// Tell others the user is autheticated
|
||||||
this.checkAuth()
|
await this.checkAuth()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (
|
if (
|
||||||
e.response &&
|
e.response &&
|
||||||
|
@ -168,7 +171,7 @@ export const useAuthStore = defineStore('auth', {
|
||||||
saveToken(response.data.token, true)
|
saveToken(response.data.token, true)
|
||||||
|
|
||||||
// Tell others the user is autheticated
|
// Tell others the user is autheticated
|
||||||
this.checkAuth()
|
await this.checkAuth()
|
||||||
} finally {
|
} finally {
|
||||||
this.setIsLoading(false)
|
this.setIsLoading(false)
|
||||||
}
|
}
|
||||||
|
@ -180,14 +183,14 @@ export const useAuthStore = defineStore('auth', {
|
||||||
password: password,
|
password: password,
|
||||||
})
|
})
|
||||||
saveToken(response.data.token, false)
|
saveToken(response.data.token, false)
|
||||||
this.checkAuth()
|
await this.checkAuth()
|
||||||
return response.data
|
return response.data
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Populates user information from jwt token saved in local storage in store
|
* Populates user information from jwt token saved in local storage in store
|
||||||
*/
|
*/
|
||||||
checkAuth() {
|
async checkAuth() {
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
const inOneMinute = new Date(new Date().setMinutes(now.getMinutes() + 1))
|
const inOneMinute = new Date(new Date().setMinutes(now.getMinutes() + 1))
|
||||||
// This function can be called from multiple places at the same time and shortly after one another.
|
// This function can be called from multiple places at the same time and shortly after one another.
|
||||||
|
@ -212,7 +215,7 @@ export const useAuthStore = defineStore('auth', {
|
||||||
this.setUser(info)
|
this.setUser(info)
|
||||||
|
|
||||||
if (authenticated) {
|
if (authenticated) {
|
||||||
this.refreshUserInfo()
|
await this.refreshUserInfo()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,6 +224,8 @@ export const useAuthStore = defineStore('auth', {
|
||||||
this.setUser(null)
|
this.setUser(null)
|
||||||
this.redirectToProviderIfNothingElseIsEnabled()
|
this.redirectToProviderIfNothingElseIsEnabled()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Promise.resolve(authenticated)
|
||||||
},
|
},
|
||||||
|
|
||||||
redirectToProviderIfNothingElseIsEnabled() {
|
redirectToProviderIfNothingElseIsEnabled() {
|
||||||
|
@ -290,11 +295,11 @@ export const useAuthStore = defineStore('auth', {
|
||||||
const stopLoading = setModuleLoading(this)
|
const stopLoading = setModuleLoading(this)
|
||||||
try {
|
try {
|
||||||
await HTTPFactory().post('user/confirm', {token: emailVerifyToken})
|
await HTTPFactory().post('user/confirm', {token: emailVerifyToken})
|
||||||
localStorage.removeItem('emailConfirmToken')
|
|
||||||
return true
|
return true
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
throw new Error(e.response.data.message)
|
throw new Error(e.response.data.message)
|
||||||
} finally {
|
} finally {
|
||||||
|
localStorage.removeItem('emailConfirmToken')
|
||||||
stopLoading()
|
stopLoading()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -339,22 +344,22 @@ export const useAuthStore = defineStore('auth', {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await refreshToken(!this.isLinkShareAuth)
|
await refreshToken(!this.isLinkShareAuth)
|
||||||
this.checkAuth()
|
await this.checkAuth()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Don't logout on network errors as the user would then get logged out if they don't have
|
// Don't logout on network errors as the user would then get logged out if they don't have
|
||||||
// internet for a short period of time - such as when the laptop is still reconnecting
|
// internet for a short period of time - such as when the laptop is still reconnecting
|
||||||
if (e?.request?.status) {
|
if (e?.request?.status) {
|
||||||
this.logout()
|
await this.logout()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 5000)
|
}, 5000)
|
||||||
},
|
},
|
||||||
|
|
||||||
logout() {
|
async logout() {
|
||||||
removeToken()
|
removeToken()
|
||||||
window.localStorage.clear() // Clear all settings and history we might have saved in local storage.
|
window.localStorage.clear() // Clear all settings and history we might have saved in local storage.
|
||||||
router.push({name: 'user.login'})
|
await router.push({name: 'user.login'})
|
||||||
this.checkAuth()
|
await this.checkAuth()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -11,6 +11,7 @@ import type {IList} from '@/modelTypes/IList'
|
||||||
|
|
||||||
export interface RootStoreState {
|
export interface RootStoreState {
|
||||||
loading: boolean,
|
loading: boolean,
|
||||||
|
ready: boolean,
|
||||||
|
|
||||||
currentList: IList | null,
|
currentList: IList | null,
|
||||||
background: string,
|
background: string,
|
||||||
|
@ -26,6 +27,7 @@ export interface RootStoreState {
|
||||||
export const useBaseStore = defineStore('base', {
|
export const useBaseStore = defineStore('base', {
|
||||||
state: () : RootStoreState => ({
|
state: () : RootStoreState => ({
|
||||||
loading: false,
|
loading: false,
|
||||||
|
ready: false,
|
||||||
|
|
||||||
// This is used to highlight the current list in menu for all list related views
|
// This is used to highlight the current list in menu for all list related views
|
||||||
currentList: new ListModel({
|
currentList: new ListModel({
|
||||||
|
@ -95,6 +97,10 @@ export const useBaseStore = defineStore('base', {
|
||||||
setLogoVisible(visible: boolean) {
|
setLogoVisible(visible: boolean) {
|
||||||
this.logoVisible = visible
|
this.logoVisible = visible
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setReady(ready: boolean) {
|
||||||
|
this.ready = ready
|
||||||
|
},
|
||||||
|
|
||||||
async handleSetCurrentList({list, forceUpdate = false} : {list: IList | null, forceUpdate: boolean}) {
|
async handleSetCurrentList({list, forceUpdate = false} : {list: IList | null, forceUpdate: boolean}) {
|
||||||
if (list === null) {
|
if (list === null) {
|
||||||
|
@ -133,7 +139,8 @@ export const useBaseStore = defineStore('base', {
|
||||||
|
|
||||||
async loadApp() {
|
async loadApp() {
|
||||||
await checkAndSetApiUrl(window.API_URL)
|
await checkAndSetApiUrl(window.API_URL)
|
||||||
useAuthStore().checkAuth()
|
await useAuthStore().checkAuth()
|
||||||
|
this.ready = true
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -75,12 +75,11 @@ export const useKanbanStore = defineStore('kanban', {
|
||||||
getTaskById(state) {
|
getTaskById(state) {
|
||||||
return (id: ITask['id']) => {
|
return (id: ITask['id']) => {
|
||||||
const { bucketIndex, taskIndex } = getTaskIndicesById(state, id)
|
const { bucketIndex, taskIndex } = getTaskIndicesById(state, id)
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
bucketIndex,
|
bucketIndex,
|
||||||
taskIndex,
|
taskIndex,
|
||||||
task: bucketIndex && taskIndex && state.buckets[bucketIndex]?.tasks?.[taskIndex] || null,
|
task: bucketIndex !== null && taskIndex !== null && state.buckets[bucketIndex]?.tasks?.[taskIndex] || null,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -43,7 +43,7 @@ export const useNamespaceStore = defineStore('namespace', {
|
||||||
getNamespaceById: state => (namespaceId: INamespace['id']) => {
|
getNamespaceById: state => (namespaceId: INamespace['id']) => {
|
||||||
return state.namespaces.find(({id}) => id == namespaceId) || null
|
return state.namespaces.find(({id}) => id == namespaceId) || null
|
||||||
},
|
},
|
||||||
|
|
||||||
searchNamespace() {
|
searchNamespace() {
|
||||||
return (query: string) => (
|
return (query: string) => (
|
||||||
search(query)
|
search(query)
|
||||||
|
@ -64,6 +64,13 @@ export const useNamespaceStore = defineStore('namespace', {
|
||||||
this.namespaces = namespaces
|
this.namespaces = namespaces
|
||||||
namespaces.forEach(n => {
|
namespaces.forEach(n => {
|
||||||
add(n)
|
add(n)
|
||||||
|
|
||||||
|
// Check for each list in that namespace if it has a subscription and set it if not
|
||||||
|
n.lists.forEach(l => {
|
||||||
|
if (l.subscription === null || l.subscription.entity !== 'list') {
|
||||||
|
l.subscription = n.subscription
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -203,5 +210,5 @@ export const useNamespaceStore = defineStore('namespace', {
|
||||||
|
|
||||||
// support hot reloading
|
// support hot reloading
|
||||||
if (import.meta.hot) {
|
if (import.meta.hot) {
|
||||||
import.meta.hot.accept(acceptHMRUpdate(useNamespaceStore, import.meta.hot))
|
import.meta.hot.accept(acceptHMRUpdate(useNamespaceStore, import.meta.hot))
|
||||||
}
|
}
|
|
@ -28,6 +28,7 @@ import {useLabelStore} from '@/stores/labels'
|
||||||
import {useListStore} from '@/stores/lists'
|
import {useListStore} from '@/stores/lists'
|
||||||
import {useAttachmentStore} from '@/stores/attachments'
|
import {useAttachmentStore} from '@/stores/attachments'
|
||||||
import {useKanbanStore} from '@/stores/kanban'
|
import {useKanbanStore} from '@/stores/kanban'
|
||||||
|
import {useBaseStore} from '@/stores/base'
|
||||||
|
|
||||||
// IDEA: maybe use a small fuzzy search here to prevent errors
|
// IDEA: maybe use a small fuzzy search here to prevent errors
|
||||||
function findPropertyByValue(object, key, value) {
|
function findPropertyByValue(object, key, value) {
|
||||||
|
@ -105,6 +106,7 @@ export const useTaskStore = defineStore('task', {
|
||||||
const cancel = setModuleLoading(this)
|
const cancel = setModuleLoading(this)
|
||||||
try {
|
try {
|
||||||
this.tasks = await taskService.getAll({}, params)
|
this.tasks = await taskService.getAll({}, params)
|
||||||
|
useBaseStore().setHasTasks(this.tasks.length > 0)
|
||||||
return this.tasks
|
return this.tasks
|
||||||
} finally {
|
} finally {
|
||||||
cancel()
|
cancel()
|
||||||
|
@ -171,32 +173,39 @@ export const useTaskStore = defineStore('task', {
|
||||||
user: IUser,
|
user: IUser,
|
||||||
taskId: ITask['id']
|
taskId: ITask['id']
|
||||||
}) {
|
}) {
|
||||||
const kanbanStore = useKanbanStore()
|
const cancel = setModuleLoading(this)
|
||||||
const taskAssigneeService = new TaskAssigneeService()
|
|
||||||
const r = await taskAssigneeService.create(new TaskAssigneeModel({
|
try {
|
||||||
userId: user.id,
|
const kanbanStore = useKanbanStore()
|
||||||
taskId: taskId,
|
const taskAssigneeService = new TaskAssigneeService()
|
||||||
}))
|
const r = await taskAssigneeService.create(new TaskAssigneeModel({
|
||||||
const t = kanbanStore.getTaskById(taskId)
|
userId: user.id,
|
||||||
if (t.task === null) {
|
taskId: taskId,
|
||||||
// Don't try further adding a label if the task is not in kanban
|
}))
|
||||||
// Usually this means the kanban board hasn't been accessed until now.
|
const t = kanbanStore.getTaskById(taskId)
|
||||||
// Vuex seems to have its difficulties with that, so we just log the error and fail silently.
|
if (t.task === null) {
|
||||||
console.debug('Could not add assignee to task in kanban, task not found', t)
|
// Don't try further adding a label if the task is not in kanban
|
||||||
return r
|
// Usually this means the kanban board hasn't been accessed until now.
|
||||||
}
|
// Vuex seems to have its difficulties with that, so we just log the error and fail silently.
|
||||||
|
console.debug('Could not add assignee to task in kanban, task not found', t)
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
kanbanStore.setTaskInBucketByIndex({
|
kanbanStore.setTaskInBucketByIndex({
|
||||||
...t,
|
...t,
|
||||||
task: {
|
task: {
|
||||||
...t.task,
|
...t.task,
|
||||||
assignees: [
|
assignees: [
|
||||||
...t.task.assignees,
|
...t.task.assignees,
|
||||||
user,
|
user,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
return r
|
|
||||||
|
return r
|
||||||
|
} finally {
|
||||||
|
cancel()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async removeAssignee({
|
async removeAssignee({
|
||||||
|
@ -252,7 +261,7 @@ export const useTaskStore = defineStore('task', {
|
||||||
// Don't try further adding a label if the task is not in kanban
|
// Don't try further adding a label if the task is not in kanban
|
||||||
// Usually this means the kanban board hasn't been accessed until now.
|
// Usually this means the kanban board hasn't been accessed until now.
|
||||||
// Vuex seems to have its difficulties with that, so we just log the error and fail silently.
|
// Vuex seems to have its difficulties with that, so we just log the error and fail silently.
|
||||||
console.debug('Could not add label to task in kanban, task not found', t)
|
console.debug('Could not add label to task in kanban, task not found', {taskId, t})
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,6 +387,7 @@ export const useTaskStore = defineStore('task', {
|
||||||
})
|
})
|
||||||
|
|
||||||
if(foundListId === null || foundListId === 0) {
|
if(foundListId === null || foundListId === 0) {
|
||||||
|
cancel()
|
||||||
throw new Error('NO_LIST')
|
throw new Error('NO_LIST')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -409,6 +419,13 @@ export const useTaskStore = defineStore('task', {
|
||||||
cancel()
|
cancel()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async setCoverImage(task: ITask, attachment: IAttachment | null) {
|
||||||
|
return this.update({
|
||||||
|
...task,
|
||||||
|
coverImageAttachmentId: attachment ? attachment.id : 0,
|
||||||
|
})
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
declare module 'vue-flatpickr-component' {
|
|
||||||
import type {DefineComponent} from 'vue'
|
|
||||||
export default DefineComponent<>
|
|
||||||
}
|
|
|
@ -34,9 +34,10 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {computed} from 'vue'
|
import {computed} from 'vue'
|
||||||
|
|
||||||
import {VERSION as frontendVersion} from '@/version.json'
|
import {VERSION} from '@/version.json'
|
||||||
import {useConfigStore} from '@/stores/config'
|
import {useConfigStore} from '@/stores/config'
|
||||||
|
|
||||||
const configStore = useConfigStore()
|
const configStore = useConfigStore()
|
||||||
const apiVersion = computed(() => configStore.version)
|
const apiVersion = computed(() => configStore.version)
|
||||||
|
const frontendVersion = VERSION
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="content has-text-centered">
|
<div class="content has-text-centered">
|
||||||
<h2 v-if="userInfo">
|
<h2 v-if="salutation">{{ salutation }}</h2>
|
||||||
{{ $t(welcome, {username: userInfo.name !== '' ? userInfo.name : userInfo.username}) }}!
|
|
||||||
</h2>
|
|
||||||
<message variant="danger" v-if="deletionScheduledAt !== null" class="mb-4">
|
<message variant="danger" v-if="deletionScheduledAt !== null" class="mb-4">
|
||||||
{{
|
{{
|
||||||
$t('user.deletion.scheduled', {
|
$t('user.deletion.scheduled', {
|
||||||
|
@ -69,7 +68,7 @@ import AddTask from '@/components/tasks/add-task.vue'
|
||||||
import {getHistory} from '@/modules/listHistory'
|
import {getHistory} from '@/modules/listHistory'
|
||||||
import {parseDateOrNull} from '@/helpers/parseDateOrNull'
|
import {parseDateOrNull} from '@/helpers/parseDateOrNull'
|
||||||
import {formatDateShort, formatDateSince} from '@/helpers/time/formatDate'
|
import {formatDateShort, formatDateSince} from '@/helpers/time/formatDate'
|
||||||
import {useDateTimeSalutation} from '@/composables/useDateTimeSalutation'
|
import {useDaytimeSalutation} from '@/composables/useDaytimeSalutation'
|
||||||
|
|
||||||
import {useBaseStore} from '@/stores/base'
|
import {useBaseStore} from '@/stores/base'
|
||||||
import {useListStore} from '@/stores/lists'
|
import {useListStore} from '@/stores/lists'
|
||||||
|
@ -78,7 +77,7 @@ import {useNamespaceStore} from '@/stores/namespaces'
|
||||||
import {useAuthStore} from '@/stores/auth'
|
import {useAuthStore} from '@/stores/auth'
|
||||||
import {useTaskStore} from '@/stores/tasks'
|
import {useTaskStore} from '@/stores/tasks'
|
||||||
|
|
||||||
const welcome = useDateTimeSalutation()
|
const salutation = useDaytimeSalutation()
|
||||||
|
|
||||||
const baseStore = useBaseStore()
|
const baseStore = useBaseStore()
|
||||||
const authStore = useAuthStore()
|
const authStore = useAuthStore()
|
||||||
|
@ -99,7 +98,6 @@ const listHistory = computed(() => {
|
||||||
})
|
})
|
||||||
|
|
||||||
const migratorsEnabled = computed(() => configStore.availableMigrators?.length > 0)
|
const migratorsEnabled = computed(() => configStore.availableMigrators?.length > 0)
|
||||||
const userInfo = computed(() => authStore.info)
|
|
||||||
const hasTasks = computed(() => baseStore.hasTasks)
|
const hasTasks = computed(() => baseStore.hasTasks)
|
||||||
const defaultListId = computed(() => authStore.settings.defaultListId)
|
const defaultListId = computed(() => authStore.settings.defaultListId)
|
||||||
const defaultNamespaceId = computed(() => namespaceStore.namespaces?.[0]?.id || 0)
|
const defaultNamespaceId = computed(() => namespaceStore.namespaces?.[0]?.id || 0)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<ListWrapper class="list-kanban" :list-id="listId" viewName="kanban">
|
<ListWrapper class="list-kanban" :list-id="listId" viewName="kanban">
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="filter-container" v-if="isSavedFilter(list)">
|
<div class="filter-container" v-if="!isSavedFilter(listId)">
|
||||||
<div class="items">
|
<div class="items">
|
||||||
<filter-popup
|
<filter-popup
|
||||||
v-model="params"
|
v-model="params"
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<create-edit
|
<create-edit
|
||||||
:title="$t('list.share.header')"
|
:title="$t('list.share.header')"
|
||||||
primary-label=""
|
:has-primary-action="false"
|
||||||
>
|
>
|
||||||
<template v-if="list">
|
<template v-if="list">
|
||||||
<userTeam
|
<userTeam
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
<svg viewBox="0 0 88 88" xmlns="http://www.w3.org/2000/svg" class="logo_1OKcB"><g fill="none" fill-rule="evenodd"><rect></rect><path d="M30.755 33.292l-7.34 8.935L40.798 56.48a5.782 5.782 0 008.182-.854l31.179-38.93-9.026-7.228L43.614 43.83l-12.86-10.538z" fill="#FFB000"></path><path d="M44 78.1C25.197 78.1 9.9 62.803 9.9 44S25.197 9.9 44 9.9V0C19.738 0 0 19.738 0 44s19.738 44 44 44 44-19.738 44-44h-9.9c0 18.803-15.297 34.1-34.1 34.1" fill="#4772FA"></path></g></svg>
|
After Width: | Height: | Size: 471 B |
|
@ -3,6 +3,7 @@ import todoistIcon from './icons/todoist.svg?url'
|
||||||
import trelloIcon from './icons/trello.svg?url'
|
import trelloIcon from './icons/trello.svg?url'
|
||||||
import microsoftTodoIcon from './icons/microsoft-todo.svg?url'
|
import microsoftTodoIcon from './icons/microsoft-todo.svg?url'
|
||||||
import vikunjaFileIcon from './icons/vikunja-file.png?url'
|
import vikunjaFileIcon from './icons/vikunja-file.png?url'
|
||||||
|
import tickTickIcon from './icons/ticktick.svg?url'
|
||||||
|
|
||||||
export interface Migrator {
|
export interface Migrator {
|
||||||
id: string
|
id: string
|
||||||
|
@ -42,4 +43,10 @@ export const MIGRATORS: IMigratorRecord = {
|
||||||
icon: vikunjaFileIcon,
|
icon: vikunjaFileIcon,
|
||||||
isFileMigrator: true,
|
isFileMigrator: true,
|
||||||
},
|
},
|
||||||
|
ticktick: {
|
||||||
|
id: 'ticktick',
|
||||||
|
name: 'TickTick',
|
||||||
|
icon: tickTickIcon as string,
|
||||||
|
isFileMigrator: true,
|
||||||
|
},
|
||||||
}
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<create-edit
|
<create-edit
|
||||||
:title="title"
|
:title="title"
|
||||||
primary-label=""
|
:has-primary-action="false"
|
||||||
>
|
>
|
||||||
<template v-if="namespace">
|
<template v-if="namespace">
|
||||||
<manageSharing
|
<manageSharing
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
:disabled="!canWrite"
|
:disabled="!canWrite"
|
||||||
:list-id="task.listId"
|
:list-id="task.listId"
|
||||||
:task-id="task.id"
|
:task-id="task.id"
|
||||||
ref="assignees"
|
:ref="e => setFieldRef('assignees', e)"
|
||||||
v-model="task.assignees"
|
v-model="task.assignees"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -39,8 +39,8 @@
|
||||||
</div>
|
</div>
|
||||||
<priority-select
|
<priority-select
|
||||||
:disabled="!canWrite"
|
:disabled="!canWrite"
|
||||||
@update:model-value="saveTask"
|
@update:model-value="setPriority"
|
||||||
ref="priority"
|
:ref="e => setFieldRef('priority', e)"
|
||||||
v-model="task.priority"/>
|
v-model="task.priority"/>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
|
@ -57,7 +57,7 @@
|
||||||
@close-on-change="() => saveTask()"
|
@close-on-change="() => saveTask()"
|
||||||
:choose-date-label="$t('task.detail.chooseDueDate')"
|
:choose-date-label="$t('task.detail.chooseDueDate')"
|
||||||
:disabled="taskService.loading || !canWrite"
|
:disabled="taskService.loading || !canWrite"
|
||||||
ref="dueDate"
|
:ref="e => setFieldRef('dueDate', e)"
|
||||||
/>
|
/>
|
||||||
<BaseButton
|
<BaseButton
|
||||||
@click="() => {task.dueDate = null;saveTask()}"
|
@click="() => {task.dueDate = null;saveTask()}"
|
||||||
|
@ -79,8 +79,8 @@
|
||||||
</div>
|
</div>
|
||||||
<percent-done-select
|
<percent-done-select
|
||||||
:disabled="!canWrite"
|
:disabled="!canWrite"
|
||||||
@update:model-value="saveTask"
|
@update:model-value="setPercentDone"
|
||||||
ref="percentDone"
|
:ref="e => setFieldRef('percentDone', e)"
|
||||||
v-model="task.percentDone"/>
|
v-model="task.percentDone"/>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
|
@ -97,7 +97,7 @@
|
||||||
@close-on-change="() => saveTask()"
|
@close-on-change="() => saveTask()"
|
||||||
:choose-date-label="$t('task.detail.chooseStartDate')"
|
:choose-date-label="$t('task.detail.chooseStartDate')"
|
||||||
:disabled="taskService.loading || !canWrite"
|
:disabled="taskService.loading || !canWrite"
|
||||||
ref="startDate"
|
:ref="e => setFieldRef('startDate', e)"
|
||||||
/>
|
/>
|
||||||
<BaseButton
|
<BaseButton
|
||||||
@click="() => {task.startDate = null;saveTask()}"
|
@click="() => {task.startDate = null;saveTask()}"
|
||||||
|
@ -124,7 +124,7 @@
|
||||||
@close-on-change="() => saveTask()"
|
@close-on-change="() => saveTask()"
|
||||||
:choose-date-label="$t('task.detail.chooseEndDate')"
|
:choose-date-label="$t('task.detail.chooseEndDate')"
|
||||||
:disabled="taskService.loading || !canWrite"
|
:disabled="taskService.loading || !canWrite"
|
||||||
ref="endDate"
|
:ref="e => setFieldRef('endDate', e)"
|
||||||
/>
|
/>
|
||||||
<BaseButton
|
<BaseButton
|
||||||
@click="() => {task.endDate = null;saveTask()}"
|
@click="() => {task.endDate = null;saveTask()}"
|
||||||
|
@ -146,7 +146,7 @@
|
||||||
</div>
|
</div>
|
||||||
<reminders
|
<reminders
|
||||||
:disabled="!canWrite"
|
:disabled="!canWrite"
|
||||||
ref="reminders"
|
:ref="e => setFieldRef('reminders', e)"
|
||||||
v-model="task.reminderDates"
|
v-model="task.reminderDates"
|
||||||
@update:model-value="saveTask"
|
@update:model-value="saveTask"
|
||||||
/>
|
/>
|
||||||
|
@ -171,7 +171,7 @@
|
||||||
</div>
|
</div>
|
||||||
<repeat-after
|
<repeat-after
|
||||||
:disabled="!canWrite"
|
:disabled="!canWrite"
|
||||||
ref="repeatAfter"
|
:ref="e => setFieldRef('repeatAfter', e)"
|
||||||
v-model="task"
|
v-model="task"
|
||||||
@update:model-value="saveTask"
|
@update:model-value="saveTask"
|
||||||
/>
|
/>
|
||||||
|
@ -186,7 +186,7 @@
|
||||||
</div>
|
</div>
|
||||||
<color-picker
|
<color-picker
|
||||||
menu-position="bottom"
|
menu-position="bottom"
|
||||||
ref="color"
|
:ref="e => setFieldRef('color', e)"
|
||||||
v-model="taskColor"
|
v-model="taskColor"
|
||||||
@update:model-value="saveTask"
|
@update:model-value="saveTask"
|
||||||
/>
|
/>
|
||||||
|
@ -202,7 +202,11 @@
|
||||||
</span>
|
</span>
|
||||||
{{ $t('task.attributes.labels') }}
|
{{ $t('task.attributes.labels') }}
|
||||||
</div>
|
</div>
|
||||||
<edit-labels :disabled="!canWrite" :task-id="taskId" ref="labels" v-model="task.labels"/>
|
<edit-labels
|
||||||
|
:disabled="!canWrite"
|
||||||
|
:task-id="taskId"
|
||||||
|
:ref="e => setFieldRef('labels', e)"
|
||||||
|
v-model="task.labels"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Description -->
|
<!-- Description -->
|
||||||
|
@ -218,8 +222,9 @@
|
||||||
<div class="content attachments" v-if="activeFields.attachments || hasAttachments">
|
<div class="content attachments" v-if="activeFields.attachments || hasAttachments">
|
||||||
<attachments
|
<attachments
|
||||||
:edit-enabled="canWrite"
|
:edit-enabled="canWrite"
|
||||||
:task-id="taskId"
|
:task="task"
|
||||||
ref="attachments"
|
@task-changed="({coverImageAttachmentId}) => task.coverImageAttachmentId = coverImageAttachmentId"
|
||||||
|
:ref="e => setFieldRef('attachments', e)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -237,7 +242,7 @@
|
||||||
:list-id="task.listId"
|
:list-id="task.listId"
|
||||||
:show-no-relations-notice="true"
|
:show-no-relations-notice="true"
|
||||||
:task-id="taskId"
|
:task-id="taskId"
|
||||||
ref="relatedTasks"
|
:ref="e => setFieldRef('relatedTasks', e)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -251,7 +256,10 @@
|
||||||
</h3>
|
</h3>
|
||||||
<div class="field has-addons">
|
<div class="field has-addons">
|
||||||
<div class="control is-expanded">
|
<div class="control is-expanded">
|
||||||
<list-search @update:modelValue="changeList" ref="moveList"/>
|
<list-search
|
||||||
|
@update:modelValue="changeList"
|
||||||
|
:ref="e => setFieldRef('moveList', e)"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -442,7 +450,7 @@ import TaskModel, {TASK_DEFAULT_COLOR} from '@/models/task'
|
||||||
import type {ITask} from '@/modelTypes/ITask'
|
import type {ITask} from '@/modelTypes/ITask'
|
||||||
import type {IList} from '@/modelTypes/IList'
|
import type {IList} from '@/modelTypes/IList'
|
||||||
|
|
||||||
import {PRIORITIES} from '@/constants/priorities'
|
import {PRIORITIES, type Priority} from '@/constants/priorities'
|
||||||
import {RIGHTS} from '@/constants/rights'
|
import {RIGHTS} from '@/constants/rights'
|
||||||
|
|
||||||
import BaseButton from '@/components/base/BaseButton.vue'
|
import BaseButton from '@/components/base/BaseButton.vue'
|
||||||
|
@ -500,7 +508,7 @@ const attachmentStore = useAttachmentStore()
|
||||||
const taskStore = useTaskStore()
|
const taskStore = useTaskStore()
|
||||||
const kanbanStore = useKanbanStore()
|
const kanbanStore = useKanbanStore()
|
||||||
|
|
||||||
const task = reactive(new TaskModel())
|
const task = reactive<ITask>(new TaskModel())
|
||||||
useTitle(toRef(task, 'title'))
|
useTitle(toRef(task, 'title'))
|
||||||
|
|
||||||
// We doubled the task color property here because verte does not have a real change property, leading
|
// We doubled the task color property here because verte does not have a real change property, leading
|
||||||
|
@ -658,10 +666,14 @@ const activeFieldElements : {[id in FieldType]: HTMLElement | null} = reactive({
|
||||||
startDate: null,
|
startDate: null,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function setFieldRef(name, e) {
|
||||||
|
activeFieldElements[name] = unrefElement(e)
|
||||||
|
}
|
||||||
|
|
||||||
function setFieldActive(fieldName: keyof typeof activeFields) {
|
function setFieldActive(fieldName: keyof typeof activeFields) {
|
||||||
activeFields[fieldName] = true
|
activeFields[fieldName] = true
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
const el = unrefElement(activeFieldElements[fieldName])
|
const el = activeFieldElements[fieldName]
|
||||||
|
|
||||||
if (!el) {
|
if (!el) {
|
||||||
return
|
return
|
||||||
|
@ -675,21 +687,19 @@ function setFieldActive(fieldName: keyof typeof activeFields) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function saveTask(args?: {
|
async function saveTask(args?: {
|
||||||
task: ITask,
|
task: ITask,
|
||||||
showNotification?: boolean,
|
undoCallback?: () => void,
|
||||||
undoCallback?: () => void,
|
}) {
|
||||||
}) {
|
const {
|
||||||
const {
|
task: currentTask,
|
||||||
task: currentTask,
|
undoCallback,
|
||||||
showNotification,
|
} = {
|
||||||
undoCallback,
|
...{
|
||||||
} = {
|
task: cloneDeep(task),
|
||||||
...{
|
},
|
||||||
task: cloneDeep(task),
|
...args,
|
||||||
showNotification: true,
|
}
|
||||||
},
|
|
||||||
...args,
|
|
||||||
}
|
|
||||||
if (!canWrite.value) {
|
if (!canWrite.value) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -710,10 +720,6 @@ async function saveTask(args?: {
|
||||||
Object.assign(task, newTask)
|
Object.assign(task, newTask)
|
||||||
setActiveFields()
|
setActiveFields()
|
||||||
|
|
||||||
if (!showNotification) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let actions = []
|
let actions = []
|
||||||
if (undoCallback !== null) {
|
if (undoCallback !== null) {
|
||||||
actions = [{
|
actions = [{
|
||||||
|
@ -759,14 +765,34 @@ async function toggleFavorite() {
|
||||||
Object.assign(task, newTask)
|
Object.assign(task, newTask)
|
||||||
await namespaceStore.loadNamespacesIfFavoritesDontExist()
|
await namespaceStore.loadNamespacesIfFavoritesDontExist()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function setPriority(priority: Priority) {
|
||||||
|
const newTask: ITask = {
|
||||||
|
...task,
|
||||||
|
priority,
|
||||||
|
}
|
||||||
|
|
||||||
|
return saveTask({
|
||||||
|
task: newTask,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function setPercentDone(percentDone: number) {
|
||||||
|
const newTask: ITask = {
|
||||||
|
...task,
|
||||||
|
percentDone,
|
||||||
|
}
|
||||||
|
|
||||||
|
return saveTask({
|
||||||
|
task: newTask,
|
||||||
|
})
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
$flash-background-duration: 750ms;
|
$flash-background-duration: 750ms;
|
||||||
|
|
||||||
.task-view {
|
.task-view {
|
||||||
// This is a workaround to hide the llama background from the top on the task detail page
|
|
||||||
margin-top: -1.5rem;
|
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
background-color: var(--site-background);
|
background-color: var(--site-background);
|
||||||
|
|
||||||
|
|
|
@ -127,6 +127,24 @@
|
||||||
</table>
|
</table>
|
||||||
</card>
|
</card>
|
||||||
|
|
||||||
|
<x-button class="is-fullwidth is-danger" @click="showLeaveModal = true">
|
||||||
|
{{ $t('team.edit.leave.title') }}
|
||||||
|
</x-button>
|
||||||
|
|
||||||
|
<!-- Leave team modal -->
|
||||||
|
<modal
|
||||||
|
v-if="showLeaveModal"
|
||||||
|
@close="showLeaveModal = false"
|
||||||
|
@submit="leave()"
|
||||||
|
>
|
||||||
|
<template #header><span>{{ $t('team.edit.leave.title') }}</span></template>
|
||||||
|
|
||||||
|
<template #text>
|
||||||
|
<p>{{ $t('team.edit.leave.text1') }}<br/>
|
||||||
|
{{ $t('team.edit.leave.text2') }}</p>
|
||||||
|
</template>
|
||||||
|
</modal>
|
||||||
|
|
||||||
<!-- Team delete modal -->
|
<!-- Team delete modal -->
|
||||||
<transition name="modal">
|
<transition name="modal">
|
||||||
<modal
|
<modal
|
||||||
|
@ -202,13 +220,14 @@ const teamMemberService = ref<TeamMemberService>(new TeamMemberService())
|
||||||
const userService = ref<UserService>(new UserService())
|
const userService = ref<UserService>(new UserService())
|
||||||
|
|
||||||
const team = ref<ITeam>()
|
const team = ref<ITeam>()
|
||||||
const teamId = computed(() => route.params.id)
|
const teamId = computed(() => Number(route.params.id))
|
||||||
const memberToDelete = ref<ITeamMember>()
|
const memberToDelete = ref<ITeamMember>()
|
||||||
const newMember = ref<IUser>()
|
const newMember = ref<IUser>()
|
||||||
const foundUsers = ref<IUser[]>()
|
const foundUsers = ref<IUser[]>()
|
||||||
|
|
||||||
const showDeleteModal = ref(false)
|
const showDeleteModal = ref(false)
|
||||||
const showUserDeleteModal = ref(false)
|
const showUserDeleteModal = ref(false)
|
||||||
|
const showLeaveModal = ref(false)
|
||||||
const showError = ref(false)
|
const showError = ref(false)
|
||||||
|
|
||||||
const title = ref('')
|
const title = ref('')
|
||||||
|
@ -287,6 +306,19 @@ async function findUser(query: string) {
|
||||||
const users = await userService.value.getAll({}, {s: query})
|
const users = await userService.value.getAll({}, {s: query})
|
||||||
foundUsers.value = users.filter((u: IUser) => u.id !== userInfo.value.id)
|
foundUsers.value = users.filter((u: IUser) => u.id !== userInfo.value.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function leave() {
|
||||||
|
try {
|
||||||
|
await teamMemberService.value.delete({
|
||||||
|
teamId: teamId.value,
|
||||||
|
username: userInfo.value.username,
|
||||||
|
})
|
||||||
|
success({message: t('team.edit.leave.success')})
|
||||||
|
await router.push({name: 'home'})
|
||||||
|
} finally {
|
||||||
|
showUserDeleteModal.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
|
@ -104,7 +104,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {computed, onBeforeMount, ref} from 'vue'
|
import {computed, onBeforeMount, ref} from 'vue'
|
||||||
import {useI18n} from 'vue-i18n'
|
import {useI18n} from 'vue-i18n'
|
||||||
import {useRouter} from 'vue-router'
|
|
||||||
import {useDebounceFn} from '@vueuse/core'
|
import {useDebounceFn} from '@vueuse/core'
|
||||||
|
|
||||||
import Message from '@/components/misc/message.vue'
|
import Message from '@/components/misc/message.vue'
|
||||||
|
@ -112,19 +111,19 @@ import Password from '@/components/input/password.vue'
|
||||||
|
|
||||||
import {getErrorText} from '@/message'
|
import {getErrorText} from '@/message'
|
||||||
import {redirectToProvider} from '@/helpers/redirectToProvider'
|
import {redirectToProvider} from '@/helpers/redirectToProvider'
|
||||||
import {getLastVisited, clearLastVisited} from '@/helpers/saveLastVisited'
|
import {useRedirectToLastVisited} from '@/composables/useRedirectToLastVisited'
|
||||||
|
|
||||||
import {useAuthStore} from '@/stores/auth'
|
import {useAuthStore} from '@/stores/auth'
|
||||||
import {useConfigStore} from '@/stores/config'
|
import {useConfigStore} from '@/stores/config'
|
||||||
|
|
||||||
import {useTitle} from '@/composables/useTitle'
|
import {useTitle} from '@/composables/useTitle'
|
||||||
|
|
||||||
const router = useRouter()
|
|
||||||
const {t} = useI18n({useScope: 'global'})
|
const {t} = useI18n({useScope: 'global'})
|
||||||
useTitle(() => t('user.auth.login'))
|
useTitle(() => t('user.auth.login'))
|
||||||
|
|
||||||
const authStore = useAuthStore()
|
const authStore = useAuthStore()
|
||||||
const configStore = useConfigStore()
|
const configStore = useConfigStore()
|
||||||
|
const {redirectIfSaved} = useRedirectToLastVisited()
|
||||||
|
|
||||||
const registrationEnabled = computed(() => configStore.registrationEnabled)
|
const registrationEnabled = computed(() => configStore.registrationEnabled)
|
||||||
const localAuthEnabled = computed(() => configStore.auth.local.enabled)
|
const localAuthEnabled = computed(() => configStore.auth.local.enabled)
|
||||||
|
@ -151,16 +150,7 @@ onBeforeMount(() => {
|
||||||
|
|
||||||
// Check if the user is already logged in, if so, redirect them to the homepage
|
// Check if the user is already logged in, if so, redirect them to the homepage
|
||||||
if (authenticated.value) {
|
if (authenticated.value) {
|
||||||
const last = getLastVisited()
|
redirectIfSaved()
|
||||||
if (last !== null) {
|
|
||||||
router.push({
|
|
||||||
name: last.name,
|
|
||||||
params: last.params,
|
|
||||||
})
|
|
||||||
clearLastVisited()
|
|
||||||
} else {
|
|
||||||
router.push({name: 'home'})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,9 @@
|
||||||
<message variant="danger" v-if="errorMessage">
|
<message variant="danger" v-if="errorMessage">
|
||||||
{{ errorMessage }}
|
{{ errorMessage }}
|
||||||
</message>
|
</message>
|
||||||
|
<message variant="danger" v-if="errorMessageFromQuery" class="mt-2">
|
||||||
|
{{ errorMessageFromQuery }}
|
||||||
|
</message>
|
||||||
<message v-if="loading">
|
<message v-if="loading">
|
||||||
{{ $t('user.auth.authenticating') }}
|
{{ $t('user.auth.authenticating') }}
|
||||||
</message>
|
</message>
|
||||||
|
@ -15,24 +18,25 @@ export default { name: 'Auth' }
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {ref, computed, onMounted} from 'vue'
|
import {ref, computed, onMounted} from 'vue'
|
||||||
import {useRoute, useRouter} from 'vue-router'
|
import {useRoute} from 'vue-router'
|
||||||
import {useI18n} from 'vue-i18n'
|
import {useI18n} from 'vue-i18n'
|
||||||
|
|
||||||
import {getErrorText} from '@/message'
|
import {getErrorText} from '@/message'
|
||||||
import Message from '@/components/misc/message.vue'
|
import Message from '@/components/misc/message.vue'
|
||||||
import {clearLastVisited, getLastVisited} from '@/helpers/saveLastVisited'
|
import {useRedirectToLastVisited} from '@/composables/useRedirectToLastVisited'
|
||||||
|
|
||||||
import {useAuthStore} from '@/stores/auth'
|
import {useAuthStore} from '@/stores/auth'
|
||||||
|
|
||||||
const {t} = useI18n({useScope: 'global'})
|
const {t} = useI18n({useScope: 'global'})
|
||||||
|
|
||||||
const router = useRouter()
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
const {redirectIfSaved} = useRedirectToLastVisited()
|
||||||
|
|
||||||
const authStore = useAuthStore()
|
const authStore = useAuthStore()
|
||||||
|
|
||||||
const loading = computed(() => authStore.isLoading)
|
const loading = computed(() => authStore.isLoading)
|
||||||
const errorMessage = ref('')
|
const errorMessage = ref('')
|
||||||
|
const errorMessageFromQuery = computed(() => route.query.error)
|
||||||
|
|
||||||
async function authenticateWithCode() {
|
async function authenticateWithCode() {
|
||||||
// This component gets mounted twice: The first time when the actual auth request hits the frontend,
|
// This component gets mounted twice: The first time when the actual auth request hits the frontend,
|
||||||
|
@ -70,16 +74,7 @@ async function authenticateWithCode() {
|
||||||
provider: route.params.provider,
|
provider: route.params.provider,
|
||||||
code: route.query.code,
|
code: route.query.code,
|
||||||
})
|
})
|
||||||
const last = getLastVisited()
|
redirectIfSaved()
|
||||||
if (last !== null) {
|
|
||||||
router.push({
|
|
||||||
name: last.name,
|
|
||||||
params: last.params,
|
|
||||||
})
|
|
||||||
clearLastVisited()
|
|
||||||
} else {
|
|
||||||
router.push({name: 'home'})
|
|
||||||
}
|
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
const err = getErrorText(e)
|
const err = getErrorText(e)
|
||||||
errorMessage.value = typeof err[1] !== 'undefined' ? err[1] : err[0]
|
errorMessage.value = typeof err[1] !== 'undefined' ? err[1] : err[0]
|
||||||
|
|
|
@ -7,41 +7,14 @@
|
||||||
<message variant="success">
|
<message variant="success">
|
||||||
{{ successMessage }}
|
{{ successMessage }}
|
||||||
</message>
|
</message>
|
||||||
<x-button :to="{ name: 'user.login' }">
|
<x-button :to="{ name: 'user.login' }" class="mt-4">
|
||||||
{{ $t('user.auth.login') }}
|
{{ $t('user.auth.login') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
</div>
|
</div>
|
||||||
<form @submit.prevent="submit" id="form" v-if="!successMessage">
|
<form @submit.prevent="submit" id="form" v-if="!successMessage">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label" for="password1">{{ $t('user.auth.password') }}</label>
|
<label class="label" for="password">{{ $t('user.auth.password') }}</label>
|
||||||
<div class="control">
|
<Password @submit="submit" @update:modelValue="v => credentials.password = v"/>
|
||||||
<input
|
|
||||||
class="input"
|
|
||||||
id="password1"
|
|
||||||
name="password1"
|
|
||||||
:placeholder="$t('user.auth.passwordPlaceholder')"
|
|
||||||
required
|
|
||||||
type="password"
|
|
||||||
autocomplete="new-password"
|
|
||||||
v-focus
|
|
||||||
v-model="credentials.password"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="field">
|
|
||||||
<label class="label" for="password2">{{ $t('user.auth.passwordRepeat') }}</label>
|
|
||||||
<div class="control">
|
|
||||||
<input
|
|
||||||
class="input"
|
|
||||||
id="password2"
|
|
||||||
name="password2"
|
|
||||||
:placeholder="$t('user.auth.passwordPlaceholder')"
|
|
||||||
required
|
|
||||||
type="password"
|
|
||||||
autocomplete="new-password"
|
|
||||||
v-model="credentials.password2"
|
|
||||||
@keyup.enter="submit"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="field is-grouped">
|
<div class="field is-grouped">
|
||||||
|
@ -60,17 +33,14 @@
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {ref, reactive} from 'vue'
|
import {ref, reactive} from 'vue'
|
||||||
import {useI18n} from 'vue-i18n'
|
|
||||||
|
|
||||||
import PasswordResetModel from '@/models/passwordReset'
|
import PasswordResetModel from '@/models/passwordReset'
|
||||||
import PasswordResetService from '@/services/passwordReset'
|
import PasswordResetService from '@/services/passwordReset'
|
||||||
import Message from '@/components/misc/message.vue'
|
import Message from '@/components/misc/message.vue'
|
||||||
|
import Password from '@/components/input/password.vue'
|
||||||
const {t} = useI18n({useScope: 'global'})
|
|
||||||
|
|
||||||
const credentials = reactive({
|
const credentials = reactive({
|
||||||
password: '',
|
password: '',
|
||||||
password2: '',
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const passwordResetService = reactive(new PasswordResetService())
|
const passwordResetService = reactive(new PasswordResetService())
|
||||||
|
@ -79,15 +49,14 @@ const successMessage = ref('')
|
||||||
|
|
||||||
async function submit() {
|
async function submit() {
|
||||||
errorMsg.value = ''
|
errorMsg.value = ''
|
||||||
|
|
||||||
if (credentials.password2 !== credentials.password) {
|
if(credentials.password === '') {
|
||||||
errorMsg.value = t('user.auth.passwordsDontMatch')
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const passwordReset = new PasswordResetModel({newPassword: credentials.password})
|
const passwordReset = new PasswordResetModel({newPassword: credentials.password})
|
||||||
try {
|
try {
|
||||||
const {message} = passwordResetService.resetPassword(passwordReset)
|
const {message} = await passwordResetService.resetPassword(passwordReset)
|
||||||
successMessage.value = message
|
successMessage.value = message
|
||||||
localStorage.removeItem('passwordResetToken')
|
localStorage.removeItem('passwordResetToken')
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<message variant="success">
|
<message variant="success">
|
||||||
{{ $t('user.auth.resetPasswordSuccess') }}
|
{{ $t('user.auth.resetPasswordSuccess') }}
|
||||||
</message>
|
</message>
|
||||||
<x-button :to="{ name: 'user.login' }">
|
<x-button :to="{ name: 'user.login' }" class="mt-4">
|
||||||
{{ $t('user.auth.login') }}
|
{{ $t('user.auth.login') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -6,6 +6,8 @@ import legacyFn from '@vitejs/plugin-legacy'
|
||||||
import {VitePWA} from 'vite-plugin-pwa'
|
import {VitePWA} from 'vite-plugin-pwa'
|
||||||
import {visualizer} from 'rollup-plugin-visualizer'
|
import {visualizer} from 'rollup-plugin-visualizer'
|
||||||
import svgLoader from 'vite-svg-loader'
|
import svgLoader from 'vite-svg-loader'
|
||||||
|
import postcssPresetEnv from "postcss-preset-env";
|
||||||
|
|
||||||
import { fileURLToPath, URL } from 'url'
|
import { fileURLToPath, URL } from 'url'
|
||||||
|
|
||||||
const pathSrc = fileURLToPath(new URL('./src', import.meta.url))
|
const pathSrc = fileURLToPath(new URL('./src', import.meta.url))
|
||||||
|
@ -40,6 +42,11 @@ export default defineConfig({
|
||||||
charset: false, // fixes "@charset" must be the first rule in the file" warnings
|
charset: false, // fixes "@charset" must be the first rule in the file" warnings
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
postcss: {
|
||||||
|
plugins: [
|
||||||
|
postcssPresetEnv(),
|
||||||
|
],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
vue({
|
vue({
|
||||||
|
|
Reference in New Issue