mirror of
https://github.com/hcengineering/platform.git
synced 2025-05-12 10:25:51 +00:00
Card fixes (#8432)
Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
parent
1d760d8615
commit
7e4d1d0e56
@ -224,6 +224,10 @@ export function createModel (builder: Builder): void {
|
||||
inlineEditor: card.component.CardEditor
|
||||
})
|
||||
|
||||
builder.mixin(card.class.Card, core.class.Class, view.mixin.ArrayEditor, {
|
||||
inlineEditor: card.component.CardArrayEditor
|
||||
})
|
||||
|
||||
createAction(
|
||||
builder,
|
||||
{
|
||||
@ -319,7 +323,8 @@ export function createModel (builder: Builder): void {
|
||||
})
|
||||
|
||||
builder.mixin(card.class.Card, core.class.Class, view.mixin.AttributePresenter, {
|
||||
presenter: card.component.CardRefPresenter
|
||||
presenter: card.component.CardRefPresenter,
|
||||
arrayPresenter: card.component.CardArrayEditor
|
||||
})
|
||||
|
||||
builder.mixin(card.class.Card, core.class.Class, activity.mixin.ActivityDoc, {})
|
||||
|
@ -51,6 +51,7 @@ export function createModel (builder: Builder): void {
|
||||
|
||||
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
|
||||
trigger: serverCard.trigger.OnMasterTagRemove,
|
||||
isAsync: true,
|
||||
txMatch: {
|
||||
_class: core.class.TxUpdateDoc,
|
||||
objectClass: card.class.MasterTag,
|
||||
|
115
plugins/card-resources/src/components/CardArrayEditor.svelte
Normal file
115
plugins/card-resources/src/components/CardArrayEditor.svelte
Normal file
@ -0,0 +1,115 @@
|
||||
<!--
|
||||
// Copyright © 2025 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Card, MasterTag } from '@hcengineering/card'
|
||||
import { AnyAttribute, ArrOf, Ref, RefTo } from '@hcengineering/core'
|
||||
import { IntlString } from '@hcengineering/platform'
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import {
|
||||
Button,
|
||||
ButtonKind,
|
||||
ButtonSize,
|
||||
eventToHTMLElement,
|
||||
IconWithEmoji,
|
||||
Label,
|
||||
showPopup
|
||||
} from '@hcengineering/ui'
|
||||
import view from '@hcengineering/view'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import card from '../plugin'
|
||||
import CardsPopup from './CardsPopup.svelte'
|
||||
|
||||
export let value: Ref<Card>[] | undefined
|
||||
export let readonly: boolean = false
|
||||
export let label: IntlString | undefined
|
||||
export let onChange: ((value: any) => void) | undefined
|
||||
export let attribute: AnyAttribute
|
||||
|
||||
export let focusIndex: number | undefined = undefined
|
||||
export let kind: ButtonKind = 'ghost'
|
||||
export let size: ButtonSize = 'small'
|
||||
export let justify: 'left' | 'center' = 'left'
|
||||
export let width: string | undefined = 'min-content'
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
const client = getClient()
|
||||
const hierarchy = client.getHierarchy()
|
||||
|
||||
$: _class = ((attribute?.type as ArrOf<RefTo<Card>>)?.of as RefTo<Card>)?.to
|
||||
|
||||
const handleOpen = (event: MouseEvent): void => {
|
||||
if (onChange === undefined) {
|
||||
return
|
||||
}
|
||||
event.stopPropagation()
|
||||
|
||||
if (readonly) {
|
||||
return
|
||||
}
|
||||
|
||||
showPopup(
|
||||
CardsPopup,
|
||||
{ selectedObjects: value, _class, multiSelect: true },
|
||||
eventToHTMLElement(event),
|
||||
undefined,
|
||||
change
|
||||
)
|
||||
}
|
||||
|
||||
const change = (value: Ref<Card>[]): void => {
|
||||
onChange?.(value)
|
||||
dispatch('change', value)
|
||||
}
|
||||
|
||||
let docs: Card[] = []
|
||||
|
||||
const query = createQuery()
|
||||
$: query.query(card.class.Card, { _id: { $in: value ?? [] } }, (res) => {
|
||||
docs = res
|
||||
})
|
||||
|
||||
$: clazz = _class !== undefined ? (hierarchy.findClass(_class) as MasterTag) : undefined
|
||||
|
||||
$: icon = clazz?.icon === view.ids.IconWithEmoji ? IconWithEmoji : clazz?.icon
|
||||
$: iconProps = clazz?.icon === view.ids.IconWithEmoji ? { icon: clazz?.color } : {}
|
||||
|
||||
$: emptyLabel = label ?? clazz?.label ?? card.string.Card
|
||||
</script>
|
||||
|
||||
<Button
|
||||
showTooltip={!readonly ? { label } : undefined}
|
||||
{justify}
|
||||
{focusIndex}
|
||||
{width}
|
||||
{size}
|
||||
{icon}
|
||||
{iconProps}
|
||||
{kind}
|
||||
disabled={readonly}
|
||||
on:click={handleOpen}
|
||||
>
|
||||
<div slot="content" class="overflow-label">
|
||||
{#if docs.length === 1}
|
||||
{docs[0].title}
|
||||
{:else if docs.length > 1}
|
||||
<div class="lower">
|
||||
{docs.length}
|
||||
<Label label={card.string.Cards} />
|
||||
</div>
|
||||
{:else}
|
||||
<Label label={emptyLabel} />
|
||||
{/if}
|
||||
</div>
|
||||
</Button>
|
@ -22,6 +22,7 @@
|
||||
|
||||
export let _class: Ref<Class<Card>>
|
||||
export let selected: Ref<Card> | undefined
|
||||
export let selectedObjects: Ref<Card>[] | undefined
|
||||
export let multiSelect: boolean = false
|
||||
export let allowDeselect: boolean = true
|
||||
export let titleDeselect: IntlString | undefined = undefined
|
||||
@ -36,6 +37,7 @@
|
||||
<ObjectPopup
|
||||
{_class}
|
||||
{selected}
|
||||
{selectedObjects}
|
||||
{multiSelect}
|
||||
{allowDeselect}
|
||||
{titleDeselect}
|
||||
|
@ -84,6 +84,7 @@
|
||||
const _class = hierarchy.getClass(_id)
|
||||
if (_class.label === undefined) continue
|
||||
if (_class.kind !== ClassifierKind.CLASS) continue
|
||||
if ((_class as MasterTag).removed === true) continue
|
||||
added.add(_id)
|
||||
const descendants = hierarchy.getDescendants(_id)
|
||||
const toAdd: Class<Doc>[] = []
|
||||
|
@ -14,7 +14,7 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { MasterTag } from '@hcengineering/card'
|
||||
import { Ref, isOwnerOrMaintainer } from '@hcengineering/core'
|
||||
import { Ref } from '@hcengineering/core'
|
||||
import { createQuery } from '@hcengineering/presentation'
|
||||
import { ClassAttributes, ClassHierarchy, clearSettingsStore } from '@hcengineering/setting-resources'
|
||||
import {
|
||||
|
@ -4,14 +4,19 @@
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { CreateRelation } from '@hcengineering/setting-resources'
|
||||
import card from '../../plugin'
|
||||
import { MasterTag } from '@hcengineering/card'
|
||||
|
||||
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
|
||||
)
|
||||
const _classes = [...hierarchy.getDescendants(card.class.Card), contact.class.Contact].filter((c) => {
|
||||
if (c === card.class.Card) return false
|
||||
const cl = hierarchy.getClass(c)
|
||||
if (cl._class !== card.class.MasterTag) return true
|
||||
if ((cl as MasterTag).removed === true) return false
|
||||
return true
|
||||
})
|
||||
</script>
|
||||
|
||||
<CreateRelation {aClass} {_classes} exclude={[]} on:close />
|
||||
|
@ -4,13 +4,17 @@
|
||||
import contact from '@hcengineering/contact'
|
||||
import card from '../../plugin'
|
||||
import { Analytics } from '@hcengineering/analytics'
|
||||
import { CardEvents } from '@hcengineering/card'
|
||||
import { CardEvents, MasterTag } from '@hcengineering/card'
|
||||
|
||||
const client = getClient()
|
||||
const hierarchy = client.getHierarchy()
|
||||
const _classes = [...hierarchy.getDescendants(card.class.Card), contact.class.Contact].filter(
|
||||
(c) => c !== card.class.Card
|
||||
)
|
||||
const _classes = [...hierarchy.getDescendants(card.class.Card), contact.class.Contact].filter((c) => {
|
||||
if (c === card.class.Card) return false
|
||||
const cl = hierarchy.getClass(c)
|
||||
if (cl._class !== card.class.MasterTag) return true
|
||||
if ((cl as MasterTag).removed === true) return false
|
||||
return true
|
||||
})
|
||||
|
||||
function createHandler (): void {
|
||||
Analytics.handleEvent(CardEvents.RelationCreated)
|
||||
|
@ -39,6 +39,7 @@ import RelationSetting from './components/settings/RelationSetting.svelte'
|
||||
import CardEditor from './components/CardEditor.svelte'
|
||||
import CardRefPresenter from './components/CardRefPresenter.svelte'
|
||||
import ChangeType from './components/ChangeType.svelte'
|
||||
import CardArrayEditor from './components/CardArrayEditor.svelte'
|
||||
|
||||
export { default as CardSelector } from './components/CardSelector.svelte'
|
||||
|
||||
@ -61,7 +62,8 @@ export default async (): Promise<Resources> => ({
|
||||
RelationSetting,
|
||||
CardEditor,
|
||||
CardRefPresenter,
|
||||
ChangeType
|
||||
ChangeType,
|
||||
CardArrayEditor
|
||||
},
|
||||
completion: {
|
||||
CardQuery: queryCard
|
||||
|
@ -39,7 +39,8 @@ export default mergeIds(cardId, card, {
|
||||
RelationSetting: '' as AnyComponent,
|
||||
CardEditor: '' as AnyComponent,
|
||||
CardRefPresenter: '' as AnyComponent,
|
||||
ChangeType: '' as AnyComponent
|
||||
ChangeType: '' as AnyComponent,
|
||||
CardArrayEditor: '' as AnyComponent
|
||||
},
|
||||
completion: {
|
||||
CardQuery: '' as Resource<ObjectSearchFactory>,
|
||||
|
@ -139,7 +139,11 @@
|
||||
selected = event.detail as AnyAttribute
|
||||
if (selected?._id != null) {
|
||||
const exist = (await client.findOne(selected.attributeOf, { [selected.name]: { $exists: true } })) !== undefined
|
||||
$settingsStore = { id: selected._id, component: EditAttribute, props: { attribute: selected, exist, disabled } }
|
||||
$settingsStore = {
|
||||
id: selected._id,
|
||||
component: EditAttribute,
|
||||
props: { attribute: selected, exist, disabled, isCard }
|
||||
}
|
||||
}
|
||||
}
|
||||
onDestroy(() => {
|
||||
|
@ -38,6 +38,7 @@
|
||||
export let exist: boolean
|
||||
export let disabled: boolean = true
|
||||
export let noTopIndent: boolean = false
|
||||
export let isCard: boolean = false
|
||||
|
||||
let name: string
|
||||
let type: Type<PropertyType> | undefined = attribute.type
|
||||
@ -201,6 +202,7 @@
|
||||
<Component
|
||||
{is}
|
||||
props={{
|
||||
isCard,
|
||||
type,
|
||||
defaultValue,
|
||||
editable: !exist && !disabled,
|
||||
|
@ -46,7 +46,9 @@
|
||||
.reduce((a, b) => a.concat(b))
|
||||
.filter((p) => p !== card.class.Card)
|
||||
)
|
||||
const excluded = new Set()
|
||||
// exclude removed card types
|
||||
const removedTypes = client.getModel().findAllSync(card.class.MasterTag, { removed: true })
|
||||
const excluded = new Set(removedTypes.map((p) => p._id))
|
||||
for (const _class of exclude) {
|
||||
const desc = hierarchy.getDescendants(_class)
|
||||
for (const _id of desc) {
|
||||
|
@ -452,6 +452,7 @@
|
||||
this={attribute.presenter}
|
||||
value={getValue(attribute, object)}
|
||||
onChange={getOnChange(object, attribute)}
|
||||
attribute={attribute.attribute}
|
||||
{...joinProps(attribute, object, readonly || $restrictionStore.readonly)}
|
||||
/>
|
||||
</div>
|
||||
|
@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import core, { AnyAttribute, ArrOf, Class, Doc, Ref, RefTo, Space, Type } from '@hcengineering/core'
|
||||
import core, { AnyAttribute, ArrOf, Class, ClassifierKind, Doc, Ref, RefTo, Space, Type } from '@hcengineering/core'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { Label, Scroller, Submenu, closePopup, closeTooltip, resizeObserver, showPopup } from '@hcengineering/ui'
|
||||
import { ClassFilters, Filter, KeyFilter, KeyFilterPreset, ViewOptions } from '@hcengineering/view'
|
||||
@ -145,6 +145,8 @@
|
||||
|
||||
const desc = hierarchy.getDescendants(_class)
|
||||
for (const d of desc) {
|
||||
const cl = hierarchy.findClass(d)
|
||||
if (cl?.kind !== ClassifierKind.MIXIN) continue
|
||||
const extra = hierarchy.getOwnAttributes(d)
|
||||
for (const [k, v] of extra) {
|
||||
if (!allAttributes.has(k)) {
|
||||
|
@ -56,6 +56,7 @@
|
||||
kind={'list'}
|
||||
{compactMode}
|
||||
label={attributeModel.label}
|
||||
attribute={attributeModel.attribute}
|
||||
{...joinProps(attributeModel, docObject, props)}
|
||||
on:resize={translateSize}
|
||||
/>
|
||||
@ -68,6 +69,7 @@
|
||||
kind={'list'}
|
||||
{compactMode}
|
||||
label={attributeModel.label}
|
||||
attribute={attributeModel.attribute}
|
||||
{...joinProps(attributeModel, docObject, props)}
|
||||
on:resize={translateSize}
|
||||
/>
|
||||
|
@ -111,6 +111,7 @@ async function OnAttributeRemove (ctx: TxRemoveDoc<AnyAttribute>[], control: Tri
|
||||
|
||||
async function OnMasterTagRemove (ctx: TxUpdateDoc<MasterTag>[], control: TriggerControl): Promise<Tx[]> {
|
||||
const updateTx = ctx[0]
|
||||
if (updateTx.space === core.space.DerivedTx) return []
|
||||
if (updateTx.operations.removed !== true) return []
|
||||
const res: Tx[] = []
|
||||
const desc = control.hierarchy.getDescendants(updateTx.objectId)
|
||||
|
Loading…
Reference in New Issue
Block a user