mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-30 12:15:51 +00:00
Cards fixes (#8186)
This commit is contained in:
parent
92273f548b
commit
a89f75ae9f
@ -16,13 +16,12 @@ import {
|
||||
CardEvents,
|
||||
cardId,
|
||||
DOMAIN_CARD,
|
||||
type ParentInfo,
|
||||
type Card,
|
||||
type MasterTag,
|
||||
type ParentInfo,
|
||||
type Tag
|
||||
} from '@hcengineering/card'
|
||||
import chunter from '@hcengineering/chunter'
|
||||
import contact from '@hcengineering/contact'
|
||||
import core, {
|
||||
AccountRole,
|
||||
DOMAIN_MODEL,
|
||||
@ -368,8 +367,7 @@ export function createModel (builder: Builder): void {
|
||||
name: 'tagrelation',
|
||||
label: card.string.TagRelations,
|
||||
icon: setting.icon.Relations,
|
||||
props: { _classes: [card.class.Card, contact.class.Contact], exclude: [] },
|
||||
component: setting.component.RelationSetting,
|
||||
component: card.component.RelationSetting,
|
||||
group: 'settings-editor',
|
||||
role: AccountRole.Maintainer,
|
||||
order: 4501
|
||||
@ -381,7 +379,7 @@ export function createModel (builder: Builder): void {
|
||||
setting.class.SettingsCategory,
|
||||
core.space.Model,
|
||||
{
|
||||
name: 'masterTags',
|
||||
name: 'types',
|
||||
label: card.string.MasterTags,
|
||||
icon: card.icon.Card,
|
||||
component: card.component.ManageMasterTagsContent,
|
||||
|
@ -77,12 +77,11 @@ export function createModel (builder: Builder): void {
|
||||
})
|
||||
|
||||
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
|
||||
trigger: serverCard.trigger.OnCardParentChange,
|
||||
trigger: serverCard.trigger.OnCardUpdate,
|
||||
isAsync: true,
|
||||
txMatch: {
|
||||
_class: core.class.TxUpdateDoc,
|
||||
objectClass: card.class.Card,
|
||||
operations: { parent: { $exists: true } }
|
||||
objectClass: card.class.Card
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -5,10 +5,10 @@
|
||||
"Cards": "Karten",
|
||||
"Content": "Inhalt",
|
||||
"CreateCard": "Karte erstellen",
|
||||
"CreateMasterTag": "Master-Tag erstellen",
|
||||
"CreateMasterTag": "Typ erstellen",
|
||||
"CreateTag": "Tag erstellen",
|
||||
"MasterTag": "Master-Tag",
|
||||
"MasterTags": "Master-Tags",
|
||||
"MasterTag": "Typ",
|
||||
"MasterTags": "Typen",
|
||||
"Parent": "Eltern",
|
||||
"Tags": "Tags",
|
||||
"Tag": "Tag",
|
||||
@ -18,11 +18,11 @@
|
||||
"TagRelations": "Tag-Beziehungen",
|
||||
"DeleteTag": "Tag löschen",
|
||||
"DeleteTagConfirm": "Möchten Sie diesen Tag wirklich löschen? Alle zugehörigen Eigenschaften werden gelöscht",
|
||||
"DeleteMasterTag": "Master-Tag löschen",
|
||||
"DeleteMasterTagConfirm": "Möchten Sie diesen Master-Tag wirklich löschen? Alle mit diesem Master-Tag verbundenen Objekte werden gelöscht",
|
||||
"DeleteMasterTag": "Typ löschen",
|
||||
"DeleteMasterTagConfirm": "Möchten Sie diesen Typ wirklich löschen? Alle mit diesem Typ verbundenen Objekte werden gelöscht",
|
||||
"UnsetParent": "Elternteil entfernen",
|
||||
"SetParent": "Elternteil setzen",
|
||||
"CreateChild": "Kind erstellen",
|
||||
"Children": "Kinder"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -40,6 +40,9 @@
|
||||
{:else if value}
|
||||
{#if type === 'link'}
|
||||
<div class="flex-row-center">
|
||||
{#if showParent}
|
||||
<ParentNamesPresenter {value} />
|
||||
{/if}
|
||||
<DocNavLink
|
||||
object={value}
|
||||
{onClick}
|
||||
@ -58,9 +61,6 @@
|
||||
{/if}
|
||||
<span class="overflow-label" class:select-text={!noSelect} title={value?.title}>
|
||||
{value.title}
|
||||
{#if showParent}
|
||||
<ParentNamesPresenter {value} />
|
||||
{/if}
|
||||
<slot name="details" />
|
||||
</span>
|
||||
</span>
|
||||
|
@ -74,7 +74,7 @@
|
||||
ev.stopPropagation()
|
||||
const loc = getCurrentResolvedLocation()
|
||||
loc.path[2] = settingId
|
||||
loc.path[3] = 'masterTags'
|
||||
loc.path[3] = 'types'
|
||||
loc.path[4] = value._class
|
||||
loc.path.length = 5
|
||||
loc.fragment = undefined
|
||||
|
@ -72,7 +72,7 @@
|
||||
&:active {
|
||||
color: var(--theme-content-color);
|
||||
}
|
||||
&::before {
|
||||
&::after {
|
||||
content: '›';
|
||||
padding: 0 0.25rem;
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Card } from '@hcengineering/card'
|
||||
import { FindOptions, SortingOrder } from '@hcengineering/core'
|
||||
import { Doc, FindOptions, SortingOrder } from '@hcengineering/core'
|
||||
import { ObjectPopup, getClient } from '@hcengineering/presentation'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import card from '../plugin'
|
||||
@ -48,6 +48,13 @@
|
||||
|
||||
$: selected = !Array.isArray(value) ? value.parent ?? undefined : undefined
|
||||
$: ignoreObjects = !Array.isArray(value) ? [value._id] : undefined
|
||||
|
||||
$: cards = new Set(Array.isArray(value) ? value.map((p) => p._id) : [value._id])
|
||||
|
||||
const filter = (it: Doc): boolean => {
|
||||
const card = it as Card
|
||||
return !card.parentInfo.some((p) => cards.has(p._id))
|
||||
}
|
||||
</script>
|
||||
|
||||
<ObjectPopup
|
||||
@ -59,6 +66,7 @@
|
||||
allowDeselect={true}
|
||||
placeholder={card.string.SetParent}
|
||||
create={undefined}
|
||||
{filter}
|
||||
{ignoreObjects}
|
||||
shadows={true}
|
||||
{width}
|
||||
|
@ -81,7 +81,7 @@
|
||||
ev.stopPropagation()
|
||||
const loc = getCurrentResolvedLocation()
|
||||
loc.path[2] = settingId
|
||||
loc.path[3] = 'masterTags'
|
||||
loc.path[3] = 'types'
|
||||
loc.path[4] = tag._id
|
||||
loc.path.length = 5
|
||||
loc.fragment = undefined
|
||||
|
@ -17,7 +17,7 @@
|
||||
import { Class, Doc, Ref } from '@hcengineering/core'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { NavItem } from '@hcengineering/ui'
|
||||
import { NavLink, showMenu } from '@hcengineering/view-resources'
|
||||
import { NavLink } from '@hcengineering/view-resources'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import card from '../plugin'
|
||||
|
||||
@ -67,9 +67,6 @@
|
||||
on:click={() => {
|
||||
dispatch('select', clazz._id)
|
||||
}}
|
||||
on:contextmenu={(evt) => {
|
||||
showMenu(evt, { object: clazz })
|
||||
}}
|
||||
/>
|
||||
</NavLink>
|
||||
{#if (descendants.get(clazz._id)?.length ?? 0) > 0}
|
||||
|
@ -0,0 +1,17 @@
|
||||
<script lang="ts">
|
||||
import contact from '@hcengineering/contact'
|
||||
import { Class, Doc, Ref } from '@hcengineering/core'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { CreateRelation } from '@hcengineering/setting-resources'
|
||||
import card from '../../plugin'
|
||||
|
||||
export let aClass: Ref<Class<Doc>> | undefined = undefined
|
||||
|
||||
const client = getClient()
|
||||
const hierarchy = client.getHierarchy()
|
||||
const _classes = [...hierarchy.getDescendants(card.class.Card), contact.class.Contact].filter(
|
||||
(c) => c !== card.class.Card
|
||||
)
|
||||
</script>
|
||||
|
||||
<CreateRelation {aClass} {_classes} exclude={[]} on:close />
|
@ -35,7 +35,7 @@
|
||||
onDestroy(resolvedLocationStore.subscribe(handleLocationChanged))
|
||||
|
||||
function handleLocationChanged ({ path }: Location): void {
|
||||
if (path[3] !== 'masterTags' || path[4] === undefined) {
|
||||
if (path[3] !== 'types' || path[4] === undefined) {
|
||||
selectedTagId = undefined
|
||||
} else {
|
||||
selectedTagId = path[4] as Ref<MasterTag>
|
||||
|
@ -0,0 +1,14 @@
|
||||
<script lang="ts">
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { RelationSetting } from '@hcengineering/setting-resources'
|
||||
import contact from '@hcengineering/contact'
|
||||
import card from '../../plugin'
|
||||
|
||||
const client = getClient()
|
||||
const hierarchy = client.getHierarchy()
|
||||
const _classes = [...hierarchy.getDescendants(card.class.Card), contact.class.Contact].filter(
|
||||
(c) => c !== card.class.Card
|
||||
)
|
||||
</script>
|
||||
|
||||
<RelationSetting {_classes} exclude={[]} />
|
@ -13,8 +13,7 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import card, { MasterTag } from '@hcengineering/card'
|
||||
import contact from '@hcengineering/contact'
|
||||
import { MasterTag } from '@hcengineering/card'
|
||||
import core, { Association, Class, Doc, Ref } from '@hcengineering/core'
|
||||
import { IntlString } from '@hcengineering/platform'
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
@ -22,6 +21,7 @@
|
||||
import { clearSettingsStore, settingsStore } from '@hcengineering/setting-resources'
|
||||
import { ButtonIcon, Icon, IconAdd, Label, showPopup } from '@hcengineering/ui'
|
||||
import { onDestroy } from 'svelte'
|
||||
import CreateRelation from './CreateRelation.svelte'
|
||||
|
||||
export let masterTag: MasterTag
|
||||
|
||||
@ -49,10 +49,8 @@
|
||||
}
|
||||
|
||||
function addRelation (): void {
|
||||
showPopup(setting.component.CreateRelation, {
|
||||
aClass: masterTag._id,
|
||||
exclude: [],
|
||||
_classes: [card.class.Card, contact.class.Contact]
|
||||
showPopup(CreateRelation, {
|
||||
aClass: masterTag._id
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,7 @@ import TagsSection from './components/settings/TagsSection.svelte'
|
||||
import RelationsSection from './components/settings/RelationsSection.svelte'
|
||||
import ChildsSection from './components/settings/ChildsSection.svelte'
|
||||
import SetParentActionPopup from './components/SetParentActionPopup.svelte'
|
||||
import RelationSetting from './components/settings/RelationSetting.svelte'
|
||||
|
||||
export default async (): Promise<Resources> => ({
|
||||
component: {
|
||||
@ -51,7 +52,8 @@ export default async (): Promise<Resources> => ({
|
||||
TagsSection,
|
||||
RelationsSection,
|
||||
ChildsSection,
|
||||
SetParentActionPopup
|
||||
SetParentActionPopup,
|
||||
RelationSetting
|
||||
},
|
||||
completion: {
|
||||
CardQuery: queryCard
|
||||
|
@ -35,7 +35,8 @@ export default mergeIds(cardId, card, {
|
||||
TagsSection: '' as AnyComponent,
|
||||
ChildsSection: '' as AnyComponent,
|
||||
RelationsSection: '' as AnyComponent,
|
||||
SetParentActionPopup: '' as AnyComponent
|
||||
SetParentActionPopup: '' as AnyComponent,
|
||||
RelationSetting: '' as AnyComponent
|
||||
},
|
||||
completion: {
|
||||
CardQuery: '' as Resource<ObjectSearchFactory>,
|
||||
|
@ -82,7 +82,9 @@
|
||||
const clazz = hierarchy.getClass(key)
|
||||
result.push([
|
||||
{ id: key, label: clazz.label, icon: clazz.icon },
|
||||
value.map((it) => ({ id: it._id, label: it.label, icon: it.icon }))
|
||||
value
|
||||
.map((it) => ({ id: it._id, label: it.label, icon: it.icon }))
|
||||
.sort((a, b) => a.label.localeCompare(b.label))
|
||||
])
|
||||
} catch {}
|
||||
}
|
||||
|
@ -75,7 +75,9 @@ export {
|
||||
ClassSetting,
|
||||
filterDescendants,
|
||||
SpaceTypeGeneralSectionEditor,
|
||||
ClassHierarchy
|
||||
ClassHierarchy,
|
||||
RelationSetting,
|
||||
CreateRelation
|
||||
}
|
||||
|
||||
async function DeleteMixin (object: Mixin<Class<Doc>>): Promise<void> {
|
||||
|
@ -48,7 +48,7 @@
|
||||
$: query.query(
|
||||
view.class.Viewlet,
|
||||
{
|
||||
attachTo: _class
|
||||
attachTo: client.getHierarchy().getBaseClass(_class)
|
||||
},
|
||||
(res) => {
|
||||
viewlet = res[0]
|
||||
|
@ -200,54 +200,93 @@ async function OnCardRemove (ctx: TxRemoveDoc<Card>[], control: TriggerControl):
|
||||
return res
|
||||
}
|
||||
|
||||
async function OnCardParentChange (ctx: TxUpdateDoc<Card>[], control: TriggerControl): Promise<Tx[]> {
|
||||
async function OnCardUpdate (ctx: TxUpdateDoc<Card>[], control: TriggerControl): Promise<Tx[]> {
|
||||
const updateTx = ctx[0]
|
||||
if (updateTx.operations.parent === undefined) return []
|
||||
const newParent = updateTx.operations.parent
|
||||
const doc = (await control.findAll(control.ctx, card.class.Card, { _id: updateTx.objectId }))[0]
|
||||
if (doc === undefined) return []
|
||||
const oldParent = doc.parentInfo[doc.parentInfo.length - 1]?._id
|
||||
const res: Tx[] = []
|
||||
if (oldParent != null) {
|
||||
const parent = (await control.findAll(control.ctx, card.class.Card, { _id: oldParent }))[0]
|
||||
if (parent !== undefined) {
|
||||
res.push(
|
||||
control.txFactory.createTxUpdateDoc(parent._class, parent.space, parent._id, {
|
||||
$inc: {
|
||||
children: -1
|
||||
}
|
||||
})
|
||||
)
|
||||
if (updateTx.operations.parent !== undefined) {
|
||||
const newParent = updateTx.operations.parent
|
||||
const oldParent = doc.parentInfo[doc.parentInfo.length - 1]?._id
|
||||
if (newParent != null) {
|
||||
const parent = (await control.findAll(control.ctx, card.class.Card, { _id: newParent }))[0]
|
||||
if (parent !== undefined) {
|
||||
if (parent.parentInfo.findIndex((p) => p._id === doc._id) === -1) {
|
||||
res.push(
|
||||
control.txFactory.createTxUpdateDoc(parent._class, parent.space, parent._id, {
|
||||
$inc: {
|
||||
children: 1
|
||||
}
|
||||
})
|
||||
)
|
||||
res.push(
|
||||
control.txFactory.createTxUpdateDoc(doc._class, doc.space, doc._id, {
|
||||
parentInfo: [
|
||||
...parent.parentInfo,
|
||||
{
|
||||
_id: parent._id,
|
||||
_class: parent._class,
|
||||
title: parent.title
|
||||
}
|
||||
]
|
||||
})
|
||||
)
|
||||
} else {
|
||||
// rollback
|
||||
return [
|
||||
control.txFactory.createTxUpdateDoc(doc._class, doc.space, doc._id, {
|
||||
parent: oldParent ?? null
|
||||
})
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
if (oldParent != null) {
|
||||
const parent = (await control.findAll(control.ctx, card.class.Card, { _id: oldParent }))[0]
|
||||
if (parent !== undefined) {
|
||||
res.push(
|
||||
control.txFactory.createTxUpdateDoc(parent._class, parent.space, parent._id, {
|
||||
$inc: {
|
||||
children: -1
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (newParent != null) {
|
||||
const parent = (await control.findAll(control.ctx, card.class.Card, { _id: newParent }))[0]
|
||||
if (parent !== undefined) {
|
||||
res.push(
|
||||
control.txFactory.createTxUpdateDoc(parent._class, parent.space, parent._id, {
|
||||
$inc: {
|
||||
children: 1
|
||||
}
|
||||
})
|
||||
)
|
||||
res.push(
|
||||
control.txFactory.createTxUpdateDoc(doc._class, doc.space, doc._id, {
|
||||
parentInfo: [
|
||||
...parent.parentInfo,
|
||||
{
|
||||
_id: parent._id,
|
||||
_class: parent._class,
|
||||
title: parent.title
|
||||
}
|
||||
]
|
||||
})
|
||||
)
|
||||
}
|
||||
if (updateTx.operations.title !== undefined) {
|
||||
res.push(...(await updateParentInfoName(control, doc._id, updateTx.operations.title, doc._id)))
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
async function updateParentInfoName (
|
||||
control: TriggerControl,
|
||||
parent: Ref<Card>,
|
||||
title: string,
|
||||
originParent: Ref<Card>
|
||||
): Promise<Tx[]> {
|
||||
const res: Tx[] = []
|
||||
const childs = await control.findAll(control.ctx, card.class.Card, { parent })
|
||||
for (const child of childs) {
|
||||
if (child._id === originParent) continue
|
||||
const parentInfo = child.parentInfo
|
||||
const index = parentInfo.findIndex((p) => p._id === parent)
|
||||
if (index === -1) {
|
||||
continue
|
||||
}
|
||||
parentInfo[index].title = title
|
||||
res.push(
|
||||
control.txFactory.createTxUpdateDoc(child._class, child.space, child._id, {
|
||||
parentInfo
|
||||
})
|
||||
)
|
||||
res.push(...(await updateParentInfoName(control, child._id, title, originParent)))
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
async function OnCardCreate (ctx: TxCreateDoc<Card>[], control: TriggerControl): Promise<Tx[]> {
|
||||
const createTx = ctx[0]
|
||||
const doc = TxProcessor.createDoc2Doc(createTx)
|
||||
@ -277,6 +316,6 @@ export default async () => ({
|
||||
OnMasterTagRemove,
|
||||
OnCardRemove,
|
||||
OnCardCreate,
|
||||
OnCardParentChange
|
||||
OnCardUpdate
|
||||
}
|
||||
})
|
||||
|
@ -32,7 +32,7 @@ export default plugin(serverCardId, {
|
||||
OnMasterTagCreate: '' as Resource<TriggerFunc>,
|
||||
OnMasterTagRemove: '' as Resource<TriggerFunc>,
|
||||
OnCardCreate: '' as Resource<TriggerFunc>,
|
||||
OnCardParentChange: '' as Resource<TriggerFunc>,
|
||||
OnCardUpdate: '' as Resource<TriggerFunc>,
|
||||
OnCardRemove: '' as Resource<TriggerFunc>
|
||||
}
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user