forked from vikunja/frontend
Compare commits
19 Commits
52b0a4c6ac
...
b005d023c9
Author | SHA1 | Date | |
---|---|---|---|
|
b005d023c9 | ||
|
92727e1c01 | ||
5da6a6bb39 | |||
34ded051d1 | |||
65be56eb39 | |||
3dbd36eef7 | |||
a9d3446ce3 | |||
e37145cd43 | |||
641ccd1026 | |||
0cd9d43a7c | |||
c92062b6a5 | |||
4a3b4982ab | |||
0f42ed3cf7 | |||
7802cf619f | |||
2a8ecb8a8c | |||
|
15b5ad9d84 | ||
|
714c01403c | ||
|
194b1291e6 | ||
|
422ce6795a |
|
@ -19,4 +19,4 @@ indent_size = 2
|
||||||
|
|
||||||
[*.json]
|
[*.json]
|
||||||
indent_style = space
|
indent_style = space
|
||||||
indent_size = 4
|
indent_size = 2
|
|
@ -3,7 +3,6 @@ import {UserFactory} from '../../factories/user'
|
||||||
import '../../support/authenticateUser'
|
import '../../support/authenticateUser'
|
||||||
import {ListFactory} from '../../factories/list'
|
import {ListFactory} from '../../factories/list'
|
||||||
import {NamespaceFactory} from '../../factories/namespace'
|
import {NamespaceFactory} from '../../factories/namespace'
|
||||||
import {TaskFactory} from '../../factories/task'
|
|
||||||
|
|
||||||
describe('Namepaces', () => {
|
describe('Namepaces', () => {
|
||||||
let namespaces
|
let namespaces
|
||||||
|
@ -99,4 +98,48 @@ describe('Namepaces', () => {
|
||||||
cy.get('.namespace-container .menu.namespaces-lists')
|
cy.get('.namespace-container .menu.namespaces-lists')
|
||||||
.should('not.contain', newNamespaces[0].title)
|
.should('not.contain', newNamespaces[0].title)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('Should not show archived lists & namespaces if the filter is not checked', () => {
|
||||||
|
const n = NamespaceFactory.create(1, {
|
||||||
|
id: 2,
|
||||||
|
is_archived: true,
|
||||||
|
}, false)
|
||||||
|
ListFactory.create(1, {
|
||||||
|
id: 2,
|
||||||
|
namespace_id: n[0].id,
|
||||||
|
}, false)
|
||||||
|
|
||||||
|
ListFactory.create(1, {
|
||||||
|
id: 3,
|
||||||
|
is_archived: true,
|
||||||
|
}, false)
|
||||||
|
|
||||||
|
// Initial
|
||||||
|
cy.visit('/namespaces')
|
||||||
|
cy.get('.namespaces-list .namespace')
|
||||||
|
.should('not.contain', 'Archived')
|
||||||
|
|
||||||
|
// Show archived
|
||||||
|
cy.get('.namespaces-list .fancycheckbox.show-archived-check label.check span')
|
||||||
|
.should('be.visible')
|
||||||
|
.click()
|
||||||
|
cy.get('.namespaces-list .fancycheckbox.show-archived-check input')
|
||||||
|
.should('be.checked')
|
||||||
|
cy.get('.namespaces-list .namespace')
|
||||||
|
.should('contain', 'Archived')
|
||||||
|
|
||||||
|
// Don't show archived
|
||||||
|
cy.get('.namespaces-list .fancycheckbox.show-archived-check label.check span')
|
||||||
|
.should('be.visible')
|
||||||
|
.click()
|
||||||
|
cy.get('.namespaces-list .fancycheckbox.show-archived-check input')
|
||||||
|
.should('not.be.checked')
|
||||||
|
|
||||||
|
// Second time visiting after unchecking
|
||||||
|
cy.visit('/namespaces')
|
||||||
|
cy.get('.namespaces-list .fancycheckbox.show-archived-check input')
|
||||||
|
.should('not.be.checked')
|
||||||
|
cy.get('.namespaces-list .namespace')
|
||||||
|
.should('not.contain', 'Archived')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -21,7 +21,7 @@ export class Factory {
|
||||||
* @param override
|
* @param override
|
||||||
* @returns {[]}
|
* @returns {[]}
|
||||||
*/
|
*/
|
||||||
static create(count = 1, override = {}) {
|
static create(count = 1, override = {}, truncate = true) {
|
||||||
const data = []
|
const data = []
|
||||||
|
|
||||||
for (let i = 1; i <= count; i++) {
|
for (let i = 1; i <= count; i++) {
|
||||||
|
@ -38,7 +38,7 @@ export class Factory {
|
||||||
data.push(entry)
|
data.push(entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
seed(this.table, data)
|
seed(this.table, data, truncate)
|
||||||
|
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,14 +8,14 @@
|
||||||
* @param table
|
* @param table
|
||||||
* @param data
|
* @param data
|
||||||
*/
|
*/
|
||||||
export function seed(table, data = {}) {
|
export function seed(table, data = {}, truncate = true) {
|
||||||
if(data === null) {
|
if (data === null) {
|
||||||
data = []
|
data = []
|
||||||
}
|
}
|
||||||
|
|
||||||
cy.request({
|
cy.request({
|
||||||
method: 'PATCH',
|
method: 'PATCH',
|
||||||
url: `${Cypress.env('API_URL')}/test/${table}`,
|
url: `${Cypress.env('API_URL')}/test/${table}?truncate=${truncate ? 'true' : 'false'}`,
|
||||||
headers: {
|
headers: {
|
||||||
'Authorization': Cypress.env('TEST_SECRET'),
|
'Authorization': Cypress.env('TEST_SECRET'),
|
||||||
},
|
},
|
||||||
|
|
212
package.json
212
package.json
|
@ -1,109 +1,113 @@
|
||||||
{
|
{
|
||||||
"name": "vikunja-frontend",
|
"name": "vikunja-frontend",
|
||||||
"version": "0.10.0",
|
"version": "0.10.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"serve": "vue-cli-service serve",
|
"serve": "vue-cli-service serve",
|
||||||
"serve:dist": "node scripts/serve-dist.js",
|
"serve:dist": "node scripts/serve-dist.js",
|
||||||
"build": "vue-cli-service build --modern",
|
"build": "vue-cli-service build --modern",
|
||||||
"build:report": "vue-cli-service build --report",
|
"build:report": "vue-cli-service build --report",
|
||||||
"lint": "vue-cli-service lint --ignore-pattern '*.test.*'",
|
"lint": "vue-cli-service lint --ignore-pattern '*.test.*'",
|
||||||
"cypress:open": "cypress open",
|
"cypress:open": "cypress open",
|
||||||
"test:unit": "jest",
|
"test:unit": "jest",
|
||||||
"test:frontend": "cypress run"
|
"test:frontend": "cypress run"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"browserslist": "4.16.6",
|
||||||
|
"bulma": "0.9.2",
|
||||||
|
"camel-case": "4.1.2",
|
||||||
|
"copy-to-clipboard": "3.3.1",
|
||||||
|
"date-fns": "2.22.1",
|
||||||
|
"dompurify": "2.2.9",
|
||||||
|
"highlight.js": "11.0.1",
|
||||||
|
"lodash": "4.17.21",
|
||||||
|
"marked": "2.0.7",
|
||||||
|
"register-service-worker": "1.7.2",
|
||||||
|
"sass": "1.34.1",
|
||||||
|
"snake-case": "3.0.4",
|
||||||
|
"verte": "0.0.12",
|
||||||
|
"vue": "2.6.14",
|
||||||
|
"vue-advanced-cropper": "1.6.0",
|
||||||
|
"vue-drag-resize": "1.5.4",
|
||||||
|
"vue-easymde": "1.4.0",
|
||||||
|
"vue-shortkey": "3.1.7",
|
||||||
|
"vue-smooth-dnd": "0.8.1",
|
||||||
|
"vuex": "3.6.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@fortawesome/fontawesome-svg-core": "1.2.35",
|
||||||
|
"@fortawesome/free-regular-svg-icons": "5.15.3",
|
||||||
|
"@fortawesome/free-solid-svg-icons": "5.15.3",
|
||||||
|
"@fortawesome/vue-fontawesome": "2.0.2",
|
||||||
|
"@vue/cli": "4.5.13",
|
||||||
|
"@vue/cli-plugin-babel": "4.5.13",
|
||||||
|
"@vue/cli-plugin-eslint": "4.5.13",
|
||||||
|
"@vue/cli-plugin-pwa": "4.5.13",
|
||||||
|
"@vue/cli-service": "4.5.13",
|
||||||
|
"axios": "0.21.1",
|
||||||
|
"babel-eslint": "10.1.0",
|
||||||
|
"cypress": "7.4.0",
|
||||||
|
"cypress-file-upload": "5.0.7",
|
||||||
|
"eslint": "7.28.0",
|
||||||
|
"eslint-plugin-vue": "7.10.0",
|
||||||
|
"faker": "5.5.3",
|
||||||
|
"jest": "27.0.4",
|
||||||
|
"sass-loader": "10.2.0",
|
||||||
|
"vue-flatpickr-component": "8.1.6",
|
||||||
|
"vue-notification": "1.3.20",
|
||||||
|
"vue-router": "3.5.1",
|
||||||
|
"vue-template-compiler": "2.6.14",
|
||||||
|
"wait-on": "5.3.0"
|
||||||
|
},
|
||||||
|
"eslintConfig": {
|
||||||
|
"root": true,
|
||||||
|
"env": {
|
||||||
|
"node": true
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"extends": [
|
||||||
"browserslist": "4.16.6",
|
"plugin:vue/essential",
|
||||||
"bulma": "0.9.2",
|
"eslint:recommended"
|
||||||
"camel-case": "4.1.2",
|
|
||||||
"copy-to-clipboard": "3.3.1",
|
|
||||||
"date-fns": "2.22.1",
|
|
||||||
"dompurify": "2.2.9",
|
|
||||||
"highlight.js": "11.0.0",
|
|
||||||
"lodash": "4.17.21",
|
|
||||||
"marked": "2.0.7",
|
|
||||||
"register-service-worker": "1.7.2",
|
|
||||||
"sass": "1.34.0",
|
|
||||||
"snake-case": "3.0.4",
|
|
||||||
"verte": "0.0.12",
|
|
||||||
"vue": "2.6.13",
|
|
||||||
"vue-advanced-cropper": "1.6.0",
|
|
||||||
"vue-drag-resize": "1.5.4",
|
|
||||||
"vue-easymde": "1.4.0",
|
|
||||||
"vue-shortkey": "3.1.7",
|
|
||||||
"vue-smooth-dnd": "0.8.1",
|
|
||||||
"vuex": "3.6.2"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@fortawesome/fontawesome-svg-core": "1.2.35",
|
|
||||||
"@fortawesome/free-regular-svg-icons": "5.15.3",
|
|
||||||
"@fortawesome/free-solid-svg-icons": "5.15.3",
|
|
||||||
"@fortawesome/vue-fontawesome": "2.0.2",
|
|
||||||
"@vue/cli": "4.5.13",
|
|
||||||
"@vue/cli-plugin-babel": "4.5.13",
|
|
||||||
"@vue/cli-plugin-eslint": "4.5.13",
|
|
||||||
"@vue/cli-plugin-pwa": "4.5.13",
|
|
||||||
"@vue/cli-service": "4.5.13",
|
|
||||||
"axios": "0.21.1",
|
|
||||||
"babel-eslint": "10.1.0",
|
|
||||||
"cypress": "7.4.0",
|
|
||||||
"cypress-file-upload": "5.0.7",
|
|
||||||
"eslint": "7.27.0",
|
|
||||||
"eslint-plugin-vue": "7.10.0",
|
|
||||||
"faker": "5.5.3",
|
|
||||||
"jest": "27.0.3",
|
|
||||||
"sass-loader": "10.2.0",
|
|
||||||
"vue-flatpickr-component": "8.1.6",
|
|
||||||
"vue-notification": "1.3.20",
|
|
||||||
"vue-router": "3.5.1",
|
|
||||||
"vue-template-compiler": "2.6.13",
|
|
||||||
"wait-on": "5.3.0"
|
|
||||||
},
|
|
||||||
"eslintConfig": {
|
|
||||||
"root": true,
|
|
||||||
"env": {
|
|
||||||
"node": true
|
|
||||||
},
|
|
||||||
"extends": [
|
|
||||||
"plugin:vue/essential",
|
|
||||||
"eslint:recommended"
|
|
||||||
],
|
|
||||||
"rules": {
|
|
||||||
"vue/html-quotes": [
|
|
||||||
"error",
|
|
||||||
"double"
|
|
||||||
],
|
|
||||||
"quotes": [
|
|
||||||
"error",
|
|
||||||
"single"
|
|
||||||
],
|
|
||||||
"comma-dangle": [
|
|
||||||
"error",
|
|
||||||
"always-multiline"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"parserOptions": {
|
|
||||||
"parser": "babel-eslint"
|
|
||||||
},
|
|
||||||
"ignorePatterns": [
|
|
||||||
"*.test.js",
|
|
||||||
"cypress/*"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"postcss": {
|
|
||||||
"plugins": {
|
|
||||||
"autoprefixer": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"browserslist": [
|
|
||||||
"> 1%",
|
|
||||||
"last 2 versions",
|
|
||||||
"not ie < 11"
|
|
||||||
],
|
],
|
||||||
"license": "AGPL-3.0-or-later",
|
"rules": {
|
||||||
"jest": {
|
"vue/html-quotes": [
|
||||||
"testPathIgnorePatterns": [
|
"error",
|
||||||
"cypress"
|
"double"
|
||||||
]
|
],
|
||||||
|
"quotes": [
|
||||||
|
"error",
|
||||||
|
"single"
|
||||||
|
],
|
||||||
|
"comma-dangle": [
|
||||||
|
"error",
|
||||||
|
"always-multiline"
|
||||||
|
],
|
||||||
|
"semi": [
|
||||||
|
"error",
|
||||||
|
"never"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"parserOptions": {
|
||||||
|
"parser": "babel-eslint"
|
||||||
|
},
|
||||||
|
"ignorePatterns": [
|
||||||
|
"*.test.js",
|
||||||
|
"cypress/*"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"postcss": {
|
||||||
|
"plugins": {
|
||||||
|
"autoprefixer": {}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"browserslist": [
|
||||||
|
"> 1%",
|
||||||
|
"last 2 versions",
|
||||||
|
"not ie < 11"
|
||||||
|
],
|
||||||
|
"license": "AGPL-3.0-or-later",
|
||||||
|
"jest": {
|
||||||
|
"testPathIgnorePatterns": [
|
||||||
|
"cypress"
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -55,6 +55,7 @@ export default {
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.renewTokenOnFocus()
|
this.renewTokenOnFocus()
|
||||||
|
this.loadLabels()
|
||||||
},
|
},
|
||||||
computed: mapState({
|
computed: mapState({
|
||||||
namespaces(state) {
|
namespaces(state) {
|
||||||
|
@ -126,6 +127,12 @@ export default {
|
||||||
showKeyboardShortcuts() {
|
showKeyboardShortcuts() {
|
||||||
this.$store.commit(KEYBOARD_SHORTCUTS_ACTIVE, true)
|
this.$store.commit(KEYBOARD_SHORTCUTS_ACTIVE, true)
|
||||||
},
|
},
|
||||||
|
loadLabels() {
|
||||||
|
this.$store.dispatch('labels/loadAllLabels')
|
||||||
|
.catch(e => {
|
||||||
|
this.error(e, this)
|
||||||
|
})
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -118,6 +118,7 @@ import {calculateDayInterval} from '@/helpers/time/calculateDayInterval'
|
||||||
import {calculateNearestHours} from '@/helpers/time/calculateNearestHours'
|
import {calculateNearestHours} from '@/helpers/time/calculateNearestHours'
|
||||||
import {closeWhenClickedOutside} from '@/helpers/closeWhenClickedOutside'
|
import {closeWhenClickedOutside} from '@/helpers/closeWhenClickedOutside'
|
||||||
import {createDateFromString} from '@/helpers/time/createDateFromString'
|
import {createDateFromString} from '@/helpers/time/createDateFromString'
|
||||||
|
import {mapState} from 'vuex'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'datepicker',
|
name: 'datepicker',
|
||||||
|
@ -127,14 +128,6 @@ export default {
|
||||||
show: false,
|
show: false,
|
||||||
changed: false,
|
changed: false,
|
||||||
|
|
||||||
flatPickerConfig: {
|
|
||||||
altFormat: 'j M Y H:i',
|
|
||||||
altInput: true,
|
|
||||||
dateFormat: 'Y-m-d H:i',
|
|
||||||
enableTime: true,
|
|
||||||
time_24hr: true,
|
|
||||||
inline: true,
|
|
||||||
},
|
|
||||||
// Since flatpickr dates are strings, we need to convert them to native date objects.
|
// Since flatpickr dates are strings, we need to convert them to native date objects.
|
||||||
// To make that work, we need a separate variable since flatpickr does not have a change event.
|
// To make that work, we need a separate variable since flatpickr does not have a change event.
|
||||||
flatPickrDate: null,
|
flatPickrDate: null,
|
||||||
|
@ -172,6 +165,19 @@ export default {
|
||||||
this.updateData()
|
this.updateData()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
computed: mapState({
|
||||||
|
flatPickerConfig: state => ({
|
||||||
|
altFormat: 'j M Y H:i',
|
||||||
|
altInput: true,
|
||||||
|
dateFormat: 'Y-m-d H:i',
|
||||||
|
enableTime: true,
|
||||||
|
time_24hr: true,
|
||||||
|
inline: true,
|
||||||
|
locale: {
|
||||||
|
firstDayOfWeek: state.auth.settings.weekStart,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}),
|
||||||
methods: {
|
methods: {
|
||||||
setDateValue(newVal) {
|
setDateValue(newVal) {
|
||||||
if(newVal === null) {
|
if(newVal === null) {
|
||||||
|
|
|
@ -34,11 +34,13 @@
|
||||||
|
|
||||||
<p class="has-text-centered has-text-grey is-italic" v-if="isPreviewActive && text === '' && emptyText !== ''">
|
<p class="has-text-centered has-text-grey is-italic" v-if="isPreviewActive && text === '' && emptyText !== ''">
|
||||||
{{ emptyText }}
|
{{ emptyText }}
|
||||||
<a @click="toggleEdit">Edit</a>.
|
<template v-if="isEditEnabled">
|
||||||
|
<a @click="toggleEdit">Edit</a>.
|
||||||
|
</template>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<ul class="actions">
|
<ul class="actions">
|
||||||
<template v-if="hasEditBottom">
|
<template v-if="hasEditBottom && isEditEnabled">
|
||||||
<li>
|
<li>
|
||||||
<a v-if="!isEditActive" @click="toggleEdit">Edit</a>
|
<a v-if="!isEditActive" @click="toggleEdit">Edit</a>
|
||||||
<a v-else @click="toggleEdit">Done</a>
|
<a v-else @click="toggleEdit">Done</a>
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
@keyup="search"
|
@keyup="search"
|
||||||
@keyup.enter.exact.prevent="() => createOrSelectOnEnter()"
|
@keyup.enter.exact.prevent="() => createOrSelectOnEnter()"
|
||||||
:placeholder="placeholder"
|
:placeholder="placeholder"
|
||||||
@keydown.down.exact.prevent="() => preSelect(0, true)"
|
@keydown.down.exact.prevent="() => preSelect(0)"
|
||||||
ref="searchInput"
|
ref="searchInput"
|
||||||
@focus="() => showSearchResults = true"
|
@focus="() => showSearchResults = true"
|
||||||
/>
|
/>
|
||||||
|
@ -35,27 +35,6 @@
|
||||||
|
|
||||||
<transition name="fade">
|
<transition name="fade">
|
||||||
<div class="search-results" :class="{'search-results-inline': inline}" v-if="searchResultsVisible">
|
<div class="search-results" :class="{'search-results-inline': inline}" v-if="searchResultsVisible">
|
||||||
<button
|
|
||||||
v-if="creatableAvailable"
|
|
||||||
class="is-fullwidth"
|
|
||||||
ref="result--1"
|
|
||||||
@keydown.up.prevent="() => preSelect(-2)"
|
|
||||||
@keydown.down.prevent="() => preSelect(0)"
|
|
||||||
@keyup.enter.prevent="create"
|
|
||||||
@click.prevent.stop="create"
|
|
||||||
>
|
|
||||||
<span>
|
|
||||||
<slot name="searchResult" :option="query">
|
|
||||||
<span class="search-result">
|
|
||||||
{{ query }}
|
|
||||||
</span>
|
|
||||||
</slot>
|
|
||||||
</span>
|
|
||||||
<span class="hint-text">
|
|
||||||
{{ createPlaceholder }}
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
<button
|
||||||
class="is-fullwidth"
|
class="is-fullwidth"
|
||||||
v-for="(data, key) in filteredSearchResults"
|
v-for="(data, key) in filteredSearchResults"
|
||||||
|
@ -74,6 +53,27 @@
|
||||||
{{ selectPlaceholder }}
|
{{ selectPlaceholder }}
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
v-if="creatableAvailable"
|
||||||
|
class="is-fullwidth"
|
||||||
|
:ref="`result-${filteredSearchResults.length}`"
|
||||||
|
@keydown.up.prevent="() => preSelect(filteredSearchResults.length - 1)"
|
||||||
|
@keydown.down.prevent="() => preSelect(filteredSearchResults.length + 1)"
|
||||||
|
@keyup.enter.prevent="create"
|
||||||
|
@click.prevent.stop="create"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
<slot name="searchResult" :option="query">
|
||||||
|
<span class="search-result">
|
||||||
|
{{ query }}
|
||||||
|
</span>
|
||||||
|
</slot>
|
||||||
|
</span>
|
||||||
|
<span class="hint-text">
|
||||||
|
{{ createPlaceholder }}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
|
|
||||||
|
@ -202,14 +202,14 @@ export default {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
searchResultsVisible() {
|
searchResultsVisible() {
|
||||||
if(this.query === '' && !this.showEmpty) {
|
if (this.query === '' && !this.showEmpty) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.showSearchResults && (
|
return this.showSearchResults && (
|
||||||
(this.filteredSearchResults.length > 0) ||
|
(this.filteredSearchResults.length > 0) ||
|
||||||
(this.creatable && this.query !== '')
|
(this.creatable && this.query !== '')
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
creatableAvailable() {
|
creatableAvailable() {
|
||||||
return this.creatable && this.query !== '' && !this.filteredSearchResults.some(elem => {
|
return this.creatable && this.query !== '' && !this.filteredSearchResults.some(elem => {
|
||||||
|
@ -295,13 +295,8 @@ export default {
|
||||||
|
|
||||||
this.query = this.label !== '' ? object[this.label] : object
|
this.query = this.label !== '' ? object[this.label] : object
|
||||||
},
|
},
|
||||||
preSelect(index, lookForCreatable = false) {
|
preSelect(index) {
|
||||||
|
if (index < 0) {
|
||||||
if (index === 0 && this.creatable && lookForCreatable) {
|
|
||||||
index = -1
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index < -1) {
|
|
||||||
this.$refs.searchInput.focus()
|
this.$refs.searchInput.focus()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,7 +131,6 @@
|
||||||
<label class="label">Labels</label>
|
<label class="label">Labels</label>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<multiselect
|
<multiselect
|
||||||
:loading="labelService.loading"
|
|
||||||
placeholder="Type to search for a label..."
|
placeholder="Type to search for a label..."
|
||||||
@search="findLabels"
|
@search="findLabels"
|
||||||
:search-results="foundLabels"
|
:search-results="foundLabels"
|
||||||
|
@ -202,9 +201,9 @@ import PercentDoneSelect from '@/components/tasks/partials/percentDoneSelect'
|
||||||
import Multiselect from '@/components/input/multiselect'
|
import Multiselect from '@/components/input/multiselect'
|
||||||
|
|
||||||
import UserService from '@/services/user'
|
import UserService from '@/services/user'
|
||||||
import LabelService from '@/services/label'
|
|
||||||
import ListService from '@/services/list'
|
import ListService from '@/services/list'
|
||||||
import NamespaceService from '@/services/namespace'
|
import NamespaceService from '@/services/namespace'
|
||||||
|
import {mapState} from 'vuex'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'filters',
|
name: 'filters',
|
||||||
|
@ -243,21 +242,12 @@ export default {
|
||||||
list_id: '',
|
list_id: '',
|
||||||
namespace: '',
|
namespace: '',
|
||||||
},
|
},
|
||||||
flatPickerConfig: {
|
|
||||||
altFormat: 'j M Y H:i',
|
|
||||||
altInput: true,
|
|
||||||
dateFormat: 'Y-m-d H:i',
|
|
||||||
enableTime: true,
|
|
||||||
time_24hr: true,
|
|
||||||
mode: 'range',
|
|
||||||
},
|
|
||||||
|
|
||||||
usersService: UserService,
|
usersService: UserService,
|
||||||
foundusers: [],
|
foundusers: [],
|
||||||
users: [],
|
users: [],
|
||||||
|
|
||||||
labelService: LabelService,
|
labelQuery: '',
|
||||||
foundLabels: [],
|
|
||||||
labels: [],
|
labels: [],
|
||||||
|
|
||||||
listsService: ListService,
|
listsService: ListService,
|
||||||
|
@ -271,7 +261,6 @@ export default {
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.usersService = new UserService()
|
this.usersService = new UserService()
|
||||||
this.labelService = new LabelService()
|
|
||||||
this.listsService = new ListService()
|
this.listsService = new ListService()
|
||||||
this.namespaceService = new NamespaceService()
|
this.namespaceService = new NamespaceService()
|
||||||
},
|
},
|
||||||
|
@ -291,6 +280,30 @@ export default {
|
||||||
this.prepareFilters()
|
this.prepareFilters()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
foundLabels() {
|
||||||
|
const labels = (Object.values(this.$store.state.labels.labels).filter(l => {
|
||||||
|
return l.title.toLowerCase().includes(this.labelQuery.toLowerCase())
|
||||||
|
}) ?? [])
|
||||||
|
|
||||||
|
return differenceWith(labels, this.labels, (first, second) => {
|
||||||
|
return first.id === second.id
|
||||||
|
})
|
||||||
|
},
|
||||||
|
...mapState({
|
||||||
|
flatPickerConfig: state => ({
|
||||||
|
altFormat: 'j M Y H:i',
|
||||||
|
altInput: true,
|
||||||
|
dateFormat: 'Y-m-d H:i',
|
||||||
|
enableTime: true,
|
||||||
|
time_24hr: true,
|
||||||
|
mode: 'range',
|
||||||
|
locale: {
|
||||||
|
firstDayOfWeek: state.auth.settings.weekStart,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
change() {
|
change() {
|
||||||
this.$emit('input', this.params)
|
this.$emit('input', this.params)
|
||||||
|
@ -560,25 +573,8 @@ export default {
|
||||||
this.$set(this.filters, filterName, ids.join(','))
|
this.$set(this.filters, filterName, ids.join(','))
|
||||||
this.setSingleValueFilter(filterName, filterName, '', 'in')
|
this.setSingleValueFilter(filterName, filterName, '', 'in')
|
||||||
},
|
},
|
||||||
clearLabels() {
|
|
||||||
this.$set(this, 'foundLabels', [])
|
|
||||||
},
|
|
||||||
findLabels(query) {
|
findLabels(query) {
|
||||||
|
this.labelQuery = query
|
||||||
if (query === '') {
|
|
||||||
this.clearLabels()
|
|
||||||
}
|
|
||||||
|
|
||||||
this.labelService.getAll({}, {s: query})
|
|
||||||
.then(response => {
|
|
||||||
// Filter the results to not include labels already selected
|
|
||||||
this.$set(this, 'foundLabels', differenceWith(response, this.labels, (first, second) => {
|
|
||||||
return first.id === second.id
|
|
||||||
}))
|
|
||||||
})
|
|
||||||
.catch(e => {
|
|
||||||
this.error(e, this)
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
addLabel() {
|
addLabel() {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="has-text-grey-light p-4" v-if="hintText !== ''">
|
<div class="help has-text-grey-light p-2" v-if="hintText !== ''">
|
||||||
{{ hintText }}
|
{{ hintText }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -72,6 +72,11 @@ const CMD_NEW_LIST = 'newList'
|
||||||
const CMD_NEW_NAMESPACE = 'newNamespace'
|
const CMD_NEW_NAMESPACE = 'newNamespace'
|
||||||
const CMD_NEW_TEAM = 'newTeam'
|
const CMD_NEW_TEAM = 'newTeam'
|
||||||
|
|
||||||
|
const SEARCH_MODE_ALL = 'all'
|
||||||
|
const SEARCH_MODE_TASKS = 'tasks'
|
||||||
|
const SEARCH_MODE_LISTS = 'lists'
|
||||||
|
const SEARCH_MODE_TEAMS = 'teams'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'quick-actions',
|
name: 'quick-actions',
|
||||||
data() {
|
data() {
|
||||||
|
@ -84,6 +89,7 @@ export default {
|
||||||
taskService: null,
|
taskService: null,
|
||||||
|
|
||||||
foundTeams: [],
|
foundTeams: [],
|
||||||
|
teamSearchTimeout: null,
|
||||||
teamService: null,
|
teamService: null,
|
||||||
|
|
||||||
namespaceService: null,
|
namespaceService: null,
|
||||||
|
@ -99,9 +105,17 @@ export default {
|
||||||
return active
|
return active
|
||||||
},
|
},
|
||||||
results() {
|
results() {
|
||||||
const lists = (Object.values(this.$store.state.lists).filter(l => {
|
let lists = []
|
||||||
return l.title.toLowerCase().includes(this.query.toLowerCase())
|
if (this.searchMode === SEARCH_MODE_ALL || this.searchMode === SEARCH_MODE_LISTS) {
|
||||||
}) ?? [])
|
let query = this.query
|
||||||
|
if (this.searchMode === SEARCH_MODE_LISTS) {
|
||||||
|
query = query.substr(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
lists = (Object.values(this.$store.state.lists).filter(l => {
|
||||||
|
return l.title.toLowerCase().includes(query.toLowerCase())
|
||||||
|
}) ?? [])
|
||||||
|
}
|
||||||
|
|
||||||
const cmds = this.availableCmds
|
const cmds = this.availableCmds
|
||||||
.filter(a => a.title.toLowerCase().includes(this.query.toLowerCase()))
|
.filter(a => a.title.toLowerCase().includes(this.query.toLowerCase()))
|
||||||
|
@ -167,7 +181,7 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ''
|
return 'You can use # to only seach for tasks, * to only search for lists and @ to only search for teams.'
|
||||||
},
|
},
|
||||||
currentList() {
|
currentList() {
|
||||||
return Object.keys(this.$store.state[CURRENT_LIST]).length === 0 ? null : this.$store.state[CURRENT_LIST]
|
return Object.keys(this.$store.state[CURRENT_LIST]).length === 0 ? null : this.$store.state[CURRENT_LIST]
|
||||||
|
@ -196,6 +210,23 @@ export default {
|
||||||
|
|
||||||
return cmds
|
return cmds
|
||||||
},
|
},
|
||||||
|
searchMode() {
|
||||||
|
if (this.query === '') {
|
||||||
|
return SEARCH_MODE_ALL
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.query.startsWith('#')) {
|
||||||
|
return SEARCH_MODE_TASKS
|
||||||
|
}
|
||||||
|
if (this.query.startsWith('*')) {
|
||||||
|
return SEARCH_MODE_LISTS
|
||||||
|
}
|
||||||
|
if (this.query.startsWith('@')) {
|
||||||
|
return SEARCH_MODE_TEAMS
|
||||||
|
}
|
||||||
|
|
||||||
|
return SEARCH_MODE_ALL
|
||||||
|
},
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.taskService = new TaskService()
|
this.taskService = new TaskService()
|
||||||
|
@ -206,9 +237,20 @@ export default {
|
||||||
methods: {
|
methods: {
|
||||||
search() {
|
search() {
|
||||||
this.searchTasks()
|
this.searchTasks()
|
||||||
|
this.searchTeams()
|
||||||
},
|
},
|
||||||
searchTasks() {
|
searchTasks() {
|
||||||
if (this.query === '' || this.selectedCmd !== null) {
|
if (this.searchMode !== SEARCH_MODE_ALL && this.searchMode !== SEARCH_MODE_TASKS) {
|
||||||
|
this.foundTasks = []
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let query = this.query
|
||||||
|
if (this.searchMode === SEARCH_MODE_TASKS) {
|
||||||
|
query = query.substr(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (query === '' || this.selectedCmd !== null) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,7 +260,7 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.taskSearchTimeout = setTimeout(() => {
|
this.taskSearchTimeout = setTimeout(() => {
|
||||||
this.taskService.getAll({}, {s: this.query})
|
this.taskService.getAll({}, {s: query})
|
||||||
.then(r => {
|
.then(r => {
|
||||||
r = r.map(t => {
|
r = r.map(t => {
|
||||||
t.type = TYPE_TASK
|
t.type = TYPE_TASK
|
||||||
|
@ -233,6 +275,37 @@ export default {
|
||||||
})
|
})
|
||||||
}, 150)
|
}, 150)
|
||||||
},
|
},
|
||||||
|
searchTeams() {
|
||||||
|
if (this.searchMode !== SEARCH_MODE_ALL && this.searchMode !== SEARCH_MODE_TEAMS) {
|
||||||
|
this.foundTeams = []
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let query = this.query
|
||||||
|
if (this.searchMode === SEARCH_MODE_TEAMS) {
|
||||||
|
query = query.substr(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (query === '' || this.selectedCmd !== null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.teamSearchTimeout !== null) {
|
||||||
|
clearTimeout(this.teamSearchTimeout)
|
||||||
|
this.teamSearchTimeout = null
|
||||||
|
}
|
||||||
|
|
||||||
|
this.teamSearchTimeout = setTimeout(() => {
|
||||||
|
this.teamService.getAll({}, {s: query})
|
||||||
|
.then(r => {
|
||||||
|
r = r.map(t => {
|
||||||
|
t.title = t.name
|
||||||
|
return t
|
||||||
|
})
|
||||||
|
this.$set(this, 'foundTeams', r)
|
||||||
|
})
|
||||||
|
}, 150)
|
||||||
|
},
|
||||||
closeQuickActions() {
|
closeQuickActions() {
|
||||||
this.$store.commit(QUICK_ACTIONS_ACTIVE, false)
|
this.$store.commit(QUICK_ACTIONS_ACTIVE, false)
|
||||||
},
|
},
|
||||||
|
@ -321,7 +394,6 @@ export default {
|
||||||
.then(r => {
|
.then(r => {
|
||||||
this.$store.commit('namespaces/addNamespace', r)
|
this.$store.commit('namespaces/addNamespace', r)
|
||||||
this.success({message: 'The namespace was successfully created.'}, this)
|
this.success({message: 'The namespace was successfully created.'}, this)
|
||||||
this.$router.back()
|
|
||||||
this.closeQuickActions()
|
this.closeQuickActions()
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
|
|
|
@ -27,21 +27,24 @@
|
||||||
Add
|
Add
|
||||||
</x-button>
|
</x-button>
|
||||||
</p>
|
</p>
|
||||||
|
<p class="help is-warning" v-if="!validListIdAvailable">
|
||||||
|
No default list set. Please go to settings and specify default list.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import LabelTask from '../../models/labelTask';
|
import LabelTask from '../../models/labelTask'
|
||||||
import LabelModel from '../../models/label';
|
import LabelModel from '../../models/label'
|
||||||
|
|
||||||
import { HAS_TASKS } from '@/store/mutation-types';
|
import { HAS_TASKS } from '@/store/mutation-types'
|
||||||
// import Nothing from "@/components/misc/nothing";
|
// import Nothing from "@/components/misc/nothing";
|
||||||
|
|
||||||
import ListService from '../../services/list';
|
import ListService from '../../services/list'
|
||||||
import TaskService from '../../services/task';
|
import TaskService from '../../services/task'
|
||||||
import TaskModel from '../../models/task';
|
import TaskModel from '../../models/task'
|
||||||
import LabelService from '../../services/label';
|
import LabelService from '../../services/label'
|
||||||
import LabelTaskService from '../../services/labelTask';
|
import LabelTaskService from '../../services/labelTask'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'add-task',
|
name: 'add-task',
|
||||||
|
@ -54,7 +57,7 @@ export default {
|
||||||
labelTaskService: LabelTaskService,
|
labelTaskService: LabelTaskService,
|
||||||
listIdForNewTask: undefined,
|
listIdForNewTask: undefined,
|
||||||
validListIdAvailable: false,
|
validListIdAvailable: false,
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
components: {},
|
components: {},
|
||||||
props: {
|
props: {
|
||||||
|
@ -64,151 +67,178 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.listService = new ListService();
|
this.listService = new ListService()
|
||||||
this.taskService = new TaskService();
|
this.taskService = new TaskService()
|
||||||
this.labelService = new LabelService();
|
this.labelService = new LabelService()
|
||||||
this.labelTaskService = new LabelTaskService();
|
this.labelTaskService = new LabelTaskService()
|
||||||
},
|
},
|
||||||
beforeMount() {
|
beforeMount() {
|
||||||
console.log(this.listId);
|
console.log(this.listId)
|
||||||
if (this.listId !== undefined) {
|
if (this.listId !== undefined) {
|
||||||
this.listIdForNewTask = this.listId;
|
this.listIdForNewTask = this.listId
|
||||||
this.validListIdAvailable = true;
|
this.validListIdAvailable = true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
addTask() {
|
addTask() {
|
||||||
if (this.newTaskText === '') {
|
if (this.newTaskText === '') {
|
||||||
this.showError = true;
|
this.showError = true
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
this.showError = false;
|
this.showError = false
|
||||||
|
|
||||||
const task = new TaskModel({
|
const task = new TaskModel({
|
||||||
title: this.newTaskText,
|
title: this.newTaskText,
|
||||||
listId: this.listIdForNewTask,
|
listId: this.listIdForNewTask,
|
||||||
});
|
})
|
||||||
|
|
||||||
this.taskService
|
this.taskService
|
||||||
.create(task)
|
.create(task)
|
||||||
.then(task => {
|
.then(task => {
|
||||||
this.newTaskText = '';
|
this.newTaskText = ''
|
||||||
|
|
||||||
|
// Unlike a proper programming language, Javascript only knows references to objects and does not
|
||||||
|
// allow you to control what is a reference and what isnt. Because of this we can't just add
|
||||||
|
// all labels to the task they belong to right after we found and added them to the task since
|
||||||
|
// the task update method also ensures all data the api sees has the right format. That means
|
||||||
|
// it processes labels. That processing changes the date format and the label color and makes
|
||||||
|
// the label pretty much unusable for everything else. Normally, this is not a big deal, because
|
||||||
|
// the labels on a task get thrown away anyway and replaced with the new models from the api
|
||||||
|
// when we get the updated answer back. However, in this specific case because we're passing a
|
||||||
|
// label we obtained from vuex that reference is kept and not thrown away. The task itself gets
|
||||||
|
// a new label object - you won't notice the bad reference until you want to add the same label
|
||||||
|
// again and notice it doesn't have a color anymore.
|
||||||
|
// I think this is what happens: (or rather would happen without the hack I've put in)
|
||||||
|
// 1. Query the store for a label which matches the name
|
||||||
|
// 2. Find one - remember, we get only a *reference* to the label from the store, not a new label object.
|
||||||
|
// (Now there's *two* places with a reference to the same label object: in the store and in the
|
||||||
|
// variable which holds the label from the search in the store)
|
||||||
|
// 3. .push the label to the task
|
||||||
|
// 4. Update the task to remove the labels from the name
|
||||||
|
// 4.1. The task update processes all labels belonging to that task, changing attributes of our
|
||||||
|
// label in the process. Because this is a reference, it is also "updated" in the store.
|
||||||
|
// 5. Get an api response back. The service handler now creates a new label object for all labels
|
||||||
|
// returned from the api. It will throw away all references to the old label in the process.
|
||||||
|
// 6. Now we have two objects with the same label data: The old one we originally obtained from
|
||||||
|
// the store and the one that was created when parsing the api response. The old one was
|
||||||
|
// modified before sending the api request and thus, our store which still holds a reference
|
||||||
|
// to the old label now contains old data.
|
||||||
|
// I guess this is the point where normally the GC would come in and collect the old label
|
||||||
|
// object if the store wouldn't still hold a reference to it.
|
||||||
|
//
|
||||||
|
// Now, as a workaround, I'm putting all new labels added to that task in this separate variable to
|
||||||
|
// add them only after the task was updated to circumvent the task update service processing the
|
||||||
|
// label before sending it. Feels more hacky than it probably is.
|
||||||
|
const newLabels = []
|
||||||
|
|
||||||
// Check if the task has words starting with ~ in the title and make them to labels
|
// Check if the task has words starting with ~ in the title and make them to labels
|
||||||
const parts = task.title.split(' ~');
|
const parts = task.title.split(' ~')
|
||||||
// The first element will always contain the title, even if there is no occurrence of ~
|
// The first element will always contain the title, even if there is no occurrence of ~
|
||||||
if (parts.length > 1) {
|
if (parts.length > 1) {
|
||||||
// First, create an unresolved promise for each entry in the array to wait
|
// First, create an unresolved promise for each entry in the array to wait
|
||||||
// until all labels are added to update the task title once again
|
// until all labels are added to update the task title once again
|
||||||
let labelAddings = [];
|
let labelAddings = []
|
||||||
let labelAddsToWaitFor = [];
|
let labelAddsToWaitFor = []
|
||||||
parts.forEach((p, index) => {
|
parts.forEach((p, index) => {
|
||||||
if (index < 1) {
|
if (index < 1) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
labelAddsToWaitFor.push(
|
labelAddsToWaitFor.push(
|
||||||
new Promise((resolve, reject) => {
|
new Promise((resolve, reject) => {
|
||||||
labelAddings.push({ resolve: resolve, reject: reject });
|
labelAddings.push({ resolve: resolve, reject: reject })
|
||||||
}),
|
}),
|
||||||
);
|
)
|
||||||
});
|
})
|
||||||
|
|
||||||
// Then do everything that is involved in finding, creating and adding the label to the task
|
// Then do everything that is involved in finding, creating and adding the label to the task
|
||||||
parts.forEach((p, index) => {
|
parts.forEach((p, index) => {
|
||||||
if (index < 1) {
|
if (index < 1) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// The part up until the next space
|
// The part up until the next space
|
||||||
const labelTitle = p.split(' ')[0];
|
const labelTitle = p.split(' ')[0]
|
||||||
|
|
||||||
// Don't create an empty label
|
// Don't create an empty label
|
||||||
if (labelTitle === '') {
|
if (labelTitle === '') {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the label exists
|
// Check if the label exists
|
||||||
this.labelService
|
const label = Object.values(this.$store.state.labels.labels).find(l => {
|
||||||
.getAll({}, { s: labelTitle })
|
return l.title.toLowerCase() === labelTitle.toLowerCase()
|
||||||
.then(res => {
|
})
|
||||||
// Label found, use it
|
|
||||||
if (res.length > 0 && res[0].title === labelTitle) {
|
// Label found, use it
|
||||||
|
if (typeof label !== 'undefined') {
|
||||||
|
const labelTask = new LabelTask({
|
||||||
|
taskId: task.id,
|
||||||
|
labelId: label.id,
|
||||||
|
})
|
||||||
|
this.labelTaskService.create(labelTask)
|
||||||
|
.then(result => {
|
||||||
|
newLabels.push(label)
|
||||||
|
|
||||||
|
// Remove the label text from the task title
|
||||||
|
task.title = task.title.replace(` ~${labelTitle}`, '')
|
||||||
|
|
||||||
|
// Make the promise done (the one with the index 0 does not exist)
|
||||||
|
labelAddings[index - 1].resolve(result)
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
this.error(e, this)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// label not found, create it
|
||||||
|
const label = new LabelModel({title: labelTitle})
|
||||||
|
this.$store.dispatch('labels/createLabel', label)
|
||||||
|
.then(res => {
|
||||||
const labelTask = new LabelTask({
|
const labelTask = new LabelTask({
|
||||||
taskId: task.id,
|
taskId: task.id,
|
||||||
labelId: res[0].id,
|
labelId: res.id,
|
||||||
});
|
})
|
||||||
this.labelTaskService
|
this.labelTaskService.create(labelTask)
|
||||||
.create(labelTask)
|
|
||||||
.then(result => {
|
.then(result => {
|
||||||
task.labels.push(res[0]);
|
newLabels.push(res)
|
||||||
|
|
||||||
// Remove the label text from the task title
|
// Remove the label text from the task title
|
||||||
task.title = task.title.replace(` ~${labelTitle}`, '');
|
task.title = task.title.replace(` ~${labelTitle}`, '')
|
||||||
|
|
||||||
// Make the promise done (the one with the index 0 does not exist)
|
// Make the promise done (the one with the index 0 does not exist)
|
||||||
labelAddings[index - 1].resolve(result);
|
labelAddings[index - 1].resolve(result)
|
||||||
})
|
})
|
||||||
.catch(e => {
|
.catch(e => {
|
||||||
this.error(e, this);
|
this.error(e, this)
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// label not found, create it
|
|
||||||
const label = new LabelModel({ title: labelTitle });
|
|
||||||
this.labelService
|
|
||||||
.create(label)
|
|
||||||
.then(res => {
|
|
||||||
const labelTask = new LabelTask({
|
|
||||||
taskId: task.id,
|
|
||||||
labelId: res.id,
|
|
||||||
});
|
|
||||||
this.labelTaskService
|
|
||||||
.create(labelTask)
|
|
||||||
.then(result => {
|
|
||||||
task.labels.push(res);
|
|
||||||
|
|
||||||
// Remove the label text from the task title
|
|
||||||
task.title = task.title.replace(
|
|
||||||
` ~${labelTitle}`,
|
|
||||||
'',
|
|
||||||
);
|
|
||||||
|
|
||||||
// Make the promise done (the one with the index 0 does not exist)
|
|
||||||
labelAddings[index - 1].resolve(result);
|
|
||||||
})
|
|
||||||
.catch(e => {
|
|
||||||
this.error(e, this);
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
.catch(e => {
|
})
|
||||||
this.error(e, this);
|
.catch(e => {
|
||||||
});
|
this.error(e, this)
|
||||||
}
|
})
|
||||||
})
|
}
|
||||||
.catch(e => {
|
})
|
||||||
this.error(e, this);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// This waits to update the task until all labels have been added and the title has
|
// This waits to update the task until all labels have been added and the title has
|
||||||
// been modified to remove each label text
|
// been modified to remove each label text
|
||||||
Promise.all(labelAddsToWaitFor).then(() => {
|
Promise.all(labelAddsToWaitFor)
|
||||||
this.taskService
|
.then(() => {
|
||||||
.update(task)
|
this.taskService.update(task)
|
||||||
.then(() => {
|
.then(updatedTask => {
|
||||||
this.$store.commit(HAS_TASKS, true);
|
updatedTask.labels = newLabels
|
||||||
})
|
this.$store.commit(HAS_TASKS, true)
|
||||||
.catch(e => {
|
})
|
||||||
this.error(e, this);
|
.catch(e => {
|
||||||
});
|
this.error(e, this)
|
||||||
});
|
})
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
this.$emit('taskAdded', task);
|
this.$emit('taskAdded', task)
|
||||||
})
|
})
|
||||||
.catch(e => {
|
.catch(e => {
|
||||||
this.error(e, this);
|
this.error(e, this)
|
||||||
});
|
})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -94,14 +94,6 @@ export default {
|
||||||
newTask: TaskModel,
|
newTask: TaskModel,
|
||||||
isTaskEdit: false,
|
isTaskEdit: false,
|
||||||
taskEditTask: TaskModel,
|
taskEditTask: TaskModel,
|
||||||
flatPickerConfig: {
|
|
||||||
altFormat: 'j M Y H:i',
|
|
||||||
altInput: true,
|
|
||||||
dateFormat: 'Y-m-d H:i',
|
|
||||||
enableTime: true,
|
|
||||||
onOpen: this.updateLastReminderDate,
|
|
||||||
onClose: this.addReminderDate,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
<script>
|
<script>
|
||||||
import TaskService from '../../../services/task'
|
import TaskService from '../../../services/task'
|
||||||
import flatPickr from 'vue-flatpickr-component'
|
import flatPickr from 'vue-flatpickr-component'
|
||||||
|
import {mapState} from 'vuex'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'defer-task',
|
name: 'defer-task',
|
||||||
|
@ -51,15 +52,6 @@ export default {
|
||||||
dueDate: null,
|
dueDate: null,
|
||||||
lastValue: null,
|
lastValue: null,
|
||||||
changeInterval: null,
|
changeInterval: null,
|
||||||
|
|
||||||
flatPickerConfig: {
|
|
||||||
altFormat: 'j M Y H:i',
|
|
||||||
altInput: true,
|
|
||||||
dateFormat: 'Y-m-d H:i',
|
|
||||||
enableTime: true,
|
|
||||||
time_24hr: true,
|
|
||||||
inline: true,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
@ -102,6 +94,19 @@ export default {
|
||||||
this.lastValue = this.dueDate
|
this.lastValue = this.dueDate
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
computed: mapState({
|
||||||
|
flatPickerConfig: state => ({
|
||||||
|
altFormat: 'j M Y H:i',
|
||||||
|
altInput: true,
|
||||||
|
dateFormat: 'Y-m-d H:i',
|
||||||
|
enableTime: true,
|
||||||
|
time_24hr: true,
|
||||||
|
inline: true,
|
||||||
|
locale: {
|
||||||
|
firstDayOfWeek: state.auth.settings.weekStart,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}),
|
||||||
methods: {
|
methods: {
|
||||||
deferDays(days) {
|
deferDays(days) {
|
||||||
this.dueDate = new Date(this.dueDate)
|
this.dueDate = new Date(this.dueDate)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<multiselect
|
<multiselect
|
||||||
:loading="labelService.loading || labelTaskService.loading"
|
:loading="loading"
|
||||||
placeholder="Type to add a new label..."
|
placeholder="Type to add a new label..."
|
||||||
:multiple="true"
|
:multiple="true"
|
||||||
@search="findLabel"
|
@search="findLabel"
|
||||||
|
@ -11,6 +11,7 @@
|
||||||
@create="createAndAddLabel"
|
@create="createAndAddLabel"
|
||||||
create-placeholder="Add this as new label"
|
create-placeholder="Add this as new label"
|
||||||
v-model="labels"
|
v-model="labels"
|
||||||
|
:search-delay="10"
|
||||||
>
|
>
|
||||||
<template v-slot:tag="props">
|
<template v-slot:tag="props">
|
||||||
<span
|
<span
|
||||||
|
@ -39,11 +40,11 @@
|
||||||
<script>
|
<script>
|
||||||
import differenceWith from 'lodash/differenceWith'
|
import differenceWith from 'lodash/differenceWith'
|
||||||
|
|
||||||
import LabelService from '../../../services/label'
|
|
||||||
import LabelModel from '../../../models/label'
|
import LabelModel from '../../../models/label'
|
||||||
import LabelTaskService from '../../../services/labelTask'
|
import LabelTaskService from '../../../services/labelTask'
|
||||||
|
|
||||||
import Multiselect from '@/components/input/multiselect'
|
import Multiselect from '@/components/input/multiselect'
|
||||||
|
import {LOADING, LOADING_MODULE} from '@/store/mutation-types'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'edit-labels',
|
name: 'edit-labels',
|
||||||
|
@ -62,12 +63,10 @@ export default {
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
labelService: LabelService,
|
|
||||||
labelTaskService: LabelTaskService,
|
labelTaskService: LabelTaskService,
|
||||||
foundLabels: [],
|
|
||||||
labelTimeout: null,
|
labelTimeout: null,
|
||||||
labels: [],
|
labels: [],
|
||||||
searchQuery: '',
|
query: '',
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
@ -79,38 +78,26 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.labelService = new LabelService()
|
|
||||||
this.labelTaskService = new LabelTaskService()
|
this.labelTaskService = new LabelTaskService()
|
||||||
this.labels = this.value
|
this.labels = this.value
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
foundLabels() {
|
||||||
|
const labels = (Object.values(this.$store.state.labels.labels).filter(l => {
|
||||||
|
return l.title.toLowerCase().includes(this.query.toLowerCase())
|
||||||
|
}) ?? [])
|
||||||
|
|
||||||
|
return differenceWith(labels, this.labels, (first, second) => {
|
||||||
|
return first.id === second.id
|
||||||
|
})
|
||||||
|
},
|
||||||
|
loading() {
|
||||||
|
return this.labelTaskService.loading || (this.$store.state[LOADING] && this.$store.state[LOADING_MODULE] === 'labels')
|
||||||
|
},
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
findLabel(query) {
|
findLabel(query) {
|
||||||
this.searchQuery = query
|
this.query = query
|
||||||
if (query === '') {
|
|
||||||
this.clearAllLabels()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.labelTimeout !== null) {
|
|
||||||
clearTimeout(this.labelTimeout)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delay the search 300ms to not send a request on every keystroke
|
|
||||||
this.labelTimeout = setTimeout(() => {
|
|
||||||
this.labelService.getAll({}, {s: query})
|
|
||||||
.then(response => {
|
|
||||||
this.$set(this, 'foundLabels', differenceWith(response, this.labels, (first, second) => {
|
|
||||||
return first.id === second.id
|
|
||||||
}))
|
|
||||||
this.labelTimeout = null
|
|
||||||
})
|
|
||||||
.catch(e => {
|
|
||||||
this.error(e, this)
|
|
||||||
})
|
|
||||||
}, 300)
|
|
||||||
},
|
|
||||||
clearAllLabels() {
|
|
||||||
this.$set(this, 'foundLabels', [])
|
|
||||||
},
|
},
|
||||||
addLabel(label, showNotification = true) {
|
addLabel(label, showNotification = true) {
|
||||||
this.$store.dispatch('tasks/addLabel', {label: label, taskId: this.taskId})
|
this.$store.dispatch('tasks/addLabel', {label: label, taskId: this.taskId})
|
||||||
|
@ -141,8 +128,8 @@ export default {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
createAndAddLabel(title) {
|
createAndAddLabel(title) {
|
||||||
let newLabel = new LabelModel({title: title})
|
const newLabel = new LabelModel({title: title})
|
||||||
this.labelService.create(newLabel)
|
this.$store.dispatch('labels/createLabel', newLabel)
|
||||||
.then(r => {
|
.then(r => {
|
||||||
this.addLabel(r, false)
|
this.addLabel(r, false)
|
||||||
this.labels.push(r)
|
this.labels.push(r)
|
||||||
|
@ -156,7 +143,3 @@ export default {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
|
@ -9,6 +9,7 @@ export default class UserSettingsModel extends AbstractModel {
|
||||||
discoverableByName: false,
|
discoverableByName: false,
|
||||||
discoverableByEmail: false,
|
discoverableByEmail: false,
|
||||||
overdueTasksRemindersEnabled: true,
|
overdueTasksRemindersEnabled: true,
|
||||||
|
weekStart: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -129,8 +129,7 @@ export default class AbstractService {
|
||||||
* @param route
|
* @param route
|
||||||
* @returns object
|
* @returns object
|
||||||
*/
|
*/
|
||||||
getRouteReplacements(route) {
|
getRouteReplacements(route, parameters = {}) {
|
||||||
let parameters = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}
|
|
||||||
let replace$$1 = {}
|
let replace$$1 = {}
|
||||||
let pattern = this.getRouteParameterPattern()
|
let pattern = this.getRouteParameterPattern()
|
||||||
pattern = new RegExp(pattern instanceof RegExp ? pattern.source : pattern, 'g')
|
pattern = new RegExp(pattern instanceof RegExp ? pattern.source : pattern, 'g')
|
||||||
|
|
|
@ -17,6 +17,7 @@ import kanban from './modules/kanban'
|
||||||
import tasks from './modules/tasks'
|
import tasks from './modules/tasks'
|
||||||
import lists from './modules/lists'
|
import lists from './modules/lists'
|
||||||
import attachments from './modules/attachments'
|
import attachments from './modules/attachments'
|
||||||
|
import labels from './modules/labels'
|
||||||
|
|
||||||
import ListService from '../services/list'
|
import ListService from '../services/list'
|
||||||
import {setTitle} from '@/helpers/setTitle'
|
import {setTitle} from '@/helpers/setTitle'
|
||||||
|
@ -32,6 +33,7 @@ export const store = new Vuex.Store({
|
||||||
tasks,
|
tasks,
|
||||||
lists,
|
lists,
|
||||||
attachments,
|
attachments,
|
||||||
|
labels,
|
||||||
},
|
},
|
||||||
state: {
|
state: {
|
||||||
loading: false,
|
loading: false,
|
||||||
|
|
|
@ -2,6 +2,13 @@ import {HTTPFactory} from '@/http-common'
|
||||||
import {ERROR_MESSAGE, LOADING} from '../mutation-types'
|
import {ERROR_MESSAGE, LOADING} from '../mutation-types'
|
||||||
import UserModel from '../../models/user'
|
import UserModel from '../../models/user'
|
||||||
|
|
||||||
|
const defaultSettings = settings => {
|
||||||
|
if (typeof settings.weekStart === 'undefined' || settings.weekStart === '') {
|
||||||
|
settings.weekStart = 0
|
||||||
|
}
|
||||||
|
return settings
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
namespaced: true,
|
namespaced: true,
|
||||||
state: () => ({
|
state: () => ({
|
||||||
|
@ -20,12 +27,12 @@ export default {
|
||||||
state.avatarUrl = info.getAvatarUrl()
|
state.avatarUrl = info.getAvatarUrl()
|
||||||
|
|
||||||
if (info.settings) {
|
if (info.settings) {
|
||||||
state.settings = info.settings
|
state.settings = defaultSettings(info.settings)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setUserSettings(state, settings) {
|
setUserSettings(state, settings) {
|
||||||
state.settings = settings
|
state.settings = defaultSettings(settings)
|
||||||
const info = state.info !== null ? state.info : {}
|
const info = state.info !== null ? state.info : {}
|
||||||
info.name = settings.name
|
info.name = settings.name
|
||||||
state.info = info
|
state.info = info
|
||||||
|
|
100
src/store/modules/labels.js
Normal file
100
src/store/modules/labels.js
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
import LabelService from '@/services/label'
|
||||||
|
import Vue from 'vue'
|
||||||
|
import {setLoading} from '@/store/helper'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
namespaced: true,
|
||||||
|
// The state is an object which has the label ids as keys.
|
||||||
|
state: () => ({
|
||||||
|
labels: {},
|
||||||
|
loaded: false,
|
||||||
|
}),
|
||||||
|
mutations: {
|
||||||
|
setLabels(state, labels) {
|
||||||
|
labels.forEach(l => {
|
||||||
|
Vue.set(state.labels, l.id, l)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
setLabel(state, label) {
|
||||||
|
Vue.set(state.labels, label.id, label)
|
||||||
|
},
|
||||||
|
removeLabelById(state, label) {
|
||||||
|
Vue.delete(state.labels, label.id)
|
||||||
|
},
|
||||||
|
setLoaded(state, loaded) {
|
||||||
|
state.loaded = loaded
|
||||||
|
},
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
loadAllLabels(ctx, {forceLoad} = {}) {
|
||||||
|
if (ctx.state.loaded && !forceLoad) {
|
||||||
|
return Promise.resolve()
|
||||||
|
}
|
||||||
|
|
||||||
|
const cancel = setLoading(ctx, 'labels')
|
||||||
|
const labelService = new LabelService()
|
||||||
|
|
||||||
|
const getAllLabels = (page = 1) => {
|
||||||
|
return labelService.getAll({}, {}, page)
|
||||||
|
.then(labels => {
|
||||||
|
if (page < labelService.totalPages) {
|
||||||
|
return getAllLabels(page + 1)
|
||||||
|
.then(nextLabels => {
|
||||||
|
return labels.concat(nextLabels)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return labels
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
return Promise.reject(e)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return getAllLabels()
|
||||||
|
.then(r => {
|
||||||
|
ctx.commit('setLabels', r)
|
||||||
|
ctx.commit('setLoaded', true)
|
||||||
|
return Promise.resolve(r)
|
||||||
|
})
|
||||||
|
.catch(e => Promise.reject(e))
|
||||||
|
.finally(() => cancel())
|
||||||
|
},
|
||||||
|
deleteLabel(ctx, label) {
|
||||||
|
const cancel = setLoading(ctx, 'labels')
|
||||||
|
const labelService = new LabelService()
|
||||||
|
|
||||||
|
return labelService.delete(label)
|
||||||
|
.then(r => {
|
||||||
|
ctx.commit('removeLabelById', label)
|
||||||
|
return Promise.resolve(r)
|
||||||
|
})
|
||||||
|
.catch(e => Promise.reject(e))
|
||||||
|
.finally(() => cancel())
|
||||||
|
},
|
||||||
|
updateLabel(ctx, label) {
|
||||||
|
const cancel = setLoading(ctx, 'labels')
|
||||||
|
const labelService = new LabelService()
|
||||||
|
|
||||||
|
return labelService.update(label)
|
||||||
|
.then(r => {
|
||||||
|
ctx.commit('setLabel', r)
|
||||||
|
return Promise.resolve(r)
|
||||||
|
})
|
||||||
|
.catch(e => Promise.reject(e))
|
||||||
|
.finally(() => cancel())
|
||||||
|
},
|
||||||
|
createLabel(ctx, label) {
|
||||||
|
const cancel = setLoading(ctx, 'labels')
|
||||||
|
const labelService = new LabelService()
|
||||||
|
|
||||||
|
return labelService.create(label)
|
||||||
|
.then(r => {
|
||||||
|
ctx.commit('setLabel', r)
|
||||||
|
return Promise.resolve(r)
|
||||||
|
})
|
||||||
|
.catch(e => Promise.reject(e))
|
||||||
|
.finally(() => cancel())
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
|
@ -152,23 +152,6 @@ $filter-container-top-link-share-list: -47px;
|
||||||
margin-top: $filter-container-top-default;
|
margin-top: $filter-container-top-default;
|
||||||
}
|
}
|
||||||
|
|
||||||
.is-archived {
|
.is-archived .notification.is-warning {
|
||||||
$notification-height: 1.25rem + 1.25rem + 1.5rem + 1.5rem;
|
margin-bottom: 1rem;
|
||||||
|
|
||||||
.filter-container {
|
|
||||||
margin-top: calc(#{$filter-container-top-default} - #{$notification-height});
|
|
||||||
}
|
|
||||||
|
|
||||||
.link-share-container .gantt-chart-container .filter-container,
|
|
||||||
.gantt-chart-container .filter-container {
|
|
||||||
margin-top: calc(#{$filter-container-top-link-share-gantt} - 2rem - #{$notification-height});
|
|
||||||
}
|
|
||||||
|
|
||||||
.link-share-container .list-view .filter-container {
|
|
||||||
margin-top: calc(#{$filter-container-top-link-share-list} - #{$notification-height});
|
|
||||||
}
|
|
||||||
|
|
||||||
.link-share-container .filter-container {
|
|
||||||
margin-top: calc(#{$filter-container-top-default} - #{$notification-height});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -199,6 +199,10 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.link-share-container:not(.has-background) .task-view {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
.task-view-container {
|
.task-view-container {
|
||||||
padding-bottom: 1rem;
|
padding-bottom: 1rem;
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
<h2>
|
<h2>
|
||||||
Hi {{ userInfo.name !== '' ? userInfo.name : userInfo.username }}!
|
Hi {{ userInfo.name !== '' ? userInfo.name : userInfo.username }}!
|
||||||
</h2>
|
</h2>
|
||||||
<div>{{ defaultListId }}</div>
|
|
||||||
<add-task
|
<add-task
|
||||||
:listId="defaultListId"
|
:listId="defaultListId"
|
||||||
@taskAdded="updateTaskList"
|
@taskAdded="updateTaskList"
|
||||||
|
@ -35,9 +34,9 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState } from 'vuex';
|
import { mapState } from 'vuex'
|
||||||
import ShowTasks from './tasks/ShowTasks';
|
import ShowTasks from './tasks/ShowTasks'
|
||||||
import AddTask from '../components/tasks/add-task';
|
import AddTask from '../components/tasks/add-task'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Home',
|
name: 'Home',
|
||||||
|
@ -52,7 +51,7 @@ export default {
|
||||||
tasks: [],
|
tasks: [],
|
||||||
defaultListId: undefined,
|
defaultListId: undefined,
|
||||||
showTasksKey: 0,
|
showTasksKey: 0,
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
//TODO: Load the value from user settings. Until then it will not render the add task component.
|
//TODO: Load the value from user settings. Until then it will not render the add task component.
|
||||||
|
@ -66,23 +65,23 @@ export default {
|
||||||
hasTasks: state => state.hasTasks,
|
hasTasks: state => state.hasTasks,
|
||||||
defaultNamespaceId: state => {
|
defaultNamespaceId: state => {
|
||||||
if (state.namespaces.namespaces.length === 0) {
|
if (state.namespaces.namespaces.length === 0) {
|
||||||
return 0;
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
return state.namespaces.namespaces[0].id;
|
return state.namespaces.namespaces[0].id
|
||||||
},
|
},
|
||||||
hasLists: state => {
|
hasLists: state => {
|
||||||
if (state.namespaces.namespaces.length === 0) {
|
if (state.namespaces.namespaces.length === 0) {
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return state.namespaces.namespaces[0].lists.length > 0;
|
return state.namespaces.namespaces[0].lists.length > 0
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
methods: {
|
methods: {
|
||||||
updateTaskList() {
|
updateTaskList() {
|
||||||
this.showTasksKey += 1;
|
this.showTasksKey += 1
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div :class="{ 'is-loading': labelService.loading}" class="loader-container">
|
<div :class="{ 'is-loading': loading}" class="loader-container">
|
||||||
<x-button
|
<x-button
|
||||||
:to="{name:'labels.create'}"
|
:to="{name:'labels.create'}"
|
||||||
class="is-pulled-right"
|
class="is-pulled-right"
|
||||||
|
@ -76,7 +76,7 @@
|
||||||
<div class="field has-addons">
|
<div class="field has-addons">
|
||||||
<div class="control is-expanded">
|
<div class="control is-expanded">
|
||||||
<x-button
|
<x-button
|
||||||
:loading="labelService.loading"
|
:loading="loading"
|
||||||
class="is-fullwidth"
|
class="is-fullwidth"
|
||||||
@click="editLabelSubmit()"
|
@click="editLabelSubmit()"
|
||||||
>
|
>
|
||||||
|
@ -101,11 +101,11 @@
|
||||||
<script>
|
<script>
|
||||||
import {mapState} from 'vuex'
|
import {mapState} from 'vuex'
|
||||||
|
|
||||||
import LabelService from '../../services/label'
|
|
||||||
import LabelModel from '../../models/label'
|
import LabelModel from '../../models/label'
|
||||||
import ColorPicker from '../../components/input/colorPicker'
|
import ColorPicker from '../../components/input/colorPicker'
|
||||||
import LoadingComponent from '../../components/misc/loading'
|
import LoadingComponent from '../../components/misc/loading'
|
||||||
import ErrorComponent from '../../components/misc/error'
|
import ErrorComponent from '../../components/misc/error'
|
||||||
|
import {LOADING, LOADING_MODULE} from '@/store/mutation-types'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ListLabels',
|
name: 'ListLabels',
|
||||||
|
@ -120,15 +120,12 @@ export default {
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
labelService: LabelService,
|
|
||||||
labels: [],
|
|
||||||
labelEditLabel: LabelModel,
|
labelEditLabel: LabelModel,
|
||||||
isLabelEdit: false,
|
isLabelEdit: false,
|
||||||
editorActive: false,
|
editorActive: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.labelService = new LabelService()
|
|
||||||
this.labelEditLabel = new LabelModel()
|
this.labelEditLabel = new LabelModel()
|
||||||
this.loadLabels()
|
this.loadLabels()
|
||||||
},
|
},
|
||||||
|
@ -137,43 +134,19 @@ export default {
|
||||||
},
|
},
|
||||||
computed: mapState({
|
computed: mapState({
|
||||||
userInfo: state => state.auth.info,
|
userInfo: state => state.auth.info,
|
||||||
|
labels: state => state.labels.labels,
|
||||||
|
loading: state => state[LOADING] && state[LOADING_MODULE] === 'labels',
|
||||||
}),
|
}),
|
||||||
methods: {
|
methods: {
|
||||||
loadLabels() {
|
loadLabels() {
|
||||||
const getAllLabels = (page = 1) => {
|
this.$store.dispatch('labels/loadAllLabels')
|
||||||
return this.labelService.getAll({}, {}, page)
|
|
||||||
.then(labels => {
|
|
||||||
if (page < this.labelService.totalPages) {
|
|
||||||
return getAllLabels(page + 1)
|
|
||||||
.then(nextLabels => {
|
|
||||||
return labels.concat(nextLabels)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
return labels
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(e => {
|
|
||||||
return Promise.reject(e)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
getAllLabels()
|
|
||||||
.then(r => {
|
|
||||||
this.$set(this, 'labels', r)
|
|
||||||
})
|
|
||||||
.catch(e => {
|
.catch(e => {
|
||||||
this.error(e, this)
|
this.error(e, this)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
deleteLabel(label) {
|
deleteLabel(label) {
|
||||||
this.labelService.delete(label)
|
this.$store.dispatch('labels/deleteLabel', label)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
// Remove the label from the list
|
|
||||||
for (const l in this.labels) {
|
|
||||||
if (this.labels[l].id === label.id) {
|
|
||||||
this.labels.splice(l, 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.success({message: 'The label was successfully deleted.'}, this)
|
this.success({message: 'The label was successfully deleted.'}, this)
|
||||||
})
|
})
|
||||||
.catch(e => {
|
.catch(e => {
|
||||||
|
@ -181,13 +154,8 @@ export default {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
editLabelSubmit() {
|
editLabelSubmit() {
|
||||||
this.labelService.update(this.labelEditLabel)
|
this.$store.dispatch('labels/updateLabel', this.labelEditLabel)
|
||||||
.then(r => {
|
.then(() => {
|
||||||
for (const l in this.labels) {
|
|
||||||
if (this.labels[l].id === r.id) {
|
|
||||||
this.$set(this.labels, l, r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.success({message: 'The label was successfully updated.'}, this)
|
this.success({message: 'The label was successfully updated.'}, this)
|
||||||
})
|
})
|
||||||
.catch(e => {
|
.catch(e => {
|
||||||
|
|
|
@ -8,10 +8,10 @@
|
||||||
<label class="label" for="labelTitle">Label Title</label>
|
<label class="label" for="labelTitle">Label Title</label>
|
||||||
<div
|
<div
|
||||||
class="control is-expanded"
|
class="control is-expanded"
|
||||||
:class="{ 'is-loading': labelService.loading }"
|
:class="{ 'is-loading': loading }"
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
:class="{ disabled: labelService.loading }"
|
:class="{ disabled: loading }"
|
||||||
class="input"
|
class="input"
|
||||||
placeholder="The label title goes here..."
|
placeholder="The label title goes here..."
|
||||||
type="text"
|
type="text"
|
||||||
|
@ -28,7 +28,7 @@
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">Color</label>
|
<label class="label">Color</label>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<color-picker v-model="label.hexColor" />
|
<color-picker v-model="label.hexColor"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</create-edit>
|
</create-edit>
|
||||||
|
@ -36,17 +36,16 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import labelModel from '../../models/label'
|
import labelModel from '../../models/label'
|
||||||
import labelService from '../../services/label'
|
|
||||||
import LabelModel from '../../models/label'
|
import LabelModel from '../../models/label'
|
||||||
import LabelService from '../../services/label'
|
|
||||||
import CreateEdit from '@/components/misc/create-edit'
|
import CreateEdit from '@/components/misc/create-edit'
|
||||||
import ColorPicker from '../../components/input/colorPicker'
|
import ColorPicker from '../../components/input/colorPicker'
|
||||||
|
import {mapState} from 'vuex'
|
||||||
|
import {LOADING, LOADING_MODULE} from '@/store/mutation-types'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'NewLabel',
|
name: 'NewLabel',
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
labelService: labelService,
|
|
||||||
label: labelModel,
|
label: labelModel,
|
||||||
showError: false,
|
showError: false,
|
||||||
}
|
}
|
||||||
|
@ -56,12 +55,14 @@ export default {
|
||||||
ColorPicker,
|
ColorPicker,
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.labelService = new LabelService()
|
|
||||||
this.label = new LabelModel()
|
this.label = new LabelModel()
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.setTitle('Create a new label')
|
this.setTitle('Create a new label')
|
||||||
},
|
},
|
||||||
|
computed: mapState({
|
||||||
|
loading: state => state[LOADING] && state[LOADING_MODULE] === 'labels',
|
||||||
|
}),
|
||||||
methods: {
|
methods: {
|
||||||
newLabel() {
|
newLabel() {
|
||||||
if (this.label.title === '') {
|
if (this.label.title === '') {
|
||||||
|
@ -70,17 +71,13 @@ export default {
|
||||||
}
|
}
|
||||||
this.showError = false
|
this.showError = false
|
||||||
|
|
||||||
this.labelService
|
this.$store.dispatch('labels/createLabel', this.label)
|
||||||
.create(this.label)
|
.then(r => {
|
||||||
.then((response) => {
|
|
||||||
this.$router.push({
|
this.$router.push({
|
||||||
name: 'labels.index',
|
name: 'labels.index',
|
||||||
params: { id: response.id },
|
params: {id: r.id},
|
||||||
})
|
})
|
||||||
this.success(
|
this.success({message: 'The label was successfully created.'}, this)
|
||||||
{ message: 'The label was successfully created.' },
|
|
||||||
this,
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
this.error(e, this)
|
this.error(e, this)
|
||||||
|
|
|
@ -66,6 +66,7 @@ import GanttChart from '../../../components/tasks/gantt-component'
|
||||||
import flatPickr from 'vue-flatpickr-component'
|
import flatPickr from 'vue-flatpickr-component'
|
||||||
import Fancycheckbox from '../../../components/input/fancycheckbox'
|
import Fancycheckbox from '../../../components/input/fancycheckbox'
|
||||||
import {saveListView} from '@/helpers/saveListView'
|
import {saveListView} from '@/helpers/saveListView'
|
||||||
|
import {mapState} from 'vuex'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Gantt',
|
name: 'Gantt',
|
||||||
|
@ -85,14 +86,19 @@ export default {
|
||||||
dayWidth: 35,
|
dayWidth: 35,
|
||||||
dateFrom: null,
|
dateFrom: null,
|
||||||
dateTo: null,
|
dateTo: null,
|
||||||
flatPickerConfig: {
|
|
||||||
altFormat: 'j M Y',
|
|
||||||
altInput: true,
|
|
||||||
dateFormat: 'Y-m-d',
|
|
||||||
enableTime: false,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
computed: mapState({
|
||||||
|
flatPickerConfig: state => ({
|
||||||
|
altFormat: 'j M Y',
|
||||||
|
altInput: true,
|
||||||
|
dateFormat: 'Y-m-d',
|
||||||
|
enableTime: false,
|
||||||
|
locale: {
|
||||||
|
firstDayOfWeek: state.auth.settings.weekStart,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}),
|
||||||
beforeMount() {
|
beforeMount() {
|
||||||
this.dateFrom = new Date((new Date()).setDate((new Date()).getDate() - 15))
|
this.dateFrom = new Date((new Date()).setDate((new Date()).getDate() - 15))
|
||||||
this.dateTo = new Date((new Date()).setDate((new Date()).getDate() + 30))
|
this.dateTo = new Date((new Date()).setDate((new Date()).getDate() + 30))
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
@focusout="() => saveBucketTitle(bucket.id)"
|
@focusout="() => saveBucketTitle(bucket.id)"
|
||||||
@keydown.enter.prevent.stop="() => saveBucketTitle(bucket.id)"
|
@keydown.enter.prevent.stop="() => saveBucketTitle(bucket.id)"
|
||||||
class="title input"
|
class="title input"
|
||||||
contenteditable="true"
|
:contenteditable="canWrite"
|
||||||
spellcheck="false">{{ bucket.title }}</h2>
|
spellcheck="false">{{ bucket.title }}</h2>
|
||||||
<span
|
<span
|
||||||
:class="{'is-max': bucket.tasks.length >= bucket.limit}"
|
:class="{'is-max': bucket.tasks.length >= bucket.limit}"
|
||||||
|
|
|
@ -64,19 +64,16 @@
|
||||||
<add-task
|
<add-task
|
||||||
:listId="Number($route.params.listId)"
|
:listId="Number($route.params.listId)"
|
||||||
@taskAdded="updateTaskList"
|
@taskAdded="updateTaskList"
|
||||||
|
ref="newTaskInput"
|
||||||
/>
|
/>
|
||||||
<p class="help is-danger" v-if="showError && newTaskText === ''">
|
<p class="help is-danger" v-if="showError && newTaskText === ''">
|
||||||
Please specify a list title.
|
Please specify a list title.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<nothing
|
<nothing v-if="ctaVisible && tasks.length === 0 && !taskCollectionService.loading">
|
||||||
v-if="
|
|
||||||
ctaVisible && tasks.length === 0 && !taskCollectionService.loading
|
|
||||||
"
|
|
||||||
>
|
|
||||||
This list is currently empty.
|
This list is currently empty.
|
||||||
<a @click="$refs.newTaskInput.focus()">Create a new task.</a>
|
<a @click="focusNewTaskInput()">Create a new task.</a>
|
||||||
</nothing>
|
</nothing>
|
||||||
|
|
||||||
<div class="tasks-container">
|
<div class="tasks-container">
|
||||||
|
@ -165,21 +162,20 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import TaskService from '../../../services/task';
|
import TaskService from '../../../services/task'
|
||||||
import TaskModel from '../../../models/task';
|
import TaskModel from '../../../models/task'
|
||||||
import LabelTaskService from '../../../services/labelTask';
|
import LabelTaskService from '../../../services/labelTask'
|
||||||
import LabelService from '../../../services/label';
|
|
||||||
|
|
||||||
import EditTask from '../../../components/tasks/edit-task';
|
import EditTask from '../../../components/tasks/edit-task'
|
||||||
import AddTask from '../../../components/tasks/add-task';
|
import AddTask from '../../../components/tasks/add-task'
|
||||||
import SingleTaskInList from '../../../components/tasks/partials/singleTaskInList';
|
import SingleTaskInList from '../../../components/tasks/partials/singleTaskInList'
|
||||||
import taskList from '../../../components/tasks/mixins/taskList';
|
import taskList from '../../../components/tasks/mixins/taskList'
|
||||||
import { saveListView } from '@/helpers/saveListView';
|
import { saveListView } from '@/helpers/saveListView'
|
||||||
import Rights from '../../../models/rights.json';
|
import Rights from '../../../models/rights.json'
|
||||||
import { mapState } from 'vuex';
|
import { mapState } from 'vuex'
|
||||||
import FilterPopup from '@/components/list/partials/filter-popup';
|
import FilterPopup from '@/components/list/partials/filter-popup'
|
||||||
import { HAS_TASKS } from '@/store/mutation-types';
|
import { HAS_TASKS } from '@/store/mutation-types'
|
||||||
import Nothing from '@/components/misc/nothing';
|
import Nothing from '@/components/misc/nothing'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'List',
|
name: 'List',
|
||||||
|
@ -192,10 +188,9 @@ export default {
|
||||||
|
|
||||||
showError: false,
|
showError: false,
|
||||||
labelTaskService: LabelTaskService,
|
labelTaskService: LabelTaskService,
|
||||||
labelService: LabelService,
|
|
||||||
|
|
||||||
ctaVisible: false,
|
ctaVisible: false,
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
mixins: [taskList],
|
mixins: [taskList],
|
||||||
components: {
|
components: {
|
||||||
|
@ -206,56 +201,58 @@ export default {
|
||||||
AddTask,
|
AddTask,
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.taskService = new TaskService();
|
this.taskService = new TaskService()
|
||||||
this.labelService = new LabelService();
|
this.labelTaskService = new LabelTaskService()
|
||||||
this.labelTaskService = new LabelTaskService();
|
|
||||||
|
|
||||||
// Save the current list view to local storage
|
// Save the current list view to local storage
|
||||||
// We use local storage and not vuex here to make it persistent across reloads.
|
// We use local storage and not vuex here to make it persistent across reloads.
|
||||||
saveListView(this.$route.params.listId, this.$route.name);
|
saveListView(this.$route.params.listId, this.$route.name)
|
||||||
},
|
},
|
||||||
computed: mapState({
|
computed: mapState({
|
||||||
canWrite: state => state.currentList.maxRight > Rights.READ,
|
canWrite: state => state.currentList.maxRight > Rights.READ,
|
||||||
list: state => state.currentList,
|
list: state => state.currentList,
|
||||||
}),
|
}),
|
||||||
mounted() {
|
mounted() {
|
||||||
this.$nextTick(() => (this.ctaVisible = true));
|
this.$nextTick(() => (this.ctaVisible = true))
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// This function initializes the tasks page and loads the first page of tasks
|
// This function initializes the tasks page and loads the first page of tasks
|
||||||
initTasks(page, search = '') {
|
initTasks(page, search = '') {
|
||||||
this.taskEditTask = null;
|
this.taskEditTask = null
|
||||||
this.isTaskEdit = false;
|
this.isTaskEdit = false
|
||||||
this.loadTasks(page, search);
|
this.loadTasks(page, search)
|
||||||
|
},
|
||||||
|
focusNewTaskInput() {
|
||||||
|
this.$refs.newTaskInput.$refs.newTaskInput.focus()
|
||||||
},
|
},
|
||||||
updateTaskList(task) {
|
updateTaskList(task) {
|
||||||
this.tasks.push(task);
|
this.tasks.push(task)
|
||||||
this.sortTasks();
|
this.sortTasks()
|
||||||
this.$store.commit(HAS_TASKS, true);
|
this.$store.commit(HAS_TASKS, true)
|
||||||
},
|
},
|
||||||
editTask(id) {
|
editTask(id) {
|
||||||
// Find the selected task and set it to the current object
|
// Find the selected task and set it to the current object
|
||||||
let theTask = this.getTaskById(id); // Somehow this does not work if we directly assign this to this.taskEditTask
|
let theTask = this.getTaskById(id) // Somehow this does not work if we directly assign this to this.taskEditTask
|
||||||
this.taskEditTask = theTask;
|
this.taskEditTask = theTask
|
||||||
this.isTaskEdit = true;
|
this.isTaskEdit = true
|
||||||
},
|
},
|
||||||
getTaskById(id) {
|
getTaskById(id) {
|
||||||
for (const t in this.tasks) {
|
for (const t in this.tasks) {
|
||||||
if (this.tasks[t].id === parseInt(id)) {
|
if (this.tasks[t].id === parseInt(id)) {
|
||||||
return this.tasks[t];
|
return this.tasks[t]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {}; // FIXME: This should probably throw something to make it clear to the user noting was found
|
return {} // FIXME: This should probably throw something to make it clear to the user noting was found
|
||||||
},
|
},
|
||||||
updateTasks(updatedTask) {
|
updateTasks(updatedTask) {
|
||||||
for (const t in this.tasks) {
|
for (const t in this.tasks) {
|
||||||
if (this.tasks[t].id === updatedTask.id) {
|
if (this.tasks[t].id === updatedTask.id) {
|
||||||
this.$set(this.tasks, t, updatedTask);
|
this.$set(this.tasks, t, updatedTask)
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.sortTasks();
|
this.sortTasks()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -108,7 +108,7 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.showArchived = localStorage.getItem('showArchived') ?? false
|
this.showArchived = JSON.parse(localStorage.getItem('showArchived')) ?? false
|
||||||
this.loadBackgroundsForLists()
|
this.loadBackgroundsForLists()
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
@ -147,7 +147,7 @@ export default {
|
||||||
.catch(e => this.error(e, this))
|
.catch(e => this.error(e, this))
|
||||||
},
|
},
|
||||||
saveShowArchivedState() {
|
saveShowArchivedState() {
|
||||||
localStorage.setItem('showArchived', this.showArchived)
|
localStorage.setItem('showArchived', JSON.stringify(this.showArchived))
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="is-max-width-desktop show-tasks">
|
<div class="is-max-width-desktop show-tasks">
|
||||||
<fancycheckbox
|
<fancycheckbox
|
||||||
@change="loadPendingTasks"
|
@change="setDate"
|
||||||
class="is-pulled-right"
|
class="is-pulled-right"
|
||||||
v-if="!showAll"
|
v-if="!showAll"
|
||||||
v-model="showNulls"
|
v-model="showNulls"
|
||||||
|
@ -15,7 +15,7 @@
|
||||||
:class="{ 'disabled': taskService.loading}"
|
:class="{ 'disabled': taskService.loading}"
|
||||||
:config="flatPickerConfig"
|
:config="flatPickerConfig"
|
||||||
:disabled="taskService.loading"
|
:disabled="taskService.loading"
|
||||||
@on-close="loadPendingTasks"
|
@on-close="setDate"
|
||||||
class="input"
|
class="input"
|
||||||
v-model="cStartDate"
|
v-model="cStartDate"
|
||||||
/>
|
/>
|
||||||
|
@ -24,7 +24,7 @@
|
||||||
:class="{ 'disabled': taskService.loading}"
|
:class="{ 'disabled': taskService.loading}"
|
||||||
:config="flatPickerConfig"
|
:config="flatPickerConfig"
|
||||||
:disabled="taskService.loading"
|
:disabled="taskService.loading"
|
||||||
@on-close="loadPendingTasks"
|
@on-close="setDate"
|
||||||
class="input"
|
class="input"
|
||||||
v-model="cEndDate"
|
v-model="cEndDate"
|
||||||
/>
|
/>
|
||||||
|
@ -81,14 +81,6 @@ export default {
|
||||||
cEndDate: null,
|
cEndDate: null,
|
||||||
|
|
||||||
showNothingToDo: false,
|
showNothingToDo: false,
|
||||||
|
|
||||||
flatPickerConfig: {
|
|
||||||
altFormat: 'j M Y H:i',
|
|
||||||
altInput: true,
|
|
||||||
dateFormat: 'Y-m-d H:i',
|
|
||||||
enableTime: true,
|
|
||||||
time_24hr: true,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
|
@ -116,8 +108,29 @@ export default {
|
||||||
},
|
},
|
||||||
computed: mapState({
|
computed: mapState({
|
||||||
userAuthenticated: state => state.auth.authenticated,
|
userAuthenticated: state => state.auth.authenticated,
|
||||||
|
flatPickerConfig: state => ({
|
||||||
|
altFormat: 'j M Y H:i',
|
||||||
|
altInput: true,
|
||||||
|
dateFormat: 'Y-m-d H:i',
|
||||||
|
enableTime: true,
|
||||||
|
time_24hr: true,
|
||||||
|
locale: {
|
||||||
|
firstDayOfWeek: state.auth.settings.weekStart,
|
||||||
|
},
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
methods: {
|
methods: {
|
||||||
|
setDate() {
|
||||||
|
this.$router.push({
|
||||||
|
name: this.$route.name,
|
||||||
|
query: {
|
||||||
|
from: +new Date(this.cStartDate),
|
||||||
|
to: +new Date(this.cEndDate),
|
||||||
|
showOverdue: this.showOverdue,
|
||||||
|
showNulls: this.showNulls,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
loadPendingTasks() {
|
loadPendingTasks() {
|
||||||
// Since this route is authentication only, users would get an error message if they access the page unauthenticated.
|
// Since this route is authentication only, users would get an error message if they access the page unauthenticated.
|
||||||
// Since this component is mounted as the home page before unauthenticated users get redirected
|
// Since this component is mounted as the home page before unauthenticated users get redirected
|
||||||
|
@ -127,8 +140,15 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure all dates are date objects
|
// Make sure all dates are date objects
|
||||||
this.cStartDate = new Date(this.cStartDate)
|
if (typeof this.$route.query.from !== 'undefined' && typeof this.$route.query.to !== 'undefined') {
|
||||||
this.cEndDate = new Date(this.cEndDate)
|
this.cStartDate = new Date(Number(this.$route.query.from))
|
||||||
|
this.cEndDate = new Date(Number(this.$route.query.to))
|
||||||
|
} else {
|
||||||
|
this.cStartDate = new Date(this.cStartDate)
|
||||||
|
this.cEndDate = new Date(this.cEndDate)
|
||||||
|
}
|
||||||
|
this.showOverdue = this.$route.query.showOverdue
|
||||||
|
this.showNulls = this.$route.query.showNulls
|
||||||
|
|
||||||
if (this.showAll) {
|
if (this.showAll) {
|
||||||
this.setTitle('Current Tasks')
|
this.setTitle('Current Tasks')
|
||||||
|
@ -177,9 +197,7 @@ export default {
|
||||||
r.sort((a, b) => {
|
r.sort((a, b) => {
|
||||||
return a.dueDate === null && b.dueDate === null ? -1 : 1
|
return a.dueDate === null && b.dueDate === null ? -1 : 1
|
||||||
})
|
})
|
||||||
const tasks = r.
|
const tasks = r.filter(t => t.dueDate !== null).concat(r.filter(t => t.dueDate === null))
|
||||||
filter(t => t.dueDate !== null).
|
|
||||||
concat(r.filter(t => t.dueDate === null))
|
|
||||||
|
|
||||||
this.$set(this, 'tasks', tasks)
|
this.$set(this, 'tasks', tasks)
|
||||||
this.$store.commit(HAS_TASKS, r.length > 0)
|
this.$store.commit(HAS_TASKS, r.length > 0)
|
||||||
|
@ -205,21 +223,20 @@ export default {
|
||||||
this.cStartDate = new Date()
|
this.cStartDate = new Date()
|
||||||
this.cEndDate = new Date((new Date()).getTime() + 7 * 24 * 60 * 60 * 1000)
|
this.cEndDate = new Date((new Date()).getTime() + 7 * 24 * 60 * 60 * 1000)
|
||||||
this.showOverdue = false
|
this.showOverdue = false
|
||||||
this.loadPendingTasks()
|
this.setDate()
|
||||||
},
|
},
|
||||||
setDatesToNextMonth() {
|
setDatesToNextMonth() {
|
||||||
this.cStartDate = new Date()
|
this.cStartDate = new Date()
|
||||||
this.cEndDate = new Date((new Date()).setMonth((new Date()).getMonth() + 1))
|
this.cEndDate = new Date((new Date()).setMonth((new Date()).getMonth() + 1))
|
||||||
this.showOverdue = false
|
this.showOverdue = false
|
||||||
this.loadPendingTasks()
|
this.setDate()
|
||||||
},
|
},
|
||||||
showTodaysTasks() {
|
showTodaysTasks() {
|
||||||
const d = new Date()
|
const d = new Date()
|
||||||
this.cStartDate = new Date()
|
this.cStartDate = new Date()
|
||||||
this.cEndDate = new Date(d.setDate(d.getDate() + 1))
|
this.cEndDate = new Date(d.setDate(d.getDate() + 1))
|
||||||
this.showNulls = false
|
|
||||||
this.showOverdue = true
|
this.showOverdue = true
|
||||||
this.loadPendingTasks()
|
this.setDate()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,13 +17,10 @@ export default {
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
startDate: new Date(this.$route.params.startDateUnix),
|
startDate: null,
|
||||||
endDate: new Date(this.$route.params.endDateUnix),
|
endDate: null,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
|
||||||
'$route': 'setDatesToNextWeek',
|
|
||||||
},
|
|
||||||
created() {
|
created() {
|
||||||
this.setDatesToNextWeek()
|
this.setDatesToNextWeek()
|
||||||
},
|
},
|
||||||
|
|
|
@ -509,6 +509,9 @@ export default {
|
||||||
this.loadTask()
|
this.loadTask()
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
currentList() {
|
||||||
|
return this.$store.state[CURRENT_LIST]
|
||||||
|
},
|
||||||
parent() {
|
parent() {
|
||||||
if (!this.task.listId) {
|
if (!this.task.listId) {
|
||||||
return {
|
return {
|
||||||
|
@ -522,11 +525,11 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
const list = this.$store.getters['namespaces/getListAndNamespaceById'](this.task.listId)
|
const list = this.$store.getters['namespaces/getListAndNamespaceById'](this.task.listId)
|
||||||
this.$store.commit(CURRENT_LIST, list.list)
|
this.$store.commit(CURRENT_LIST, list !== null ? list.list : this.currentList)
|
||||||
return list
|
return list
|
||||||
},
|
},
|
||||||
canWrite() {
|
canWrite() {
|
||||||
return this.task && this.task.maxRight && this.task.maxRight > rights.READ
|
return typeof this.task !== 'undefined' && typeof this.task.maxRight !== 'undefined' && this.task.maxRight > rights.READ
|
||||||
},
|
},
|
||||||
updatedSince() {
|
updatedSince() {
|
||||||
return this.formatDateSince(this.task.updated)
|
return this.formatDateSince(this.task.updated)
|
||||||
|
|
|
@ -132,6 +132,19 @@
|
||||||
Play a sound when marking tasks as done
|
Play a sound when marking tasks as done
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label class="is-flex is-align-items-center">
|
||||||
|
<span>
|
||||||
|
Week starts on
|
||||||
|
</span>
|
||||||
|
<div class="select ml-2">
|
||||||
|
<select v-model.number="settings.weekStart">
|
||||||
|
<option value="0">Sunday</option>
|
||||||
|
<option value="1">Monday</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
<x-button
|
<x-button
|
||||||
:loading="userSettingsService.loading"
|
:loading="userSettingsService.loading"
|
||||||
|
|
239
yarn.lock
239
yarn.lock
|
@ -1716,15 +1716,15 @@
|
||||||
debug "^3.1.0"
|
debug "^3.1.0"
|
||||||
lodash.once "^4.1.1"
|
lodash.once "^4.1.1"
|
||||||
|
|
||||||
"@eslint/eslintrc@^0.4.1":
|
"@eslint/eslintrc@^0.4.2":
|
||||||
version "0.4.1"
|
version "0.4.2"
|
||||||
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.1.tgz#442763b88cecbe3ee0ec7ca6d6dd6168550cbf14"
|
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.2.tgz#f63d0ef06f5c0c57d76c4ab5f63d3835c51b0179"
|
||||||
integrity sha512-5v7TDE9plVhvxQeWLXDTvFvJBdH6pEsdnl2g/dAptmuFEPedQ4Erq5rsDsX+mvAM610IhNaO2W5V1dOOnDKxkQ==
|
integrity sha512-8nmGq/4ycLpIwzvhI4tNDmQztZ8sp+hI7cyG8i1nQDhkAbRzHpXPidRAHlNvCZQpJTKw5ItIpMw9RSToGF00mg==
|
||||||
dependencies:
|
dependencies:
|
||||||
ajv "^6.12.4"
|
ajv "^6.12.4"
|
||||||
debug "^4.1.1"
|
debug "^4.1.1"
|
||||||
espree "^7.3.0"
|
espree "^7.3.0"
|
||||||
globals "^12.1.0"
|
globals "^13.9.0"
|
||||||
ignore "^4.0.6"
|
ignore "^4.0.6"
|
||||||
import-fresh "^3.2.1"
|
import-fresh "^3.2.1"
|
||||||
js-yaml "^3.13.1"
|
js-yaml "^3.13.1"
|
||||||
|
@ -1843,13 +1843,13 @@
|
||||||
jest-util "^27.0.2"
|
jest-util "^27.0.2"
|
||||||
slash "^3.0.0"
|
slash "^3.0.0"
|
||||||
|
|
||||||
"@jest/core@^27.0.3":
|
"@jest/core@^27.0.4":
|
||||||
version "27.0.3"
|
version "27.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/@jest/core/-/core-27.0.3.tgz#b5a38675fa0466450a7fd465f4b226762cb592a2"
|
resolved "https://registry.yarnpkg.com/@jest/core/-/core-27.0.4.tgz#679bf9ac07900da2ddbb9667bb1afa8029038f53"
|
||||||
integrity sha512-rN8lr/OJ8iApcQUh4khnMaOCVX4oRnLwy2tPW3Vh70y62K8Da8fhkxMUq0xX9VPa4+yWUm0tGc/jUSJi+Jzuwg==
|
integrity sha512-+dsmV8VUs1h/Szb+rEWk8xBM1fp1I///uFy9nk3wXGvRsF2lBp8EVPmtWc+QFRb3MY2b7u2HbkGF1fzoDzQTLA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@jest/console" "^27.0.2"
|
"@jest/console" "^27.0.2"
|
||||||
"@jest/reporters" "^27.0.2"
|
"@jest/reporters" "^27.0.4"
|
||||||
"@jest/test-result" "^27.0.2"
|
"@jest/test-result" "^27.0.2"
|
||||||
"@jest/transform" "^27.0.2"
|
"@jest/transform" "^27.0.2"
|
||||||
"@jest/types" "^27.0.2"
|
"@jest/types" "^27.0.2"
|
||||||
|
@ -1860,15 +1860,15 @@
|
||||||
exit "^0.1.2"
|
exit "^0.1.2"
|
||||||
graceful-fs "^4.2.4"
|
graceful-fs "^4.2.4"
|
||||||
jest-changed-files "^27.0.2"
|
jest-changed-files "^27.0.2"
|
||||||
jest-config "^27.0.3"
|
jest-config "^27.0.4"
|
||||||
jest-haste-map "^27.0.2"
|
jest-haste-map "^27.0.2"
|
||||||
jest-message-util "^27.0.2"
|
jest-message-util "^27.0.2"
|
||||||
jest-regex-util "^27.0.1"
|
jest-regex-util "^27.0.1"
|
||||||
jest-resolve "^27.0.2"
|
jest-resolve "^27.0.4"
|
||||||
jest-resolve-dependencies "^27.0.3"
|
jest-resolve-dependencies "^27.0.4"
|
||||||
jest-runner "^27.0.3"
|
jest-runner "^27.0.4"
|
||||||
jest-runtime "^27.0.3"
|
jest-runtime "^27.0.4"
|
||||||
jest-snapshot "^27.0.2"
|
jest-snapshot "^27.0.4"
|
||||||
jest-util "^27.0.2"
|
jest-util "^27.0.2"
|
||||||
jest-validate "^27.0.2"
|
jest-validate "^27.0.2"
|
||||||
jest-watcher "^27.0.2"
|
jest-watcher "^27.0.2"
|
||||||
|
@ -1909,10 +1909,10 @@
|
||||||
"@jest/types" "^27.0.2"
|
"@jest/types" "^27.0.2"
|
||||||
expect "^27.0.2"
|
expect "^27.0.2"
|
||||||
|
|
||||||
"@jest/reporters@^27.0.2":
|
"@jest/reporters@^27.0.4":
|
||||||
version "27.0.2"
|
version "27.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-27.0.2.tgz#ad73835d1cd54da08b0998a70b14446405e8e0d9"
|
resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-27.0.4.tgz#95609b1be97afb80d55d8aa3d7c3179c15810e65"
|
||||||
integrity sha512-SVQjew/kafNxSN1my4praGQP+VPVGHsU8zqiEDppLvq6j1lryIjdNb9P+bZSsKeifU4bIoaPnf9Ui0tK9WOpFA==
|
integrity sha512-Xa90Nm3JnV0xCe4M6A10M9WuN9krb+WFKxV1A98Y4ePCw40n++r7uxFUNU7DT1i9Behj7fjrAIju9oU0t1QtCg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@bcoe/v8-coverage" "^0.2.3"
|
"@bcoe/v8-coverage" "^0.2.3"
|
||||||
"@jest/console" "^27.0.2"
|
"@jest/console" "^27.0.2"
|
||||||
|
@ -1930,7 +1930,7 @@
|
||||||
istanbul-lib-source-maps "^4.0.0"
|
istanbul-lib-source-maps "^4.0.0"
|
||||||
istanbul-reports "^3.0.2"
|
istanbul-reports "^3.0.2"
|
||||||
jest-haste-map "^27.0.2"
|
jest-haste-map "^27.0.2"
|
||||||
jest-resolve "^27.0.2"
|
jest-resolve "^27.0.4"
|
||||||
jest-util "^27.0.2"
|
jest-util "^27.0.2"
|
||||||
jest-worker "^27.0.2"
|
jest-worker "^27.0.2"
|
||||||
slash "^3.0.0"
|
slash "^3.0.0"
|
||||||
|
@ -1958,15 +1958,15 @@
|
||||||
"@types/istanbul-lib-coverage" "^2.0.0"
|
"@types/istanbul-lib-coverage" "^2.0.0"
|
||||||
collect-v8-coverage "^1.0.0"
|
collect-v8-coverage "^1.0.0"
|
||||||
|
|
||||||
"@jest/test-sequencer@^27.0.3":
|
"@jest/test-sequencer@^27.0.4":
|
||||||
version "27.0.3"
|
version "27.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-27.0.3.tgz#2a8632b86a9a6f8900e514917cdab6a062e71049"
|
resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-27.0.4.tgz#976493b277594d81e589896f0ed21f198308928a"
|
||||||
integrity sha512-DcLTzraZ8xLr5fcIl+CF14vKeBBpBrn55wFxI9Ju+dhEBdjRdJQ/Z/pLkMehkPZWIQ+rR23J8e+wFDkfjree0Q==
|
integrity sha512-6UFEVwdmxYdyNffBxVVZxmXEdBE4riSddXYSnFNH0ELFQFk/bvagizim8WfgJTqF4EKd+j1yFxvhb8BMHfOjSQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@jest/test-result" "^27.0.2"
|
"@jest/test-result" "^27.0.2"
|
||||||
graceful-fs "^4.2.4"
|
graceful-fs "^4.2.4"
|
||||||
jest-haste-map "^27.0.2"
|
jest-haste-map "^27.0.2"
|
||||||
jest-runtime "^27.0.3"
|
jest-runtime "^27.0.4"
|
||||||
|
|
||||||
"@jest/transform@^27.0.2":
|
"@jest/transform@^27.0.2":
|
||||||
version "27.0.2"
|
version "27.0.2"
|
||||||
|
@ -6243,13 +6243,13 @@ eslint-visitor-keys@^2.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8"
|
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8"
|
||||||
integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==
|
integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==
|
||||||
|
|
||||||
eslint@7.27.0:
|
eslint@7.28.0:
|
||||||
version "7.27.0"
|
version "7.28.0"
|
||||||
resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.27.0.tgz#665a1506d8f95655c9274d84bd78f7166b07e9c7"
|
resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.28.0.tgz#435aa17a0b82c13bb2be9d51408b617e49c1e820"
|
||||||
integrity sha512-JZuR6La2ZF0UD384lcbnd0Cgg6QJjiCwhMD6eU4h/VGPcVGwawNNzKU41tgokGXnfjOOyI6QIffthhJTPzzuRA==
|
integrity sha512-UMfH0VSjP0G4p3EWirscJEQ/cHqnT/iuH6oNZOB94nBjWbMnhGEPxsZm1eyIW0C/9jLI0Fow4W5DXLjEI7mn1g==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/code-frame" "7.12.11"
|
"@babel/code-frame" "7.12.11"
|
||||||
"@eslint/eslintrc" "^0.4.1"
|
"@eslint/eslintrc" "^0.4.2"
|
||||||
ajv "^6.10.0"
|
ajv "^6.10.0"
|
||||||
chalk "^4.0.0"
|
chalk "^4.0.0"
|
||||||
cross-spawn "^7.0.2"
|
cross-spawn "^7.0.2"
|
||||||
|
@ -6266,7 +6266,7 @@ eslint@7.27.0:
|
||||||
fast-deep-equal "^3.1.3"
|
fast-deep-equal "^3.1.3"
|
||||||
file-entry-cache "^6.0.1"
|
file-entry-cache "^6.0.1"
|
||||||
functional-red-black-tree "^1.0.1"
|
functional-red-black-tree "^1.0.1"
|
||||||
glob-parent "^5.0.0"
|
glob-parent "^5.1.2"
|
||||||
globals "^13.6.0"
|
globals "^13.6.0"
|
||||||
ignore "^4.0.6"
|
ignore "^4.0.6"
|
||||||
import-fresh "^3.0.0"
|
import-fresh "^3.0.0"
|
||||||
|
@ -7250,13 +7250,6 @@ glob-parent@^3.1.0:
|
||||||
is-glob "^3.1.0"
|
is-glob "^3.1.0"
|
||||||
path-dirname "^1.0.0"
|
path-dirname "^1.0.0"
|
||||||
|
|
||||||
glob-parent@^5.0.0:
|
|
||||||
version "5.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.0.tgz#5f4c1d1e748d30cd73ad2944b3577a81b081e8c2"
|
|
||||||
integrity sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==
|
|
||||||
dependencies:
|
|
||||||
is-glob "^4.0.1"
|
|
||||||
|
|
||||||
glob-parent@^5.1.0:
|
glob-parent@^5.1.0:
|
||||||
version "5.1.1"
|
version "5.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229"
|
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229"
|
||||||
|
@ -7264,7 +7257,7 @@ glob-parent@^5.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
is-glob "^4.0.1"
|
is-glob "^4.0.1"
|
||||||
|
|
||||||
glob-parent@~5.1.0:
|
glob-parent@^5.1.2, glob-parent@~5.1.0:
|
||||||
version "5.1.2"
|
version "5.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
|
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
|
||||||
integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
|
integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
|
||||||
|
@ -7307,13 +7300,6 @@ globals@^11.1.0:
|
||||||
resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
|
resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
|
||||||
integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
|
integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
|
||||||
|
|
||||||
globals@^12.1.0:
|
|
||||||
version "12.3.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/globals/-/globals-12.3.0.tgz#1e564ee5c4dded2ab098b0f88f24702a3c56be13"
|
|
||||||
integrity sha512-wAfjdLgFsPZsklLJvOBUBmzYE8/CwhEqSBEMRXA3qxIiNtyqvjYurAtIfDh6chlEPUfmTY3MnZh5Hfh4q0UlIw==
|
|
||||||
dependencies:
|
|
||||||
type-fest "^0.8.1"
|
|
||||||
|
|
||||||
globals@^13.6.0:
|
globals@^13.6.0:
|
||||||
version "13.6.0"
|
version "13.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/globals/-/globals-13.6.0.tgz#d77138e53738567bb96a3916ff6f6b487af20ef7"
|
resolved "https://registry.yarnpkg.com/globals/-/globals-13.6.0.tgz#d77138e53738567bb96a3916ff6f6b487af20ef7"
|
||||||
|
@ -7321,6 +7307,13 @@ globals@^13.6.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
type-fest "^0.20.2"
|
type-fest "^0.20.2"
|
||||||
|
|
||||||
|
globals@^13.9.0:
|
||||||
|
version "13.9.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/globals/-/globals-13.9.0.tgz#4bf2bf635b334a173fb1daf7c5e6b218ecdc06cb"
|
||||||
|
integrity sha512-74/FduwI/JaIrr1H8e71UbDE+5x7pIPs1C2rrwC52SszOo043CsWOZEMW7o2Y58xwm9b+0RBKDxY5n2sUpEFxA==
|
||||||
|
dependencies:
|
||||||
|
type-fest "^0.20.2"
|
||||||
|
|
||||||
globby@^11.0.2:
|
globby@^11.0.2:
|
||||||
version "11.0.2"
|
version "11.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.2.tgz#1af538b766a3b540ebfb58a32b2e2d5897321d83"
|
resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.2.tgz#1af538b766a3b540ebfb58a32b2e2d5897321d83"
|
||||||
|
@ -7619,10 +7612,10 @@ hex-color-regex@^1.1.0:
|
||||||
resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e"
|
resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e"
|
||||||
integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==
|
integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==
|
||||||
|
|
||||||
highlight.js@11.0.0:
|
highlight.js@11.0.1:
|
||||||
version "11.0.0"
|
version "11.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-11.0.0.tgz#e22ac9ca45edc4f87a2187685d591a108ceb8449"
|
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-11.0.1.tgz#a78bafccd9aa297978799fe5eed9beb7ee1ef887"
|
||||||
integrity sha512-ByaTMfsSuoqerTwemOgpIhfULEIaK52JJYhky/sK7/Yqc0+t7Uh5DHay9vIC94YXSupnQ1Vqfc9VXrYP4eXW3Q==
|
integrity sha512-EqYpWyTF2s8nMfttfBA2yLKPNoZCO33pLS4MnbXQ4hECf1TKujCt1Kq7QAdrio7roL4+CqsfjqwYj4tYgq0pJQ==
|
||||||
|
|
||||||
highlight.js@^9.6.0:
|
highlight.js@^9.6.0:
|
||||||
version "9.17.1"
|
version "9.17.1"
|
||||||
|
@ -8554,10 +8547,10 @@ jest-changed-files@^27.0.2:
|
||||||
execa "^5.0.0"
|
execa "^5.0.0"
|
||||||
throat "^6.0.1"
|
throat "^6.0.1"
|
||||||
|
|
||||||
jest-circus@^27.0.3:
|
jest-circus@^27.0.4:
|
||||||
version "27.0.3"
|
version "27.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-27.0.3.tgz#32006967de484e03589da944064d72e172ce3261"
|
resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-27.0.4.tgz#3b261514ee3b3da33def736a6352c98ff56bb6e6"
|
||||||
integrity sha512-tdMfzs7SgD5l7jRcI1iB3vtQi5fHwCgo4RlO8bzZnYc05PZ+tlAOMZeS8eGYkZ2tPaRY/aRLMFWQp/8zXBrolQ==
|
integrity sha512-QD+eblDiRphta630WRKewuASLs/oY1Zki2G4bccntRvrTHQ63ljwFR5TLduuK4Zg0ZPzW0+8o6AP7KRd1yKOjw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@jest/environment" "^27.0.3"
|
"@jest/environment" "^27.0.3"
|
||||||
"@jest/test-result" "^27.0.2"
|
"@jest/test-result" "^27.0.2"
|
||||||
|
@ -8571,39 +8564,39 @@ jest-circus@^27.0.3:
|
||||||
jest-each "^27.0.2"
|
jest-each "^27.0.2"
|
||||||
jest-matcher-utils "^27.0.2"
|
jest-matcher-utils "^27.0.2"
|
||||||
jest-message-util "^27.0.2"
|
jest-message-util "^27.0.2"
|
||||||
jest-runtime "^27.0.3"
|
jest-runtime "^27.0.4"
|
||||||
jest-snapshot "^27.0.2"
|
jest-snapshot "^27.0.4"
|
||||||
jest-util "^27.0.2"
|
jest-util "^27.0.2"
|
||||||
pretty-format "^27.0.2"
|
pretty-format "^27.0.2"
|
||||||
slash "^3.0.0"
|
slash "^3.0.0"
|
||||||
stack-utils "^2.0.3"
|
stack-utils "^2.0.3"
|
||||||
throat "^6.0.1"
|
throat "^6.0.1"
|
||||||
|
|
||||||
jest-cli@^27.0.3:
|
jest-cli@^27.0.4:
|
||||||
version "27.0.3"
|
version "27.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-27.0.3.tgz#b733871acb526054a0f8c971d0466595c5f8316d"
|
resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-27.0.4.tgz#491b12c754c0d7c6873b13a66f26b3a80a852910"
|
||||||
integrity sha512-7bt9Sgv4nWH5pUnyJfdLf8CHWfo4+7lSPxeBwQx4r0vBj9jweJam/piE2U91SXtQI+ckm+TIN97OVnqIYpVhSg==
|
integrity sha512-E0T+/i2lxsWAzV7LKYd0SB7HUAvePqaeIh5vX43/G5jXLhv1VzjYzJAGEkTfvxV774ll9cyE2ljcL73PVMEOXQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@jest/core" "^27.0.3"
|
"@jest/core" "^27.0.4"
|
||||||
"@jest/test-result" "^27.0.2"
|
"@jest/test-result" "^27.0.2"
|
||||||
"@jest/types" "^27.0.2"
|
"@jest/types" "^27.0.2"
|
||||||
chalk "^4.0.0"
|
chalk "^4.0.0"
|
||||||
exit "^0.1.2"
|
exit "^0.1.2"
|
||||||
graceful-fs "^4.2.4"
|
graceful-fs "^4.2.4"
|
||||||
import-local "^3.0.2"
|
import-local "^3.0.2"
|
||||||
jest-config "^27.0.3"
|
jest-config "^27.0.4"
|
||||||
jest-util "^27.0.2"
|
jest-util "^27.0.2"
|
||||||
jest-validate "^27.0.2"
|
jest-validate "^27.0.2"
|
||||||
prompts "^2.0.1"
|
prompts "^2.0.1"
|
||||||
yargs "^16.0.3"
|
yargs "^16.0.3"
|
||||||
|
|
||||||
jest-config@^27.0.3:
|
jest-config@^27.0.4:
|
||||||
version "27.0.3"
|
version "27.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-27.0.3.tgz#31871583573c6d669dcdb5bb2d1a8738f3b91c20"
|
resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-27.0.4.tgz#c4f41378acf40ca77860fb4e213b12109d87b8cf"
|
||||||
integrity sha512-zgtI2YQo+ekKsmYNyDlXFY/7w7WWBSJFoj/WRe173WB88CDUrEYWr0sLdbLOQe+sRu6l1Y2S0MCS6BOJm5jkoA==
|
integrity sha512-VkQFAHWnPQefdvHU9A+G3H/Z3NrrTKqWpvxgQz3nkUdkDTWeKJE6e//BL+R7z79dXOMVksYgM/z6ndtN0hfChg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/core" "^7.1.0"
|
"@babel/core" "^7.1.0"
|
||||||
"@jest/test-sequencer" "^27.0.3"
|
"@jest/test-sequencer" "^27.0.4"
|
||||||
"@jest/types" "^27.0.2"
|
"@jest/types" "^27.0.2"
|
||||||
babel-jest "^27.0.2"
|
babel-jest "^27.0.2"
|
||||||
chalk "^4.0.0"
|
chalk "^4.0.0"
|
||||||
|
@ -8611,14 +8604,14 @@ jest-config@^27.0.3:
|
||||||
glob "^7.1.1"
|
glob "^7.1.1"
|
||||||
graceful-fs "^4.2.4"
|
graceful-fs "^4.2.4"
|
||||||
is-ci "^3.0.0"
|
is-ci "^3.0.0"
|
||||||
jest-circus "^27.0.3"
|
jest-circus "^27.0.4"
|
||||||
jest-environment-jsdom "^27.0.3"
|
jest-environment-jsdom "^27.0.3"
|
||||||
jest-environment-node "^27.0.3"
|
jest-environment-node "^27.0.3"
|
||||||
jest-get-type "^27.0.1"
|
jest-get-type "^27.0.1"
|
||||||
jest-jasmine2 "^27.0.3"
|
jest-jasmine2 "^27.0.4"
|
||||||
jest-regex-util "^27.0.1"
|
jest-regex-util "^27.0.1"
|
||||||
jest-resolve "^27.0.2"
|
jest-resolve "^27.0.4"
|
||||||
jest-runner "^27.0.3"
|
jest-runner "^27.0.4"
|
||||||
jest-util "^27.0.2"
|
jest-util "^27.0.2"
|
||||||
jest-validate "^27.0.2"
|
jest-validate "^27.0.2"
|
||||||
micromatch "^4.0.4"
|
micromatch "^4.0.4"
|
||||||
|
@ -8702,10 +8695,10 @@ jest-haste-map@^27.0.2:
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents "^2.3.2"
|
fsevents "^2.3.2"
|
||||||
|
|
||||||
jest-jasmine2@^27.0.3:
|
jest-jasmine2@^27.0.4:
|
||||||
version "27.0.3"
|
version "27.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-27.0.3.tgz#fa6f6499566ea1b01b68b3ad13f49d1592b02c85"
|
resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-27.0.4.tgz#c669519ccf4904a485338555e1e66cad36bb0670"
|
||||||
integrity sha512-odJ2ia8P5c+IsqOcWJPmku4AqbXIfTVLRjYTKHri3TEvbmTdLw0ghy13OAPIl/0v7cVH0TURK7+xFOHKDLvKIA==
|
integrity sha512-yj3WrjjquZwkJw+eA4c9yucHw4/+EHndHWSqgHbHGQfT94ihaaQsa009j1a0puU8CNxPDk0c1oAPeOpdJUElwA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/traverse" "^7.1.0"
|
"@babel/traverse" "^7.1.0"
|
||||||
"@jest/environment" "^27.0.3"
|
"@jest/environment" "^27.0.3"
|
||||||
|
@ -8720,8 +8713,8 @@ jest-jasmine2@^27.0.3:
|
||||||
jest-each "^27.0.2"
|
jest-each "^27.0.2"
|
||||||
jest-matcher-utils "^27.0.2"
|
jest-matcher-utils "^27.0.2"
|
||||||
jest-message-util "^27.0.2"
|
jest-message-util "^27.0.2"
|
||||||
jest-runtime "^27.0.3"
|
jest-runtime "^27.0.4"
|
||||||
jest-snapshot "^27.0.2"
|
jest-snapshot "^27.0.4"
|
||||||
jest-util "^27.0.2"
|
jest-util "^27.0.2"
|
||||||
pretty-format "^27.0.2"
|
pretty-format "^27.0.2"
|
||||||
throat "^6.0.1"
|
throat "^6.0.1"
|
||||||
|
@ -8777,19 +8770,19 @@ jest-regex-util@^27.0.1:
|
||||||
resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.0.1.tgz#69d4b1bf5b690faa3490113c47486ed85dd45b68"
|
resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.0.1.tgz#69d4b1bf5b690faa3490113c47486ed85dd45b68"
|
||||||
integrity sha512-6nY6QVcpTgEKQy1L41P4pr3aOddneK17kn3HJw6SdwGiKfgCGTvH02hVXL0GU8GEKtPH83eD2DIDgxHXOxVohQ==
|
integrity sha512-6nY6QVcpTgEKQy1L41P4pr3aOddneK17kn3HJw6SdwGiKfgCGTvH02hVXL0GU8GEKtPH83eD2DIDgxHXOxVohQ==
|
||||||
|
|
||||||
jest-resolve-dependencies@^27.0.3:
|
jest-resolve-dependencies@^27.0.4:
|
||||||
version "27.0.3"
|
version "27.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-27.0.3.tgz#7e258f7d0458bb910855f8a50f5c1e9d92c319dc"
|
resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-27.0.4.tgz#a07a242d70d668afd3fcf7f4270755eebb1fe579"
|
||||||
integrity sha512-HdjWOvFAgT5CYChF2eiBN2rRKicjaTCCtA3EtH47REIdGzEHGUhYrWYgLahXsiOovvWN6edhcHL5WCa3gbc04A==
|
integrity sha512-F33UPfw1YGWCV2uxJl7wD6TvcQn5IC0LtguwY3r4L7R6H4twpLkp5Q2ZfzRx9A2I3G8feiy0O0sqcn/Qoym71A==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@jest/types" "^27.0.2"
|
"@jest/types" "^27.0.2"
|
||||||
jest-regex-util "^27.0.1"
|
jest-regex-util "^27.0.1"
|
||||||
jest-snapshot "^27.0.2"
|
jest-snapshot "^27.0.4"
|
||||||
|
|
||||||
jest-resolve@^27.0.2:
|
jest-resolve@^27.0.4:
|
||||||
version "27.0.2"
|
version "27.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-27.0.2.tgz#087a3ed17182722a3415f92bfacc99c49cf8a965"
|
resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-27.0.4.tgz#8a27bc3f2f00c8ea28f3bc99bbf6f468300a703d"
|
||||||
integrity sha512-rmfLGyZhwAUR5z3EwPAW7LQTorWAuCYCcsQJoQxT2it+BOgX3zKxa67r1pfpK3ihy2k9TjYD3/lMp5rPm/CL1Q==
|
integrity sha512-BcfyK2i3cG79PDb/6gB6zFeFQlcqLsQjGBqznFCpA0L/3l1L/oOsltdUjs5eISAWA9HS9qtj8v2PSZr/yWxONQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@jest/types" "^27.0.2"
|
"@jest/types" "^27.0.2"
|
||||||
chalk "^4.0.0"
|
chalk "^4.0.0"
|
||||||
|
@ -8801,10 +8794,10 @@ jest-resolve@^27.0.2:
|
||||||
resolve "^1.20.0"
|
resolve "^1.20.0"
|
||||||
slash "^3.0.0"
|
slash "^3.0.0"
|
||||||
|
|
||||||
jest-runner@^27.0.3:
|
jest-runner@^27.0.4:
|
||||||
version "27.0.3"
|
version "27.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-27.0.3.tgz#d9747af3bee5a6ffaeb9e10b653263b780258b54"
|
resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-27.0.4.tgz#2787170a9509b792ae129794f6944d27d5d12a4f"
|
||||||
integrity sha512-zH23uIIh1ro1JCD7XX1bQ0bQwXEsBzLX2UJVE/AVLsk4YJRmTfyXIzzRzBWRdnMHHg1NWkJ4fGs7eFP15IqZpQ==
|
integrity sha512-NfmvSYLCsCJk2AG8Ar2NAh4PhsJJpO+/r+g4bKR5L/5jFzx/indUpnVBdrfDvuqhGLLAvrKJ9FM/Nt8o1dsqxg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@jest/console" "^27.0.2"
|
"@jest/console" "^27.0.2"
|
||||||
"@jest/environment" "^27.0.3"
|
"@jest/environment" "^27.0.3"
|
||||||
|
@ -8817,20 +8810,22 @@ jest-runner@^27.0.3:
|
||||||
exit "^0.1.2"
|
exit "^0.1.2"
|
||||||
graceful-fs "^4.2.4"
|
graceful-fs "^4.2.4"
|
||||||
jest-docblock "^27.0.1"
|
jest-docblock "^27.0.1"
|
||||||
|
jest-environment-jsdom "^27.0.3"
|
||||||
|
jest-environment-node "^27.0.3"
|
||||||
jest-haste-map "^27.0.2"
|
jest-haste-map "^27.0.2"
|
||||||
jest-leak-detector "^27.0.2"
|
jest-leak-detector "^27.0.2"
|
||||||
jest-message-util "^27.0.2"
|
jest-message-util "^27.0.2"
|
||||||
jest-resolve "^27.0.2"
|
jest-resolve "^27.0.4"
|
||||||
jest-runtime "^27.0.3"
|
jest-runtime "^27.0.4"
|
||||||
jest-util "^27.0.2"
|
jest-util "^27.0.2"
|
||||||
jest-worker "^27.0.2"
|
jest-worker "^27.0.2"
|
||||||
source-map-support "^0.5.6"
|
source-map-support "^0.5.6"
|
||||||
throat "^6.0.1"
|
throat "^6.0.1"
|
||||||
|
|
||||||
jest-runtime@^27.0.3:
|
jest-runtime@^27.0.4:
|
||||||
version "27.0.3"
|
version "27.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-27.0.3.tgz#32499c1047e5d953cfbb67fe790ab0167a614d28"
|
resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-27.0.4.tgz#2e4a6aa77cac32ac612dfe12768387a8aa15c2f0"
|
||||||
integrity sha512-k1Hl2pWWHBkSXdCggX2lyLRuDnnnmMlnJd+DPLb8LmmAeHW87WgGC6TplD377VxY3KQu73sklkhGUIdwFgsRVQ==
|
integrity sha512-voJB4xbAjS/qYPboV+e+gmg3jfvHJJY4CagFWBOM9dQKtlaiTjcpD2tWwla84Z7PtXSQPeIpXY0qksA9Dum29A==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@jest/console" "^27.0.2"
|
"@jest/console" "^27.0.2"
|
||||||
"@jest/environment" "^27.0.3"
|
"@jest/environment" "^27.0.3"
|
||||||
|
@ -8851,8 +8846,8 @@ jest-runtime@^27.0.3:
|
||||||
jest-message-util "^27.0.2"
|
jest-message-util "^27.0.2"
|
||||||
jest-mock "^27.0.3"
|
jest-mock "^27.0.3"
|
||||||
jest-regex-util "^27.0.1"
|
jest-regex-util "^27.0.1"
|
||||||
jest-resolve "^27.0.2"
|
jest-resolve "^27.0.4"
|
||||||
jest-snapshot "^27.0.2"
|
jest-snapshot "^27.0.4"
|
||||||
jest-util "^27.0.2"
|
jest-util "^27.0.2"
|
||||||
jest-validate "^27.0.2"
|
jest-validate "^27.0.2"
|
||||||
slash "^3.0.0"
|
slash "^3.0.0"
|
||||||
|
@ -8867,10 +8862,10 @@ jest-serializer@^27.0.1:
|
||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
graceful-fs "^4.2.4"
|
graceful-fs "^4.2.4"
|
||||||
|
|
||||||
jest-snapshot@^27.0.2:
|
jest-snapshot@^27.0.4:
|
||||||
version "27.0.2"
|
version "27.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-27.0.2.tgz#40c48dc6afd3cbc5d3d07c061f20fc10d94ca0cd"
|
resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-27.0.4.tgz#2b96e22ca90382b3e93bd0aae2ce4c78bf51fb5b"
|
||||||
integrity sha512-4RcgvZbPrrbEE/hT6XQ4hr+NVVLNrmsgUnYSnZRT6UAvW9Q2yzGMS+tfJh+xlQJAapnnkNJzsMn6vUa+yfiVHA==
|
integrity sha512-hnjrvpKGdSMvKfbHyaG5Kul7pDJGZvjVy0CKpzhu28MmAssDXS6GpynhXzgst1wBQoKD8c9b2VS2a5yhDLQRCA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/core" "^7.7.2"
|
"@babel/core" "^7.7.2"
|
||||||
"@babel/generator" "^7.7.2"
|
"@babel/generator" "^7.7.2"
|
||||||
|
@ -8891,7 +8886,7 @@ jest-snapshot@^27.0.2:
|
||||||
jest-haste-map "^27.0.2"
|
jest-haste-map "^27.0.2"
|
||||||
jest-matcher-utils "^27.0.2"
|
jest-matcher-utils "^27.0.2"
|
||||||
jest-message-util "^27.0.2"
|
jest-message-util "^27.0.2"
|
||||||
jest-resolve "^27.0.2"
|
jest-resolve "^27.0.4"
|
||||||
jest-util "^27.0.2"
|
jest-util "^27.0.2"
|
||||||
natural-compare "^1.4.0"
|
natural-compare "^1.4.0"
|
||||||
pretty-format "^27.0.2"
|
pretty-format "^27.0.2"
|
||||||
|
@ -8943,14 +8938,14 @@ jest-worker@^27.0.2:
|
||||||
merge-stream "^2.0.0"
|
merge-stream "^2.0.0"
|
||||||
supports-color "^8.0.0"
|
supports-color "^8.0.0"
|
||||||
|
|
||||||
jest@27.0.3:
|
jest@27.0.4:
|
||||||
version "27.0.3"
|
version "27.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/jest/-/jest-27.0.3.tgz#0b4ac738c93612f778d58250aee026220487e5a4"
|
resolved "https://registry.yarnpkg.com/jest/-/jest-27.0.4.tgz#91d4d564b36bcf93b98dac1ab19f07089e670f53"
|
||||||
integrity sha512-0G9+QqXFIZWgf5rs3yllpaA+13ZawVHfyuhuCV1EnoFbX++rVMRrYWCAnk+dfhwyv9/VTQvn+XG969u8aPRsBg==
|
integrity sha512-Px1iKFooXgGSkk1H8dJxxBIrM3tsc5SIuI4kfKYK2J+4rvCvPGr/cXktxh0e9zIPQ5g09kOMNfHQEmusBUf/ZA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@jest/core" "^27.0.3"
|
"@jest/core" "^27.0.4"
|
||||||
import-local "^3.0.2"
|
import-local "^3.0.2"
|
||||||
jest-cli "^27.0.3"
|
jest-cli "^27.0.4"
|
||||||
|
|
||||||
joi@^17.3.0:
|
joi@^17.3.0:
|
||||||
version "17.3.0"
|
version "17.3.0"
|
||||||
|
@ -11976,10 +11971,10 @@ sass-loader@10.2.0:
|
||||||
schema-utils "^3.0.0"
|
schema-utils "^3.0.0"
|
||||||
semver "^7.3.2"
|
semver "^7.3.2"
|
||||||
|
|
||||||
sass@1.34.0:
|
sass@1.34.1:
|
||||||
version "1.34.0"
|
version "1.34.1"
|
||||||
resolved "https://registry.yarnpkg.com/sass/-/sass-1.34.0.tgz#e46d5932d8b0ecc4feb846d861f26a578f7f7172"
|
resolved "https://registry.yarnpkg.com/sass/-/sass-1.34.1.tgz#30f45c606c483d47b634f1e7371e13ff773c96ef"
|
||||||
integrity sha512-rHEN0BscqjUYuomUEaqq3BMgsXqQfkcMVR7UhscsAVub0/spUrZGBMxQXFS2kfiDsPLZw5yuU9iJEFNC2x38Qw==
|
integrity sha512-scLA7EIZM+MmYlej6sdVr0HRbZX5caX5ofDT9asWnUJj21oqgsC+1LuNfm0eg+vM0fCTZHhwImTiCU0sx9h9CQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
chokidar ">=3.0.0 <4.0.0"
|
chokidar ">=3.0.0 <4.0.0"
|
||||||
|
|
||||||
|
@ -13690,10 +13685,10 @@ vue-style-loader@^4.1.0, vue-style-loader@^4.1.2:
|
||||||
hash-sum "^1.0.2"
|
hash-sum "^1.0.2"
|
||||||
loader-utils "^1.0.2"
|
loader-utils "^1.0.2"
|
||||||
|
|
||||||
vue-template-compiler@2.6.13:
|
vue-template-compiler@2.6.14:
|
||||||
version "2.6.13"
|
version "2.6.14"
|
||||||
resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.6.13.tgz#a735b8974e013ce829e7f77e08e4ee5aecbd3005"
|
resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.6.14.tgz#a2f0e7d985670d42c9c9ee0d044fed7690f4f763"
|
||||||
integrity sha512-latKAqpUjCkovB8XppW5gnZbSdYQzkf8pavsMBZYZrQcG6lAnj0EH4Ty7jMwAwFw5Cf4mybKBHlp1UTjnLPOWw==
|
integrity sha512-ODQS1SyMbjKoO1JBJZojSw6FE4qnh9rIpUZn2EUT86FKizx9uH5z6uXiIrm4/Nb/gwxTi/o17ZDEGWAXHvtC7g==
|
||||||
dependencies:
|
dependencies:
|
||||||
de-indent "^1.0.2"
|
de-indent "^1.0.2"
|
||||||
he "^1.1.0"
|
he "^1.1.0"
|
||||||
|
@ -13703,10 +13698,10 @@ vue-template-es2015-compiler@^1.9.0:
|
||||||
resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz#1ee3bc9a16ecbf5118be334bb15f9c46f82f5825"
|
resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz#1ee3bc9a16ecbf5118be334bb15f9c46f82f5825"
|
||||||
integrity sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==
|
integrity sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==
|
||||||
|
|
||||||
vue@2.6.13:
|
vue@2.6.14:
|
||||||
version "2.6.13"
|
version "2.6.14"
|
||||||
resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.13.tgz#94b2c1b31fddf1dfcc34f28ec848ba8f01ea4c5b"
|
resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.14.tgz#e51aa5250250d569a3fbad3a8a5a687d6036e235"
|
||||||
integrity sha512-O+pAdJkce1ooYS1XyoQtpBQr9An+Oys3w39rkqxukVO3ZD1ilYJkWBGoRuadiQEm2LLJnCL2utV4TMSf52ubjw==
|
integrity sha512-x2284lgYvjOMj3Za7kqzRcUSxBboHqtgRE2zlos1qWaOye5yUmHn42LB1250NJBLRwEcdrB0JRwyPTEPhfQjiQ==
|
||||||
|
|
||||||
vue@^2.6.11:
|
vue@^2.6.11:
|
||||||
version "2.6.11"
|
version "2.6.11"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user