Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
community
pount
pount-front
Commits
85b09001
Commit
85b09001
authored
Oct 12, 2021
by
Jean Rabreau
Browse files
🎨
update itemDuplicate action for partial copy into other set
parent
0564fc02
Changes
5
Hide whitespace changes
Inline
Side-by-side
src/i18n/en_US.js
View file @
85b09001
...
...
@@ -234,12 +234,15 @@ export const en_US = {
item
:
{
backToSet
:
"
Back to set
"
,
copy
:
{
toSet
:
"
Into
\"
{title}
\"
set
"
,
move
:
"
Move @:item.designate
"
,
duplicate
:
"
Create a copy
"
,
title
:
"
Copy @:item.designate
"
,
here
:
"
Copy here
"
,
inProject
:
"
Choose set
"
,
projectsLoad
:
"
Load other projets
"
projectsLoad
:
"
Load other projets
"
,
prefix
:
"
Copy of
"
,
},
copyOf
:
"
Copy of
"
,
count
:
"
No item | 1 item | {count} items
"
,
create
:
"
Add item
"
,
submitted
:
"
Submitted by:
"
,
...
...
src/i18n/fr_FR.js
View file @
85b09001
...
...
@@ -241,12 +241,15 @@ export const fr_FR = {
item
:
{
backToSet
:
"
Revenir à l'ensemble
"
,
copy
:
{
toSet
:
"
Vers le set
\"
{title}
\"
"
,
move
:
"
Déplacer @:item.designate
"
,
duplicate
:
"
Créer une copie
"
,
title
:
"
Copier @:item.designate
"
,
here
:
"
Copier ici
"
,
inProject
:
"
Choisir l'ensemble
"
,
projectsLoad
:
"
Charger les autres projets
"
projectsLoad
:
"
Charger les autres projets
"
,
prefix
:
"
Copie de
"
,
},
copyOf
:
"
Copie de
"
,
count
:
"
Aucun élément | 1 élément | {count} éléments
"
,
create
:
"
Nouvel élément
"
,
submitted
:
"
Déposé par :
"
,
...
...
src/store/item.js
View file @
85b09001
...
...
@@ -36,7 +36,7 @@ import {
* @typedef {Object} MetaData
* @property {string} id
* @property {string} name
* @property {string|string[]} value
* @property {string|string[]
|Array<string[]>
} value
* @property {boolean} multiple
* @property {boolean} isOption
* @property {boolean} repeatable
...
...
@@ -143,6 +143,7 @@ const Item = {
getters
:
{
current
:
state
=>
state
.
current
,
itemId
:
state
=>
state
.
current
.
id
,
set
:
state
=>
state
.
current
.
set
,
templateId
:
state
=>
state
.
current
.
set
.
templateId
,
projectId
:
state
=>
state
.
current
.
set
.
projectId
,
canEdit
:
state
=>
state
.
current
.
canEdit
,
...
...
@@ -334,20 +335,25 @@ const Item = {
* changing its title and resetting associated files
*
* @param context
* @param {Object} [target]
* @param {string} target.setId
* @param {Metadata} target.metadata
* @returns {Promise<void | *>}
*/
itemDuplicate
({
commit
,
dispatch
,
getters
})
{
const
{
title
:
oldTitle
,
description
,
metadata
,
set
:
{
id
:
setId
}}
=
getters
[
'
current
'
]
const
prefix
=
i18n
.
t
(
'
item.copyOf
'
)
const
title
=
`
${
prefix
}
${
oldTitle
}
`
itemDuplicate
({
commit
,
dispatch
,
getters
},
target
)
{
const
item
=
getters
[
'
current
'
]
const
{
title
:
oldTitle
,
description
}
=
item
const
setId
=
target
?
target
.
setId
:
item
.
set
.
id
const
metadata
=
target
?
target
.
metadata
:
item
.
metadata
.
map
(
d
=>
d
.
name
===
'
title
'
?
{
...
d
,
value
:
title
}
:
d
)
const
title
=
`
${
i18n
.
t
(
'
item.copyOf
'
)}${
oldTitle
}
`
const
payload
=
{
title
,
description
,
metadata
:
metadata
.
map
(
d
=>
d
.
name
===
'
title
'
?
{
...
d
,
value
:
title
}
:
d
),
metadata
,
viewer
:
{},
setId
,
}
...
...
src/store/project.js
View file @
85b09001
...
...
@@ -14,6 +14,7 @@ import {
* @property {string} id
* @property {string} title
* @property {SetCreator} creator
* @property {SetCreator} creator
*/
/**
...
...
src/views/items/ItemCopy.vue
View file @
85b09001
...
...
@@ -3,24 +3,32 @@
<v-card>
<v-card-title>
{{
$t
(
'
item.copy.title
'
)
}}
<v-spacer/>
<v-btn
tile
elevation=
"0"
@
click=
"copyHere"
>
<v-icon
color=
"secondary"
left
>
mdi-content-copy
</v-icon>
{{
$t
(
'
item.copy.here
'
)
}}
</v-btn>
</v-card-title>
<v-card-text>
<v-treeview
open-on-click
:open=
"openProjects"
:items=
"projectsTree"
:load-children=
"
addSets
"
:load-children=
"
extendTree
"
>
<template
v-slot:label=
"
{item}">
<p
v-if=
"item.level"
@
click=
"analyseForCopy(item.id, item.templateId)"
>
<p
v-if=
"item.level > 0"
@
click=
"analyseForCopy(item)"
>
<v-icon
left
color=
"secondary"
>
mdi-content-copy
</v-icon>
{{
item
.
title
}}
</p>
<p
v-else-if=
"item.id === 'next'"
@
click=
"addProjects"
>
{{
$t
(
'
item.copy.projectsLoad
'
)
}}
</p>
<p
v-else
>
{{
item
.
title
}}
</p>
...
...
@@ -28,26 +36,49 @@
</v-treeview>
</v-card-text>
<v-card-actions>
<v-btn
v-if=
"!setLoaded"
</v-card>
<v-dialog
v-model=
"analysis.displayed"
>
<v-card
v-if=
"analysis.set"
>
<v-card-title>
{{ $t('item.copy.toSet', {title: analysis.set.title})}}
</v-card-title>
<v-card-text>
<div
v-if=
"hasError"
>
</div>
</v-card-text>
<v-card-actions>
<v-btn
tile
elevation=
"0"
color=
"primary"
@
click=
"displayProjectSets"
>
{{ $t('item.copy.inProject')}}
</v-btn>
<v-btn
tile
elevation=
"0"
@
click=
"duplicate"
>
<v-icon
color=
"secondary"
left
>
mdi-content-copy
</v-icon>
{{ $t('item.copy.here' )}}
</v-btn>
</v-card-actions>
</v-card>
@
click=
"moveItem"
>
<v-icon
color=
"secondary"
left
>
mdi-file-move-outline
</v-icon>
{{ $t('item.copy.move' )}}
</v-btn>
<v-btn
tile
elevation=
"0"
@
click=
"remoteCopy"
>
<v-icon
color=
"secondary"
left
>
mdi-content-copy
</v-icon>
{{ $t('item.copy.duplicate' )}}
</v-btn>
<v-spacer/>
<v-btn
tile
elevation=
"0"
color=
"secondary"
@
click=
"analysis.displayed = false"
>
{{ $t('btn.cancel' )}}
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-sheet>
</template>
...
...
@@ -57,7 +88,7 @@ import {mapActions, mapGetters, mapState} from 'vuex'
/**
* @typedef {object} Analysis
* @property {
string
} set
Id
- targeted set
id
* @property {
ProjectSet | null
} set - targeted set
* @property {boolean} displayed - control modal display
* @property {AnalysisResult | null} result - result details
*/
...
...
@@ -68,8 +99,8 @@ import {mapActions, mapGetters, mapState} from 'vuex'
* @property {ResultDetail[]} option - fields that do no recognize item value as valid option
* @property {ResultDetail[]} tooManyValues - fields for which item value number exceed its limit
* @property {ResultDetail[]} ignoredFields - fields for which repeatable, multiple or isOption itemData mismatch
* @property {
ResultDetail
[]} missing - remaining item fields that have found no match in target
* @property {
ResultDetail[]} fields
- item metadata to be copied
* @property {
MetaData
[]} missing - remaining item fields that have found no match in target
* @property {
MetaData[]} metadata
- item metadata to be copied
*/
/**
...
...
@@ -97,7 +128,7 @@ export default {
* @type Analysis
*/
analysis
:
{
set
Id
:
''
,
set
:
null
,
displayed
:
false
,
result
:
null
},
...
...
@@ -107,7 +138,11 @@ export default {
}
},
computed
:
{
...
mapGetters
(
'
item
'
,
[
'
metadata
'
,
'
projectId
'
,
'
templateId
'
]),
...
mapGetters
(
'
item
'
,
{
itemSet
:
'
set
'
,
itemProjectId
:
'
projectId
'
,
itemMetadata
:
'
metadata
'
}),
...
mapState
(
'
set
'
,
[
'
projectSets
'
]),
...
mapGetters
(
'
template
'
,
[
'
inputFields
'
]),
...
mapGetters
(
'
project
'
,
...
...
@@ -115,129 +150,165 @@ export default {
currentProject
:
'
current
'
,
managedProjects
:
'
contributions
'
}),
hasError
()
{
const
results
=
this
.
analysis
.
result
return
results
&&
!!
results
.
required
.
length
&&
!!
results
.
tooManyValues
.
filter
(
r
=>
r
.
field
.
required
).
length
},
hasWarning
()
{
return
this
.
analysis
.
result
&&
!!
this
.
analysis
.
result
.
required
.
length
},
},
created
()
{
this
.
initSetsTree
()
},
methods
:
{
...
mapActions
(
'
item
'
,
[
'
itemDuplicate
'
]),
...
mapActions
(
'
item
'
,
[
'
itemDuplicate
'
,
'
itemUpdate
'
]),
...
mapActions
(
'
project
'
,
[
'
loadProject
'
,
'
retrieveProjects
'
]),
...
mapActions
(
'
set
'
,
[
'
loadProjectSets
'
]),
...
mapActions
(
'
template
'
,
[
'
loadTemplate
'
,
'
loadProjectTemplates
'
]),
async
analyseForCopy
(
targetedSetId
,
targetedTemplateId
)
{
await
this
.
loadTemplate
(
targetedTemplateId
)
this
.
analysis
.
result
=
this
.
inputFields
.
reduce
((
result
,
field
)
=>
{
const
itemFields
=
result
.
missing
const
itemDataIndex
=
itemFields
.
findIndex
(
f
=>
f
.
name
===
field
.
name
)
if
(
itemDataIndex
===
-
1
)
{
if
(
field
.
required
)
{
result
.
required
.
push
(
field
)
}
}
else
{
const
itemData
=
itemFields
[
itemDataIndex
]
if
(
itemData
.
repeatable
===
!!
field
.
repeatable
&&
itemData
.
multiple
===
!!
field
.
multiple
&&
itemData
.
isOption
===
!!
field
.
options
)
{
let
error
=
false
const
itemValue
=
Array
.
isArray
(
itemData
)
?
itemData
.
value
:
[
itemData
.
value
]
if
(
itemData
.
isOption
)
{
let
unknownOptions
if
(
field
.
repeatable
&&
field
.
multiple
)
{
async
analyseForCopy
(
set
)
{
if
(
set
.
id
!==
this
.
analysis
.
set
.
id
)
{
await
this
.
loadTemplate
(
set
.
templateId
)
this
.
analysis
.
result
=
this
.
inputFields
.
reduce
((
result
,
field
)
=>
{
const
itemFields
=
result
.
missing
const
itemDataIndex
=
itemFields
.
findIndex
(
f
=>
f
.
name
===
field
.
name
)
if
(
itemDataIndex
===
-
1
)
{
if
(
field
.
required
)
{
result
.
required
.
push
(
field
)
}
}
else
{
const
itemData
=
itemFields
[
itemDataIndex
]
if
(
itemData
.
repeatable
===
!!
field
.
repeatable
&&
itemData
.
multiple
===
!!
field
.
multiple
&&
itemData
.
isOption
===
!!
field
.
options
)
{
let
error
=
false
const
itemValue
=
Array
.
isArray
(
itemData
)
?
itemData
.
value
:
[
itemData
.
value
]
if
(
itemData
.
isOption
)
{
let
unknownOptions
if
(
field
.
repeatable
&&
field
.
multiple
)
{
unknownOptions
=
itemValue
.
reduce
((
options
,
valueSet
)
=>
{
return
[
...
options
,
...
valueSet
.
filter
(
v
=>
field
.
options
.
every
(
o
=>
o
.
value
!==
v
))
]
},
[])
}
else
{
unknownOptions
=
itemValue
.
filter
(
v
=>
field
.
options
.
every
(
o
=>
o
.
value
!==
v
))
}
else
{
unknownOptions
=
itemValue
.
filter
(
v
=>
field
.
options
.
every
(
o
=>
o
.
value
!==
v
))
}
if
(
unknownOptions
.
length
)
{
error
=
true
result
.
option
.
push
({
field
,
unknownOptions
})
}
}
if
(
unknownOptions
.
length
)
{
if
(
field
.
repeatable
&&
itemValue
.
length
>
field
.
maxRepeat
+
1
)
{
error
=
true
result
.
option
.
push
({
field
,
unknownOptions
})
result
.
tooManyValues
.
push
({
field
,
itemValue
})
}
result
.
missing
.
splice
(
itemDataIndex
,
1
)
if
(
!
error
)
{
result
.
metadata
.
push
(
itemData
)
}
}
else
{
result
.
ignoredFields
.
push
({
field
})
}
if
(
field
.
repeatable
&&
itemValue
.
length
>
field
.
maxRepeat
+
1
)
{
error
=
true
result
.
tooManyValues
.
push
({
field
,
itemValue
})
}
result
.
missing
.
splice
(
itemDataIndex
,
1
)
if
(
!
error
)
{
result
.
fields
.
push
(
itemData
)
}
}
else
{
result
.
ignoredFields
.
push
({
field
})
}
}
//
} else if (field.options) {
//
const itemValue = itemFields[itemValueIndex].value
//
if (
!Array.isArray(
itemValue)) {
//
if (field.options.every(o => o.value !==
itemValue
)) {
//
result.option.push({...field, itemValue: [itemValue]})
//
} else {
//
const [matchingField] = result.missing.splice(itemValueIndex, 1)
//
// le
t
value
= itemValue
//
// single value to comply to repeatable or multiple field
//
if (field.repeatable) {
//
value = [val
ue
]
//
matchingField.repeatable = true
//
}
//
if (field.multiple) {
//
value = [val
ue
]
//
matchingField.multiple = true
//
}
//
result.fields.push({...matchingField, value, isOption: true})
//
}
//
} else
if (field.
multip
le) {
//
if (field.repeatable) {
//
const
value
sMatch = itemValue.every(
// value
=> Array.isArray(value
)
//
&& value.every(v => field.options.every(o => o.value === v)
)
//
)
//
} else {
//
//
}
//
} else if (field.repeatable) {
//
const
unknownOptions
= itemValue.filter(v => field.options.every(o => o.value !== v))
//
if (
unknownOptions
.length) {
//
result.option.push({...field, unknownOptions})
//
} else {
//
const [matchingField] = result.missing.splice(itemValueIndex, 1)
//
//
}
//
} else {
//
result.tooManyValues.push({...field, itemValue})
//
}
// }
return
result
},
{
required
:
[],
option
:
[],
tooManyValue
s
:
[],
ignoredFields
:
[],
missing
:
this
.
metadata
.
map
(
m
=>
({...
m
})),
// remaining item fields have found no match in target
fields
:
[]
// received item metadata to be posted
})
this
.
analysis
.
targetedSet
=
targetedSetId
// } else if (field.optioncopyItems) {
//
const itemValue = itemFields[itemValueIndex].value
//
if (!Array.isArray(itemValue)) {
//
if (
field.options.every(o => o.value !==
itemValue)) {
//
result.option.push({...field, itemValue: [
itemValue
]})
//
} else {
//
const [matchingField] = result.missing.splice(itemValueIndex, 1)
//
// let value = itemValue
//
// sing
le value
to comply to repeatable or multiple field
//
if (field.repeatable) {
//
value = [value]
//
matchingField.repeatable = tr
ue
//
}
//
if (field.multiple) {
//
value = [value]
//
matchingField.multiple = tr
ue
//
}
//
result.fields.push({...matchingField, value, isOption: true})
//
}
//
} else if (field.multiple) {
//
if (field.
repeatab
le) {
//
const valuesMatch = itemValue.every(
//
value
=> Array.isArray(value)
//
&&
value
.every(v => field.options.every(o => o.value === v)
)
// )
//
} else {
//
// }
//
} else if (field.repeatable) {
//
const unknownOptions = itemValue.filter(v => field.options.every(o => o.value !== v))
//
if (
unknownOptions
.length) {
//
result.option.push({...field,
unknownOptions
})
//
} else {
//
const [matchingField] = result.missing.splice(itemValueIndex, 1)
//
// }
//
} else {
//
result.tooManyValues.push({...field, itemValue})
//
}
//
}
return
result
},
{
required
:
[],
option
:
[],
tooManyValues
:
[],
ignoredField
s
:
[],
missing
:
this
.
itemMetadata
.
map
(
m
=>
({...
m
})),
// remaining item fields have found no match in target
metadata
:
[]
})
this
.
analysis
.
set
=
set
}
this
.
analysis
.
displayed
=
true
},
async
duplicat
e
()
{
async
copyHer
e
()
{
await
this
.
itemDuplicate
()
this
.
$router
.
push
({
name
:
'
itemMetadata
'
,
params
:
{
itemId
:
this
.
item
.
i
d
}
params
:
{
itemId
:
this
.
item
I
d
}
})
},
async
displayProjectSets
()
{
if
(
this
.
projectId
!==
this
.
currentProject
.
id
)
{
await
this
.
loadProject
(
this
.
projectId
)
async
remoteCopy
()
{
await
this
.
itemDuplicate
({
setId
:
this
.
analysis
.
set
.
id
,
metadata
:
this
.
analysis
.
result
.
metadata
})
this
.
$router
.
push
({
name
:
'
itemMetadata
'
,
params
:
{
itemId
:
this
.
itemId
}
})
},
async
moveItem
()
{
const
{
setId
,
result
:
{
metadata
}}
=
this
.
analysis
await
this
.
itemUpdate
({
setId
,
metadata
})
this
.
analysis
.
displayed
=
false
this
.
$router
.
push
({
name
:
'
itemMetadata
'
,
params
:
{
itemId
:
this
.
itemId
}
})
},
async
initSetsTree
()
{
if
(
this
.
itemProjectId
!==
this
.
currentProject
.
id
)
{
await
this
.
loadProject
(
this
.
itemProjectId
)
}
await
this
.
loadProjectSets
({
size
:
0
})
this
.
projectsTree
=
[
{
id
:
this
.
p
rojectId
,
id
:
this
.
itemP
rojectId
,
title
:
this
.
currentProject
.
name
,
level
:
0
,
children
:
this
.
projectSets
.
map
(
...
...
@@ -249,31 +320,35 @@ export default {
}))
},
{
id
:
"
next
"
,
level
:
0
,
id
:
"
projects__loader
"
,
title
:
this
.
$t
(
'
item.copy.projectsLoad
'
),
level
:
-
1
,
children
:
[]
}
]
this
.
openProjects
=
[
this
.
p
rojectId
]
this
.
openProjects
=
[
this
.
itemP
rojectId
]
this
.
setLoaded
=
true
},
async
addProjects
()
{
await
this
.
retrieveProjects
({
manageOnly
:
true
,
size
:
0
})
const
otherManagedProjects
=
this
.
managedProjects
.
reduce
(
(
others
,
currentProject
)
=>
{
if
(
currentProject
.
id
!==
this
.
projectId
)
{
others
.
push
({
id
:
currentProject
.
id
,
title
:
currentProject
.
name
,
children
:
[],
})
}
return
others
},
[])
this
.
projectsTree
.
splice
(
1
,
1
,
...
otherManagedProjects
)
},
async
addSets
(
project
)
{
await
this
.
loadProjectSets
({
projectId
:
project
.
id
,
size
:
0
})
project
.
children
=
this
.
projectSets
.
map
(
s
=>
({
level
:
1
,
...
s
}))
async
extendTree
(
item
)
{
if
(
item
.
level
)
{
// loads other managed projects
await
this
.
retrieveProjects
({
manageOnly
:
true
,
size
:
0
})
const
otherManagedProjects
=
this
.
managedProjects
.
reduce
(
(
others
,
currentProject
)
=>
{
if
(
currentProject
.
id
!==
this
.
itemProjectId
)
{
others
.
push
({
id
:
currentProject
.
id
,
title
:
currentProject
.
name
,
children
:
[],
})
}
return
others
},
[])
this
.
projectsTree
.
splice
(
1
,
1
,
...
otherManagedProjects
)
}
else
{
// loads project sets
await
this
.
loadProjectSets
({
projectId
:
item
.
id
,
size
:
0
})
item
.
children
=
this
.
projectSets
.
map
(
s
=>
({
level
:
1
,
...
s
}))
}
},
onPagination
(
pagination
){
this
.
loadProjectSets
({
page
:
pagination
.
page
,
size
:
pagination
.
itemsPerPage
});
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment