platform/plugins/setting-resources/src/components/ClassAttributesList.svelte
Alexander Platov 3ac0e6e259
Updated layout of Project Types (#4345)
Signed-off-by: Alexander Platov <sas_lord@mail.ru>
2024-01-12 13:57:34 +07:00

175 lines
5.3 KiB
Svelte

<!--
// Copyright © 2022 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 { createEventDispatcher } from 'svelte'
import core, { AnyAttribute, ArrOf, AttachedDoc, Class, Collection, Doc, Ref, RefTo, Type } from '@hcengineering/core'
import { IntlString, getResource } from '@hcengineering/platform'
import presentation, { MessageBox, createQuery, getClient } from '@hcengineering/presentation'
import {
Action,
AnySvelteComponent,
IconDelete,
IconEdit,
Menu,
getEventPositionElement,
showPopup
} from '@hcengineering/ui'
import { getContextActions } from '@hcengineering/view-resources'
import settings from '../plugin'
import ClassAttributeRow from './ClassAttributeRow.svelte'
import EditAttribute from './EditAttribute.svelte'
export let _class: Ref<Class<Doc>>
export let ofClass: Ref<Class<Doc>> | undefined = undefined
export let notUseOfClass: boolean = false
export let selected: AnyAttribute | undefined = undefined
export let attributeMapper:
| {
component: AnySvelteComponent
label: IntlString
props: Record<string, any>
}
| undefined = undefined
const dispatch = createEventDispatcher()
const client = getClient()
const hierarchy = client.getHierarchy()
const classQuery = createQuery()
let clazz: Class<Doc> | undefined
let hovered: number | null = null
$: classQuery.query(core.class.Class, { _id: _class }, (res) => {
clazz = res.shift()
})
$: attributes = getCustomAttributes(_class)
function getCustomAttributes (_class: Ref<Class<Doc>>): AnyAttribute[] {
const cl = hierarchy.getClass(_class)
const attributes = Array.from(
hierarchy.getAllAttributes(_class, _class === ofClass && !notUseOfClass ? core.class.Doc : cl.extends).values()
)
return attributes
}
const attrQuery = createQuery()
$: attrQuery.query(core.class.Attribute, { attributeOf: _class }, () => {
attributes = getCustomAttributes(_class)
})
function update (): void {
attributes = getCustomAttributes(_class)
}
export async function editAttribute (attribute: AnyAttribute, exist: boolean): Promise<void> {
showPopup(EditAttribute, { attribute, exist }, 'top', update)
}
export async function removeAttribute (attribute: AnyAttribute, exist: boolean): Promise<void> {
showPopup(
MessageBox,
{
label: settings.string.DeleteAttribute,
message: exist ? settings.string.DeleteAttributeExistConfirm : settings.string.DeleteAttributeConfirm
},
'top',
async (result) => {
if (result != null) {
await client.remove(attribute)
update()
}
}
)
}
async function showMenu (ev: MouseEvent, attribute: AnyAttribute, row: number): Promise<void> {
hovered = row
const exist = (await client.findOne(attribute.attributeOf, { [attribute.name]: { $exists: true } })) !== undefined
const actions: Action[] = [
{
label: presentation.string.Edit,
icon: IconEdit,
action: async () => {
dispatch('select', attribute._id)
}
}
]
if (attribute.isCustom === true) {
actions.push({
label: presentation.string.Remove,
icon: IconDelete,
action: async () => {
await removeAttribute(attribute, exist)
}
})
}
const extra = await getContextActions(client, attribute, { mode: 'context' })
actions.push(
...extra.map((it) => ({
label: it.label,
icon: it.icon,
action: async (_: any, evt: Event) => {
const r = await getResource(it.action)
await r(attribute, evt, it.actionProps)
}
}))
)
showPopup(Menu, { actions }, getEventPositionElement(ev), () => {
hovered = null
})
}
function getAttrType (type: Type<any>): IntlString | undefined {
switch (type._class) {
case core.class.RefTo:
return client.getHierarchy().getClass((type as RefTo<Doc>).to).label
case core.class.Collection:
return client.getHierarchy().getClass((type as Collection<AttachedDoc>).of).label
case core.class.ArrOf:
return (type as ArrOf<Doc>).of.label
default:
return undefined
}
}
</script>
{#each attributes as attr, i}
{@const attrType = getAttrType(attr.type)}
<ClassAttributeRow
attribute={attr}
attributeType={attrType}
selected={selected && attr._id === selected._id}
hovered={hovered === i}
{attributeMapper}
clickMore={async (event) => {
event.preventDefault()
void showMenu(event, attr, i)
}}
on:contextmenu={async (event) => {
event.preventDefault()
void showMenu(event, attr, i)
}}
on:click={async () => {
if (selected && selected._id === attr._id) dispatch('deselect')
else dispatch('select', attr)
}}
/>
{/each}