feat: upgrade to packages for vue 3
- vue3-notification - vue-advanced-cropper 2 - vuedraggable 4 - vue-shortkey -> moved in repo
This commit is contained in:
parent
7c3c2945f8
commit
e779681905
10 changed files with 405 additions and 142 deletions
11
package.json
11
package.json
|
@ -14,6 +14,7 @@
|
||||||
"test:frontend": "cypress run"
|
"test:frontend": "cypress run"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@kyvg/vue3-notification": "2.3.3",
|
||||||
"@vue/compat": "3.2.14",
|
"@vue/compat": "3.2.14",
|
||||||
"browserslist": "4.17.1",
|
"browserslist": "4.17.1",
|
||||||
"bulma": "0.9.3",
|
"bulma": "0.9.3",
|
||||||
|
@ -29,14 +30,13 @@
|
||||||
"snake-case": "3.0.4",
|
"snake-case": "3.0.4",
|
||||||
"ufo": "0.7.9",
|
"ufo": "0.7.9",
|
||||||
"vue": "3.2.14",
|
"vue": "3.2.14",
|
||||||
"vue-advanced-cropper": "1.8.2",
|
"vue-advanced-cropper": "^2.6.3",
|
||||||
"vue-drag-resize": "1.5.4",
|
"vue-drag-resize": "^2.0.3",
|
||||||
"vue-easymde": "1.4.0",
|
"vue-easymde": "1.4.0",
|
||||||
"vue-flatpickr-component": "9.0.4",
|
"vue-flatpickr-component": "9.0.5",
|
||||||
"vue-i18n": "9.2.0-beta.6",
|
"vue-i18n": "9.2.0-beta.6",
|
||||||
"vue-router": "4.0.11",
|
"vue-router": "4.0.11",
|
||||||
"vue-shortkey": "3.1.7",
|
"vuedraggable": "4.0.1",
|
||||||
"vuedraggable": "2.24.3",
|
|
||||||
"vuex": "4.0.2",
|
"vuex": "4.0.2",
|
||||||
"workbox-precaching": "6.3.0"
|
"workbox-precaching": "6.3.0"
|
||||||
},
|
},
|
||||||
|
@ -70,7 +70,6 @@
|
||||||
"typescript": "4.4.3",
|
"typescript": "4.4.3",
|
||||||
"vite": "2.6.1",
|
"vite": "2.6.1",
|
||||||
"vite-plugin-pwa": "0.11.2",
|
"vite-plugin-pwa": "0.11.2",
|
||||||
"vue-notification": "1.3.20",
|
|
||||||
"wait-on": "6.0.0",
|
"wait-on": "6.0.0",
|
||||||
"workbox-cli": "6.3.0"
|
"workbox-cli": "6.3.0"
|
||||||
},
|
},
|
||||||
|
|
|
@ -91,17 +91,20 @@
|
||||||
@end="e => saveListPosition(e, nk)"
|
@end="e => saveListPosition(e, nk)"
|
||||||
handle=".handle"
|
handle=".handle"
|
||||||
:disabled="n.id < 0"
|
:disabled="n.id < 0"
|
||||||
:class="{'dragging-disabled': n.id < 0}"
|
tag="transition-group"
|
||||||
|
item-key="id"
|
||||||
|
:component-data="{
|
||||||
|
type: 'transition',
|
||||||
|
tag: 'ul',
|
||||||
|
name: !drag ? 'flip-list' : null,
|
||||||
|
class: [
|
||||||
|
'menu-list can-be-hidden',
|
||||||
|
{ 'dragging-disabled': n.id < 0 }
|
||||||
|
]
|
||||||
|
}"
|
||||||
>
|
>
|
||||||
<transition-group
|
<template #item="{element: l}">
|
||||||
type="transition"
|
|
||||||
:name="!drag ? 'flip-list' : null"
|
|
||||||
tag="ul"
|
|
||||||
class="menu-list can-be-hidden"
|
|
||||||
>
|
|
||||||
<li
|
<li
|
||||||
v-for="l in activeLists[nk]"
|
|
||||||
:key="l.id"
|
|
||||||
class="loader-container"
|
class="loader-container"
|
||||||
:class="{'is-loading': listUpdating[l.id]}"
|
:class="{'is-loading': listUpdating[l.id]}"
|
||||||
>
|
>
|
||||||
|
@ -140,7 +143,7 @@
|
||||||
<list-settings-dropdown :list="l" v-if="l.id > 0"/>
|
<list-settings-dropdown :list="l" v-if="l.id > 0"/>
|
||||||
<span class="list-setting-spacer" v-else></span>
|
<span class="list-setting-spacer" v-else></span>
|
||||||
</li>
|
</li>
|
||||||
</transition-group>
|
</template>
|
||||||
</draggable>
|
</draggable>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -86,9 +86,8 @@
|
||||||
:w="t.durationDays * dayWidth"
|
:w="t.durationDays * dayWidth"
|
||||||
:x="t.offsetDays * dayWidth - 6"
|
:x="t.offsetDays * dayWidth - 6"
|
||||||
:y="0"
|
:y="0"
|
||||||
@clicked="setTaskDragged(t)"
|
@dragstop="(e) => resizeTask(t, e)"
|
||||||
@dragstop="resizeTask"
|
@resizestop="(e) => resizeTask(t, e)"
|
||||||
@resizestop="resizeTask"
|
|
||||||
axis="x"
|
axis="x"
|
||||||
class="task"
|
class="task"
|
||||||
>
|
>
|
||||||
|
@ -136,9 +135,8 @@
|
||||||
:sticks="['mr', 'ml']"
|
:sticks="['mr', 'ml']"
|
||||||
:x="dayOffsetUntilToday * dayWidth - 6"
|
:x="dayOffsetUntilToday * dayWidth - 6"
|
||||||
:y="0"
|
:y="0"
|
||||||
@clicked="setTaskDragged(t)"
|
@dragstop="(e) => resizeTask(t, e)"
|
||||||
@dragstop="resizeTask"
|
@resizestop="(e) => resizeTask(t, e)"
|
||||||
@resizestop="resizeTask"
|
|
||||||
axis="x"
|
axis="x"
|
||||||
class="task nodate"
|
class="task nodate"
|
||||||
v-tooltip="$t('list.gantt.noDates')"
|
v-tooltip="$t('list.gantt.noDates')"
|
||||||
|
@ -233,7 +231,6 @@ export default {
|
||||||
theTasks: [], // Pretty much a copy of the prop, since we cant mutate the prop directly
|
theTasks: [], // Pretty much a copy of the prop, since we cant mutate the prop directly
|
||||||
tasksWithoutDates: [],
|
tasksWithoutDates: [],
|
||||||
taskService: new TaskService(),
|
taskService: new TaskService(),
|
||||||
taskDragged: null, // Saves to currently dragged task to be able to update it
|
|
||||||
fullWidth: 0,
|
fullWidth: 0,
|
||||||
now: new Date(),
|
now: new Date(),
|
||||||
dayOffsetUntilToday: 0,
|
dayOffsetUntilToday: 0,
|
||||||
|
@ -361,15 +358,14 @@ export default {
|
||||||
t.offsetDays = Math.floor((t.startDate - this.startDate) / 1000 / 60 / 60 / 24)
|
t.offsetDays = Math.floor((t.startDate - this.startDate) / 1000 / 60 / 60 / 24)
|
||||||
return t
|
return t
|
||||||
},
|
},
|
||||||
setTaskDragged(t) {
|
resizeTask(taskDragged, newRect) {
|
||||||
this.taskDragged = t
|
|
||||||
},
|
|
||||||
resizeTask(newRect) {
|
|
||||||
if (this.isTaskEdit) {
|
if (this.isTaskEdit) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const didntHaveDates = this.taskDragged.startDate === null ? true : false
|
let newTask = { ...taskDragged }
|
||||||
|
|
||||||
|
const didntHaveDates = newTask.startDate === null ? true : false
|
||||||
|
|
||||||
let startDate = new Date(this.startDate)
|
let startDate = new Date(this.startDate)
|
||||||
startDate.setDate(
|
startDate.setDate(
|
||||||
|
@ -379,32 +375,32 @@ export default {
|
||||||
startDate.setUTCMinutes(0)
|
startDate.setUTCMinutes(0)
|
||||||
startDate.setUTCSeconds(0)
|
startDate.setUTCSeconds(0)
|
||||||
startDate.setUTCMilliseconds(0)
|
startDate.setUTCMilliseconds(0)
|
||||||
this.taskDragged.startDate = startDate
|
newTask.startDate = startDate
|
||||||
let endDate = new Date(startDate)
|
let endDate = new Date(startDate)
|
||||||
endDate.setDate(
|
endDate.setDate(
|
||||||
startDate.getDate() + newRect.width / this.dayWidth,
|
startDate.getDate() + newRect.width / this.dayWidth,
|
||||||
)
|
)
|
||||||
this.taskDragged.startDate = startDate
|
newTask.startDate = startDate
|
||||||
this.taskDragged.endDate = endDate
|
newTask.endDate = endDate
|
||||||
|
|
||||||
// We take the task from the overall tasks array because the one in it has bad data after it was updated once.
|
// We take the task from the overall tasks array because the one in it has bad data after it was updated once.
|
||||||
// FIXME: This is a workaround. We should use a better mechanism to get the task or, even better,
|
// FIXME: This is a workaround. We should use a better mechanism to get the task or, even better,
|
||||||
// prevent it from containing outdated Data in the first place.
|
// prevent it from containing outdated Data in the first place.
|
||||||
for (const tt in this.theTasks) {
|
for (const tt in this.theTasks) {
|
||||||
if (this.theTasks[tt].id === this.taskDragged.id) {
|
if (this.theTasks[tt].id === newTask.id) {
|
||||||
this.taskDragged = this.theTasks[tt]
|
newTask = this.theTasks[tt]
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ganttData = {
|
const ganttData = {
|
||||||
endDate: this.taskDragged.endDate,
|
endDate: newTask.endDate,
|
||||||
durationDays: this.taskDragged.durationDays,
|
durationDays: newTask.durationDays,
|
||||||
offsetDays: this.taskDragged.offsetDays,
|
offsetDays: newTask.offsetDays,
|
||||||
}
|
}
|
||||||
|
|
||||||
this.taskService
|
this.taskService
|
||||||
.update(this.taskDragged)
|
.update(newTask)
|
||||||
.then(r => {
|
.then(r => {
|
||||||
r.endDate = ganttData.endDate
|
r.endDate = ganttData.endDate
|
||||||
r.durationDays = ganttData.durationDays
|
r.durationDays = ganttData.durationDays
|
||||||
|
|
36
src/main.ts
36
src/main.ts
|
@ -1,4 +1,11 @@
|
||||||
import { createApp } from 'vue'
|
import { createApp, configureCompat } from 'vue'
|
||||||
|
|
||||||
|
configureCompat({
|
||||||
|
COMPONENT_V_MODEL: false,
|
||||||
|
COMPONENT_ASYNC: false,
|
||||||
|
RENDER_FUNCTION: false,
|
||||||
|
WATCH_ARRAY: false, // TODO: check this again; this might lead to some problemes
|
||||||
|
})
|
||||||
|
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import router from './router'
|
import router from './router'
|
||||||
|
@ -18,13 +25,13 @@ import {VERSION} from './version.json'
|
||||||
// Add CSS
|
// Add CSS
|
||||||
import './styles/vikunja.scss'
|
import './styles/vikunja.scss'
|
||||||
// Notifications
|
// Notifications
|
||||||
import Notifications from 'vue-notification'
|
import Notifications from '@kyvg/vue3-notification'
|
||||||
|
|
||||||
// PWA
|
// PWA
|
||||||
import './registerServiceWorker'
|
import './registerServiceWorker'
|
||||||
|
|
||||||
// Shortcuts
|
// Shortcuts
|
||||||
// @ts-ignore - no types available
|
import shortkey from '@/plugins/shortkey'
|
||||||
import vueShortkey from 'vue-shortkey'
|
|
||||||
// Vuex
|
// Vuex
|
||||||
import {store} from './store'
|
import {store} from './store'
|
||||||
// i18n
|
// i18n
|
||||||
|
@ -45,19 +52,11 @@ if (window.API_URL.substr(window.API_URL.length - 1, window.API_URL.length) ===
|
||||||
|
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
|
|
||||||
Vue.use(Notifications)
|
app.use(Notifications)
|
||||||
|
|
||||||
|
|
||||||
Vue.use(vueShortkey, {prevent: ['input', 'textarea', '.input', '[contenteditable]']})
|
|
||||||
|
|
||||||
app.config.globalProperties.$message = {
|
app.use(shortkey, {prevent: ['input', 'textarea', '.input', '[contenteditable]']})
|
||||||
error(e, actions = []) {
|
|
||||||
return error(e, Vue.prototype, actions)
|
|
||||||
},
|
|
||||||
success(s, actions = []) {
|
|
||||||
return success(s, Vue.prototype, actions)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// directives
|
// directives
|
||||||
import focus from './directives/focus'
|
import focus from './directives/focus'
|
||||||
|
@ -92,6 +91,15 @@ app.mixin({
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
app.config.errorHandler = (err, vm, info) => {
|
||||||
|
error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
app.config.globalProperties.$message = {
|
||||||
|
error,
|
||||||
|
success,
|
||||||
|
}
|
||||||
|
|
||||||
app.use(router)
|
app.use(router)
|
||||||
app.use(store)
|
app.use(store)
|
||||||
app.use(i18n)
|
app.use(i18n)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import {i18n} from '@/i18n'
|
import {i18n} from '@/i18n'
|
||||||
|
import { notify } from '@kyvg/vue3-notification'
|
||||||
|
|
||||||
export const getErrorText = (r) => {
|
export const getErrorText = (r) => {
|
||||||
|
|
||||||
|
@ -27,8 +28,8 @@ export const getErrorText = (r) => {
|
||||||
return [r.message]
|
return [r.message]
|
||||||
}
|
}
|
||||||
|
|
||||||
export function error(e, context, actions = []) {
|
export function error(e, actions = []) {
|
||||||
context.$notify({
|
notify({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
title: i18n.global.t('error.error'),
|
title: i18n.global.t('error.error'),
|
||||||
text: getErrorText(e),
|
text: getErrorText(e),
|
||||||
|
@ -37,8 +38,8 @@ export function error(e, context, actions = []) {
|
||||||
console.error(e, actions)
|
console.error(e, actions)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function success(e, context, actions = []) {
|
export function success(e, actions = []) {
|
||||||
context.$notify({
|
notify({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
title: i18n.global.t('error.success'),
|
title: i18n.global.t('error.success'),
|
||||||
text: getErrorText(e),
|
text: getErrorText(e),
|
||||||
|
|
78
src/plugins/shortkey/helpers.js
Normal file
78
src/plugins/shortkey/helpers.js
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
function capitalizeFirstLetter(string) {
|
||||||
|
return string.charAt(0).toUpperCase() + string.slice(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
const MODIFIER_KEYS = ['shift', 'ctrl', 'meta', 'alt']
|
||||||
|
|
||||||
|
const SHORT_CUT_INDEX = [
|
||||||
|
{ key: 'ArrowUp', value: 'arrowup' },
|
||||||
|
{ key: 'ArrowLeft', value: 'arrowlef' },
|
||||||
|
{ key: 'ArrowRight', value: 'arrowright' },
|
||||||
|
{ key: 'ArrowDown', value: 'arrowdown' },
|
||||||
|
{ key: 'AltGraph', value: 'altgraph' },
|
||||||
|
{ key: 'Escape', value: 'esc' },
|
||||||
|
{ key: 'Enter', value: 'enter' },
|
||||||
|
{ key: 'Tab', value: 'tab' },
|
||||||
|
{ key: ' ', value: 'space' },
|
||||||
|
{ key: 'PageUp', value: 'pagup' },
|
||||||
|
{ key: 'PageDown', value: 'pagedow' },
|
||||||
|
{ key: 'Home', value: 'home' },
|
||||||
|
{ key: 'End', value: 'end' },
|
||||||
|
{ key: 'Delete', value: 'del' },
|
||||||
|
{ key: 'Backspace', value: 'bacspace' },
|
||||||
|
{ key: 'Insert', value: 'insert' },
|
||||||
|
{ key: 'NumLock', value: 'numlock' },
|
||||||
|
{ key: 'CapsLock', value: 'capslock' },
|
||||||
|
{ key: 'Pause', value: 'pause' },
|
||||||
|
{ key: 'ContextMenu', value: 'cotextmenu' },
|
||||||
|
{ key: 'ScrollLock', value: 'scrolllock' },
|
||||||
|
{ key: 'BrowserHome', value: 'browserhome' },
|
||||||
|
{ key: 'MediaSelect', value: 'mediaselect' },
|
||||||
|
]
|
||||||
|
|
||||||
|
export function encodeKey(pKey) {
|
||||||
|
const shortKey = {}
|
||||||
|
|
||||||
|
MODIFIER_KEYS.forEach((key) => {
|
||||||
|
shortKey[`${key}Key`] = pKey.includes(key)
|
||||||
|
})
|
||||||
|
|
||||||
|
let indexedKeys = createShortcutIndex(shortKey)
|
||||||
|
const vKey = pKey.filter(
|
||||||
|
(item) => !MODIFIER_KEYS.includes(item),
|
||||||
|
)
|
||||||
|
indexedKeys += vKey.join('')
|
||||||
|
return indexedKeys
|
||||||
|
}
|
||||||
|
|
||||||
|
function createShortcutIndex(pKey) {
|
||||||
|
let k = ''
|
||||||
|
|
||||||
|
MODIFIER_KEYS.forEach((key) => {
|
||||||
|
if (pKey.key === capitalizeFirstLetter(key) || pKey[`${key}Key`]) {
|
||||||
|
k += key
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
SHORT_CUT_INDEX.forEach(({ key, value }) => {
|
||||||
|
if (pKey.key === key) {
|
||||||
|
k += value
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (
|
||||||
|
(pKey.key && pKey.key !== ' ' && pKey.key.length === 1) ||
|
||||||
|
/F\d{1,2}|\//g.test(pKey.key)
|
||||||
|
) {
|
||||||
|
k += pKey.key.toLowerCase()
|
||||||
|
}
|
||||||
|
|
||||||
|
return k
|
||||||
|
}
|
||||||
|
export { createShortcutIndex as decodeKey }
|
||||||
|
|
||||||
|
export function parseValue(value) {
|
||||||
|
value = typeof value === 'string' ? JSON.parse(value.replace(/'/gi, '"')) : value
|
||||||
|
|
||||||
|
return value instanceof Array ? { '': value } : value
|
||||||
|
}
|
186
src/plugins/shortkey/index.js
Normal file
186
src/plugins/shortkey/index.js
Normal file
|
@ -0,0 +1,186 @@
|
||||||
|
import { parseValue, decodeKey, encodeKey } from './helpers'
|
||||||
|
|
||||||
|
let mapFunctions = {}
|
||||||
|
let objAvoided = []
|
||||||
|
let elementAvoided = []
|
||||||
|
let keyPressed = false
|
||||||
|
|
||||||
|
function dispatchShortkeyEvent(pKey) {
|
||||||
|
const e = new CustomEvent('shortkey', { bubbles: false })
|
||||||
|
|
||||||
|
if (mapFunctions[pKey].key) {
|
||||||
|
e.srcKey = mapFunctions[pKey].key
|
||||||
|
}
|
||||||
|
|
||||||
|
const elm = mapFunctions[pKey].el
|
||||||
|
|
||||||
|
if (!mapFunctions[pKey].propagte) {
|
||||||
|
elm[elm.length - 1].dispatchEvent(e)
|
||||||
|
} else {
|
||||||
|
elm.forEach((elmItem) => elmItem.dispatchEvent(e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function keyDown(pKey) {
|
||||||
|
if (
|
||||||
|
(!mapFunctions[pKey].once && !mapFunctions[pKey].push) ||
|
||||||
|
(mapFunctions[pKey].push && !keyPressed)
|
||||||
|
) {
|
||||||
|
dispatchShortkeyEvent(pKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function fillMappingFunctions(
|
||||||
|
mappingFunctions,
|
||||||
|
{ b, push, once, focus, propagte, el },
|
||||||
|
) {
|
||||||
|
for (let key in b) {
|
||||||
|
const k = encodeKey(b[key])
|
||||||
|
const propagated = mappingFunctions[k] && mappingFunctions[k].propagte
|
||||||
|
const elm =
|
||||||
|
mappingFunctions[k] && mappingFunctions[k].el
|
||||||
|
? mappingFunctions[k].el
|
||||||
|
: []
|
||||||
|
|
||||||
|
elm.push(el)
|
||||||
|
|
||||||
|
mappingFunctions[k] = {
|
||||||
|
push,
|
||||||
|
once,
|
||||||
|
focus,
|
||||||
|
key,
|
||||||
|
propagte: propagated || propagte,
|
||||||
|
el: elm,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function bindValue(value, el, binding, vnode) {
|
||||||
|
const { modifiers } = binding
|
||||||
|
const push = !!modifiers.push
|
||||||
|
const avoid = !!modifiers.avoid
|
||||||
|
const focus = !modifiers.focus
|
||||||
|
const once = !!modifiers.once
|
||||||
|
const propagte = !!modifiers.propagte
|
||||||
|
|
||||||
|
if (avoid) {
|
||||||
|
objAvoided = objAvoided.filter((itm) => !itm === el)
|
||||||
|
objAvoided.push(el)
|
||||||
|
} else {
|
||||||
|
fillMappingFunctions(mapFunctions, {
|
||||||
|
b: value,
|
||||||
|
push,
|
||||||
|
once,
|
||||||
|
focus,
|
||||||
|
propagte,
|
||||||
|
el: vnode.el,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function unbindValue(value, el) {
|
||||||
|
for (let key in value) {
|
||||||
|
const k = encodeKey(value[key])
|
||||||
|
const idxElm = mapFunctions[k].el.indexOf(el)
|
||||||
|
|
||||||
|
if (mapFunctions[k].el.length > 1 && idxElm > -1) {
|
||||||
|
mapFunctions[k].el.splice(idxElm, 1)
|
||||||
|
} else {
|
||||||
|
delete mapFunctions[k]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function availableElement(decodedKey) {
|
||||||
|
const objectIsAvoided = !!objAvoided.find(
|
||||||
|
(r) => r === document.activeElement,
|
||||||
|
)
|
||||||
|
const filterAvoided = !!elementAvoided.find(
|
||||||
|
(selector) =>
|
||||||
|
document.activeElement && document.activeElement.matches(selector),
|
||||||
|
)
|
||||||
|
return !!mapFunctions[decodedKey] && !(objectIsAvoided || filterAvoided)
|
||||||
|
}
|
||||||
|
|
||||||
|
function keyDownListener(pKey) {
|
||||||
|
const decodedKey = decodeKey(pKey)
|
||||||
|
|
||||||
|
// Check avoidable elements
|
||||||
|
if (!availableElement(decodedKey)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mapFunctions[decodedKey].propagte) {
|
||||||
|
pKey.preventDefault()
|
||||||
|
pKey.stopPropagation()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mapFunctions[decodedKey].focus) {
|
||||||
|
keyDown(decodedKey)
|
||||||
|
keyPressed = true
|
||||||
|
} else if (!keyPressed) {
|
||||||
|
const elm = mapFunctions[decodedKey].el
|
||||||
|
elm[elm.length - 1].focus()
|
||||||
|
keyPressed = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function keyUpListener(pKey) {
|
||||||
|
const decodedKey = decodeKey(pKey)
|
||||||
|
|
||||||
|
if (!availableElement(decodedKey)) {
|
||||||
|
keyPressed = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mapFunctions[decodedKey].propagte) {
|
||||||
|
pKey.preventDefault()
|
||||||
|
pKey.stopPropagation()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mapFunctions[decodedKey].once || mapFunctions[decodedKey].push) {
|
||||||
|
dispatchShortkeyEvent(decodedKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
keyPressed = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// register key presses that happen before mounting of directive
|
||||||
|
// if (process?.env?.NODE_ENV !== 'test') {
|
||||||
|
// (() => {
|
||||||
|
document.addEventListener('keydown', keyDownListener, true)
|
||||||
|
document.addEventListener('keyup', keyUpListener, true)
|
||||||
|
// })()
|
||||||
|
// }
|
||||||
|
|
||||||
|
function install(app, options) {
|
||||||
|
elementAvoided = [...(options && options.prevent ? options.prevent : [])]
|
||||||
|
|
||||||
|
app.directive('shortkey', {
|
||||||
|
beforeMount(el, binding, vnode) {
|
||||||
|
// Mapping the commands
|
||||||
|
const value = parseValue(binding.value)
|
||||||
|
bindValue(value, el, binding, vnode)
|
||||||
|
},
|
||||||
|
|
||||||
|
updated(el, binding, vnode) {
|
||||||
|
const oldValue = parseValue(binding.oldValue)
|
||||||
|
unbindValue(oldValue, el)
|
||||||
|
|
||||||
|
const newValue = parseValue(binding.value)
|
||||||
|
bindValue(newValue, el, binding, vnode)
|
||||||
|
},
|
||||||
|
|
||||||
|
unmounted(el, binding) {
|
||||||
|
const value = parseValue(binding.value)
|
||||||
|
unbindValue(value, el)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
install,
|
||||||
|
encodeKey,
|
||||||
|
decodeKey,
|
||||||
|
keyDown,
|
||||||
|
}
|
|
@ -27,17 +27,14 @@
|
||||||
group="buckets"
|
group="buckets"
|
||||||
:disabled="!canWrite"
|
:disabled="!canWrite"
|
||||||
:class="{'dragging-disabled': !canWrite}"
|
:class="{'dragging-disabled': !canWrite}"
|
||||||
|
tag="transition-group"
|
||||||
|
:item-key="({id}) => `bucket${id}`"
|
||||||
|
:component-data="bucketDraggableComponentData"
|
||||||
>
|
>
|
||||||
<transition-group
|
<template #item="{element: bucket, index: bucketIndex }">
|
||||||
type="transition"
|
|
||||||
:name="!dragBucket ? 'move-bucket': null"
|
|
||||||
tag="div"
|
|
||||||
class="kanban-bucket-container">
|
|
||||||
<div
|
<div
|
||||||
:key="`bucket${bucket.id}`"
|
|
||||||
class="bucket"
|
class="bucket"
|
||||||
:class="{'is-collapsed': collapsedBuckets[bucket.id]}"
|
:class="{'is-collapsed': collapsedBuckets[bucket.id]}"
|
||||||
v-for="(bucket, k) in buckets"
|
|
||||||
>
|
>
|
||||||
<div class="bucket-header" @click="() => unCollapseBucket(bucket)">
|
<div class="bucket-header" @click="() => unCollapseBucket(bucket)">
|
||||||
<span
|
<span
|
||||||
|
@ -136,16 +133,15 @@
|
||||||
:group="{name: 'tasks', put: shouldAcceptDrop(bucket) && !dragBucket}"
|
:group="{name: 'tasks', put: shouldAcceptDrop(bucket) && !dragBucket}"
|
||||||
:disabled="!canWrite"
|
:disabled="!canWrite"
|
||||||
:class="{'dragging-disabled': !canWrite}"
|
:class="{'dragging-disabled': !canWrite}"
|
||||||
:data-bucket-index="k"
|
:data-bucket-index="bucketIndex"
|
||||||
class="dropper"
|
class="dropper"
|
||||||
|
tag="transition-group"
|
||||||
|
:item-key="(task) => `bucket${bucket.id}-task${task.id}`"
|
||||||
|
:component-data="taskDraggableTaskComponentData"
|
||||||
>
|
>
|
||||||
<transition-group type="transition" :name="!drag ? 'move-card': null" tag="div">
|
<template #item="{element: task}">
|
||||||
<kanban-card
|
<kanban-card :task="task" />
|
||||||
:key="`bucket${bucket.id}-task${task.id}`"
|
</template>
|
||||||
v-for="task in bucket.tasks"
|
|
||||||
:task="task"
|
|
||||||
/>
|
|
||||||
</transition-group>
|
|
||||||
</draggable>
|
</draggable>
|
||||||
</div>
|
</div>
|
||||||
<div class="bucket-footer" v-if="canWrite">
|
<div class="bucket-footer" v-if="canWrite">
|
||||||
|
@ -181,7 +177,7 @@
|
||||||
</x-button>
|
</x-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</transition-group>
|
</template>
|
||||||
</draggable>
|
</draggable>
|
||||||
|
|
||||||
<div class="bucket new-bucket" v-if="canWrite && !loading && buckets.length > 0">
|
<div class="bucket new-bucket" v-if="canWrite && !loading && buckets.length > 0">
|
||||||
|
@ -251,6 +247,15 @@ import {getCollapsedBucketState, saveCollapsedBucketState} from '@/helpers/saveC
|
||||||
import {calculateItemPosition} from '../../../helpers/calculateItemPosition'
|
import {calculateItemPosition} from '../../../helpers/calculateItemPosition'
|
||||||
import KanbanCard from '../../../components/tasks/partials/kanban-card'
|
import KanbanCard from '../../../components/tasks/partials/kanban-card'
|
||||||
|
|
||||||
|
const DRAG_OPTIONS = {
|
||||||
|
// sortable options
|
||||||
|
animation: 150,
|
||||||
|
ghostClass: 'ghost',
|
||||||
|
dragClass: 'task-dragging',
|
||||||
|
delayOnTouchOnly: true,
|
||||||
|
delay: 150,
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Kanban',
|
name: 'Kanban',
|
||||||
components: {
|
components: {
|
||||||
|
@ -261,6 +266,8 @@ export default {
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
dragOptions: DRAG_OPTIONS,
|
||||||
|
|
||||||
drag: false,
|
drag: false,
|
||||||
dragBucket: false,
|
dragBucket: false,
|
||||||
sourceBucket: 0,
|
sourceBucket: 0,
|
||||||
|
@ -305,6 +312,21 @@ export default {
|
||||||
'$route.params.listId': 'loadBuckets',
|
'$route.params.listId': 'loadBuckets',
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
bucketDraggableComponentData() {
|
||||||
|
return {
|
||||||
|
type: 'transition',
|
||||||
|
tag: 'div',
|
||||||
|
name: !this.dragBucket ? 'move-bucket': null,
|
||||||
|
class: 'kanban-bucket-container',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
taskDraggableTaskComponentData() {
|
||||||
|
return {
|
||||||
|
type: 'transition',
|
||||||
|
tag: 'div',
|
||||||
|
name: !this.drag ? 'move-card': null,
|
||||||
|
}
|
||||||
|
},
|
||||||
buckets: {
|
buckets: {
|
||||||
get() {
|
get() {
|
||||||
return this.$store.state.kanban.buckets
|
return this.$store.state.kanban.buckets
|
||||||
|
@ -313,17 +335,6 @@ export default {
|
||||||
this.$store.commit('kanban/setBuckets', value)
|
this.$store.commit('kanban/setBuckets', value)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
dragOptions() {
|
|
||||||
const options = {
|
|
||||||
animation: 150,
|
|
||||||
ghostClass: 'ghost',
|
|
||||||
dragClass: 'task-dragging',
|
|
||||||
delay: 150,
|
|
||||||
delayOnTouchOnly: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
return options
|
|
||||||
},
|
|
||||||
...mapState({
|
...mapState({
|
||||||
loadedListId: state => state.kanban.listId,
|
loadedListId: state => state.kanban.listId,
|
||||||
loading: state => state[LOADING] && state[LOADING_MODULE] === 'kanban',
|
loading: state => state[LOADING] && state[LOADING_MODULE] === 'kanban',
|
||||||
|
|
|
@ -89,27 +89,28 @@
|
||||||
handle=".handle"
|
handle=".handle"
|
||||||
:disabled="!canWrite"
|
:disabled="!canWrite"
|
||||||
:class="{'dragging-disabled': !canWrite}"
|
:class="{'dragging-disabled': !canWrite}"
|
||||||
|
item-key="id"
|
||||||
>
|
>
|
||||||
<single-task-in-list
|
<template #item="{element: t}">
|
||||||
:show-list-color="false"
|
<single-task-in-list
|
||||||
:disabled="!canWrite"
|
:show-list-color="false"
|
||||||
:key="t.id"
|
:disabled="!canWrite"
|
||||||
:the-task="t"
|
:the-task="t"
|
||||||
@taskUpdated="updateTasks"
|
@taskUpdated="updateTasks"
|
||||||
task-detail-route="task.detail"
|
task-detail-route="task.detail"
|
||||||
v-for="t in tasks"
|
|
||||||
>
|
|
||||||
<span class="icon handle">
|
|
||||||
<icon icon="grip-lines"/>
|
|
||||||
</span>
|
|
||||||
<div
|
|
||||||
@click="editTask(t.id)"
|
|
||||||
class="icon settings"
|
|
||||||
v-if="!list.isArchived && canWrite"
|
|
||||||
>
|
>
|
||||||
<icon icon="pencil-alt"/>
|
<span class="icon handle">
|
||||||
</div>
|
<icon icon="grip-lines"/>
|
||||||
</single-task-in-list>
|
</span>
|
||||||
|
<div
|
||||||
|
@click="editTask(t.id)"
|
||||||
|
class="icon settings"
|
||||||
|
v-if="!list.isArchived && canWrite"
|
||||||
|
>
|
||||||
|
<icon icon="pencil-alt"/>
|
||||||
|
</div>
|
||||||
|
</single-task-in-list>
|
||||||
|
</template>
|
||||||
</draggable>
|
</draggable>
|
||||||
</div>
|
</div>
|
||||||
<card
|
<card
|
||||||
|
|
62
yarn.lock
62
yarn.lock
|
@ -1293,6 +1293,11 @@
|
||||||
"@types/yargs" "^16.0.0"
|
"@types/yargs" "^16.0.0"
|
||||||
chalk "^4.0.0"
|
chalk "^4.0.0"
|
||||||
|
|
||||||
|
"@kyvg/vue3-notification@2.3.3":
|
||||||
|
version "2.3.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@kyvg/vue3-notification/-/vue3-notification-2.3.3.tgz#7de890cbf000cf063da47bb49caa83bfb0350108"
|
||||||
|
integrity sha512-NxFejSs7FlaUzsPQ4jJyrB+UCFfsBUqICcQH70wHId52Hc9G9i0rBp2Wj3UsNj21H/HitP3r92rfz4ly2ImyMA==
|
||||||
|
|
||||||
"@nodelib/fs.scandir@2.1.5":
|
"@nodelib/fs.scandir@2.1.5":
|
||||||
version "2.1.5"
|
version "2.1.5"
|
||||||
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
|
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
|
||||||
|
@ -2807,11 +2812,6 @@ csstype@^2.6.8:
|
||||||
resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.17.tgz#4cf30eb87e1d1a005d8b6510f95292413f6a1c0e"
|
resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.17.tgz#4cf30eb87e1d1a005d8b6510f95292413f6a1c0e"
|
||||||
integrity sha512-u1wmTI1jJGzCJzWndZo8mk4wnPTZd1eOIYTYvuEyOQGfmDl3TrabCCfKnOC86FZwW/9djqTl933UF/cS425i9A==
|
integrity sha512-u1wmTI1jJGzCJzWndZo8mk4wnPTZd1eOIYTYvuEyOQGfmDl3TrabCCfKnOC86FZwW/9djqTl933UF/cS425i9A==
|
||||||
|
|
||||||
custom-event-polyfill@^1.0.7:
|
|
||||||
version "1.0.7"
|
|
||||||
resolved "https://registry.yarnpkg.com/custom-event-polyfill/-/custom-event-polyfill-1.0.7.tgz#9bc993ddda937c1a30ccd335614c6c58c4f87aee"
|
|
||||||
integrity sha512-TDDkd5DkaZxZFM8p+1I3yAlvM3rSr1wbrOliG4yJiwinMZN8z/iGL7BTlDkrJcYTmgUSb4ywVCc3ZaUtOtC76w==
|
|
||||||
|
|
||||||
cypress-file-upload@5.0.8:
|
cypress-file-upload@5.0.8:
|
||||||
version "5.0.8"
|
version "5.0.8"
|
||||||
resolved "https://registry.yarnpkg.com/cypress-file-upload/-/cypress-file-upload-5.0.8.tgz#d8824cbeaab798e44be8009769f9a6c9daa1b4a1"
|
resolved "https://registry.yarnpkg.com/cypress-file-upload/-/cypress-file-upload-5.0.8.tgz#d8824cbeaab798e44be8009769f9a6c9daa1b4a1"
|
||||||
|
@ -3096,11 +3096,6 @@ electron-to-chromium@^1.3.846:
|
||||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.846.tgz#a55fd59613dbcaed609e965e3e88f42b08c401d3"
|
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.846.tgz#a55fd59613dbcaed609e965e3e88f42b08c401d3"
|
||||||
integrity sha512-2jtSwgyiRzybHRxrc2nKI+39wH3AwQgn+sogQ+q814gv8hIFwrcZbV07Ea9f8AmK0ufPVZUvvAG1uZJ+obV4Jw==
|
integrity sha512-2jtSwgyiRzybHRxrc2nKI+39wH3AwQgn+sogQ+q814gv8hIFwrcZbV07Ea9f8AmK0ufPVZUvvAG1uZJ+obV4Jw==
|
||||||
|
|
||||||
element-matches@^0.1.2:
|
|
||||||
version "0.1.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/element-matches/-/element-matches-0.1.2.tgz#7345cb71e965bd2b12f725e524591c102198361a"
|
|
||||||
integrity sha512-yWh1otcs3OKUWDvu/IxyI36ZI3WNaRZlI0uG/DK6fu0pap0VYZ0J5pEGTk1zakme+hT0OKHwhlHc0N5TJhY6yQ==
|
|
||||||
|
|
||||||
emittery@^0.8.1:
|
emittery@^0.8.1:
|
||||||
version "0.8.1"
|
version "0.8.1"
|
||||||
resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.8.1.tgz#bb23cc86d03b30aa75a7f734819dee2e1ba70860"
|
resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.8.1.tgz#bb23cc86d03b30aa75a7f734819dee2e1ba70860"
|
||||||
|
@ -6907,21 +6902,19 @@ vite@2.6.1:
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents "~2.3.2"
|
fsevents "~2.3.2"
|
||||||
|
|
||||||
vue-advanced-cropper@1.8.2:
|
vue-advanced-cropper@^2.6.3:
|
||||||
version "1.8.2"
|
version "2.6.3"
|
||||||
resolved "https://registry.yarnpkg.com/vue-advanced-cropper/-/vue-advanced-cropper-1.8.2.tgz#c163e54584cd568e9fb2b63bc0fe08a58c060421"
|
resolved "https://registry.yarnpkg.com/vue-advanced-cropper/-/vue-advanced-cropper-2.6.3.tgz#3ec29584a53954f915a86e0f28069b79d7c29719"
|
||||||
integrity sha512-dngjbph+QbqLpk4DWCoCajWcThyy08NorFhMcmrnGFJvdxTFiuJ+XjOtrXhNpDdl7U6E/csrkx6i6E8V+BwmoQ==
|
integrity sha512-EWZ4dXnP7NpTNsCOlgGjUvBYtPtrWX+wMdW0w3PjwOk4UtQfvKz2IPYtIBzZqvxwUq0OIUq1K5y3VnCvs1DBDA==
|
||||||
dependencies:
|
dependencies:
|
||||||
classnames "^2.2.6"
|
classnames "^2.2.6"
|
||||||
debounce "^1.2.0"
|
debounce "^1.2.0"
|
||||||
easy-bem "^1.0.2"
|
easy-bem "^1.0.2"
|
||||||
|
|
||||||
vue-drag-resize@1.5.4, vue-drag-resize@^1.5.0-rc3:
|
vue-drag-resize@^2.0.3:
|
||||||
version "1.5.4"
|
version "2.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/vue-drag-resize/-/vue-drag-resize-1.5.4.tgz#f583f40f356e5792aa89109b3d13ba4407c25198"
|
resolved "https://registry.yarnpkg.com/vue-drag-resize/-/vue-drag-resize-2.0.3.tgz#1faf0813f43304205bb355fbb3dacc548dd9398a"
|
||||||
integrity sha512-SR3U7n6TAZEBgP7zw7bR9mjtAlYBjqIoaWTDPz5HXN/nYhOxKSA31aD7p71fmq1jtyt9reAnCx62valNL9ZAcg==
|
integrity sha512-5q03tZ/LyvQsg1iHRcqs+wI2OKNbNIWl9+7V8rVL6MxJhZLCIYSSgbAUaDE38LhD6dFd5aJhdgNmES61AxjXuw==
|
||||||
dependencies:
|
|
||||||
vue-drag-resize "^1.5.0-rc3"
|
|
||||||
|
|
||||||
vue-easymde@1.4.0:
|
vue-easymde@1.4.0:
|
||||||
version "1.4.0"
|
version "1.4.0"
|
||||||
|
@ -6944,10 +6937,10 @@ vue-eslint-parser@^7.0.0, vue-eslint-parser@^7.10.0:
|
||||||
lodash "^4.17.21"
|
lodash "^4.17.21"
|
||||||
semver "^6.3.0"
|
semver "^6.3.0"
|
||||||
|
|
||||||
vue-flatpickr-component@9.0.4:
|
vue-flatpickr-component@9.0.5:
|
||||||
version "9.0.4"
|
version "9.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/vue-flatpickr-component/-/vue-flatpickr-component-9.0.4.tgz#b064fffb11b0e351213434d2f6b2a291d753438c"
|
resolved "https://registry.yarnpkg.com/vue-flatpickr-component/-/vue-flatpickr-component-9.0.5.tgz#350ec73b7f3d7f80b050c170c088234f9c3bd14c"
|
||||||
integrity sha512-E8XfzLhrPsQBtZluWYEn3m21VHn7PArYnel3QPYL3auBrVMc07WaK6b20e04OK8LUCq9V+OKNZe4MoI0znY/Hw==
|
integrity sha512-fKuz/D4ePQKi+jPo4xjYRgBCLTWrTsCoKbx8nam63x4kTDtSqvFOjNwLvy0QgwC0lC+aFpUWa1dNYTH0hgUcCA==
|
||||||
dependencies:
|
dependencies:
|
||||||
flatpickr "^4.6.9"
|
flatpickr "^4.6.9"
|
||||||
|
|
||||||
|
@ -6961,11 +6954,6 @@ vue-i18n@9.2.0-beta.6:
|
||||||
"@intlify/vue-devtools" "9.2.0-beta.6"
|
"@intlify/vue-devtools" "9.2.0-beta.6"
|
||||||
"@vue/devtools-api" "^6.0.0-beta.13"
|
"@vue/devtools-api" "^6.0.0-beta.13"
|
||||||
|
|
||||||
vue-notification@1.3.20:
|
|
||||||
version "1.3.20"
|
|
||||||
resolved "https://registry.yarnpkg.com/vue-notification/-/vue-notification-1.3.20.tgz#d85618127763b46f3e25b8962b857947d5a97cbe"
|
|
||||||
integrity sha512-vPj67Ah72p8xvtyVE8emfadqVWguOScAjt6OJDEUdcW5hW189NsqvfkOrctxHUUO9UYl9cTbIkzAEcPnHu+zBQ==
|
|
||||||
|
|
||||||
vue-router@4.0.11:
|
vue-router@4.0.11:
|
||||||
version "4.0.11"
|
version "4.0.11"
|
||||||
resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-4.0.11.tgz#cd649a0941c635281763a20965b599643ddc68ed"
|
resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-4.0.11.tgz#cd649a0941c635281763a20965b599643ddc68ed"
|
||||||
|
@ -6973,14 +6961,6 @@ vue-router@4.0.11:
|
||||||
dependencies:
|
dependencies:
|
||||||
"@vue/devtools-api" "^6.0.0-beta.14"
|
"@vue/devtools-api" "^6.0.0-beta.14"
|
||||||
|
|
||||||
vue-shortkey@3.1.7:
|
|
||||||
version "3.1.7"
|
|
||||||
resolved "https://registry.yarnpkg.com/vue-shortkey/-/vue-shortkey-3.1.7.tgz#31c09a99ed597331a6a49a45eeff894a78a19eef"
|
|
||||||
integrity sha512-Wm/vPXXS+4Wl/LoYpD+cZc0J0HIoVlY8Ep0JLIqqswmAya3XUBtsqKbhzEf9sXo+3rZ5p1YsUyZfXas8XD7YjQ==
|
|
||||||
dependencies:
|
|
||||||
custom-event-polyfill "^1.0.7"
|
|
||||||
element-matches "^0.1.2"
|
|
||||||
|
|
||||||
vue@3.2.14:
|
vue@3.2.14:
|
||||||
version "3.2.14"
|
version "3.2.14"
|
||||||
resolved "https://registry.yarnpkg.com/vue/-/vue-3.2.14.tgz#da577433fb74f328ed58255c728a6a1bf196d337"
|
resolved "https://registry.yarnpkg.com/vue/-/vue-3.2.14.tgz#da577433fb74f328ed58255c728a6a1bf196d337"
|
||||||
|
@ -6992,10 +6972,10 @@ vue@3.2.14:
|
||||||
"@vue/server-renderer" "3.2.14"
|
"@vue/server-renderer" "3.2.14"
|
||||||
"@vue/shared" "3.2.14"
|
"@vue/shared" "3.2.14"
|
||||||
|
|
||||||
vuedraggable@2.24.3:
|
vuedraggable@4.0.1:
|
||||||
version "2.24.3"
|
version "4.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/vuedraggable/-/vuedraggable-2.24.3.tgz#43c93849b746a24ce503e123d5b259c701ba0d19"
|
resolved "https://registry.yarnpkg.com/vuedraggable/-/vuedraggable-4.0.1.tgz#3bcaab0808b7944030b7d9a29f9a63d59dfa12c5"
|
||||||
integrity sha512-6/HDXi92GzB+Hcs9fC6PAAozK1RLt1ewPTLjK0anTYguXLAeySDmcnqE8IC0xa7shvSzRjQXq3/+dsZ7ETGF3g==
|
integrity sha512-7qN5jhB1SLfx5P+HCm3JUW+pvgA1bSLgYLSVOeLWBDH9z+zbaEH0OlyZBVMLOxFR+JUHJjwDD0oy7T4r9TEgDA==
|
||||||
dependencies:
|
dependencies:
|
||||||
sortablejs "1.10.2"
|
sortablejs "1.10.2"
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue