Adjust label editors (#1955)

Signed-off-by: Dvinyanin Alexandr <dvinyanin.alexandr@gmail.com>
This commit is contained in:
Alex 2022-05-31 11:28:40 +07:00 committed by GitHub
parent a12d5a3347
commit 7fe382daf0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 139 additions and 416 deletions

View File

@ -1,10 +1,11 @@
# Changelog
## 0.6.23
## 0.6.23 (upcoming)
Platform:
- Fix first filter disappear
- Adjust label editors design
## 0.6.22

View File

@ -40,6 +40,7 @@ import workbench, { Application } from '@anticrm/model-workbench'
import { IntlString } from '@anticrm/platform'
import type { AnyComponent } from '@anticrm/ui'
import preference, { TPreference } from '@anticrm/model-preference'
import tags from '@anticrm/model-tags'
import board from './plugin'
@Model(board.class.Board, task.class.SpaceWithStates)
@ -64,8 +65,6 @@ export class TCardCover extends TType implements CardCover {
export class TCommonBoardPreference extends TPreference implements CommonBoardPreference {
@Prop(TypeRef(workbench.class.Application), board.string.CommonBoardPreference)
attachedTo!: Ref<Application>
cardLabelsCompactMode!: boolean
}
@Model(board.class.Card, task.class.Task)
@ -282,8 +281,9 @@ export function createModel (builder: Builder): void {
{
action: view.actionImpl.ShowPopup,
actionProps: {
component: board.component.LabelsActionPopup,
element: view.popup.PositionElementAlignment
component: tags.component.TagsEditorPopup,
element: view.popup.PositionElementAlignment,
value: 'object'
},
label: board.string.Labels,
icon: board.icon.Card,

View File

@ -28,13 +28,11 @@ export default mergeIds(boardId, board, {
CreateCard: '' as AnyComponent,
KanbanCard: '' as AnyComponent,
CardPresenter: '' as AnyComponent,
CardLabelPresenter: '' as AnyComponent,
BoardPresenter: '' as AnyComponent,
TemplatesIcon: '' as AnyComponent,
Cards: '' as AnyComponent,
KanbanView: '' as AnyComponent,
TableView: '' as AnyComponent,
LabelsActionPopup: '' as AnyComponent,
DatesActionPopup: '' as AnyComponent,
CoverActionPopup: '' as AnyComponent,
MoveActionPopup: '' as AnyComponent,

View File

@ -90,6 +90,9 @@ export function createModel (builder: Builder): void {
builder.mixin(tags.class.TagReference, core.class.Class, view.mixin.CollectionEditor, {
editor: tags.component.Tags
})
builder.mixin(tags.class.TagReference, core.class.Class, view.mixin.AttributeEditor, {
editor: tags.component.TagsAttributeEditor
})
builder.mixin(tags.class.TagReference, core.class.Class, view.mixin.AttributePresenter, {
presenter: tags.component.TagReferencePresenter

View File

@ -24,9 +24,9 @@ export default mergeIds(tagsId, tags, {
component: {
Tags: '' as AnyComponent,
TagReferencePresenter: '' as AnyComponent,
TagsPresenter: '' as AnyComponent,
TagsItemPresenter: '' as AnyComponent,
TagsFilter: '' as AnyComponent
TagsFilter: '' as AnyComponent,
TagsEditorPopup: '' as AnyComponent
},
string: {
TagElementLabel: '' as IntlString,

View File

@ -81,6 +81,7 @@
space={object.space}
{onChange}
{focus}
{object}
/>
</div>
</div>
@ -104,6 +105,7 @@
space={object.space}
{onChange}
{focus}
{object}
/>
{/if}
{:else if showHeader}
@ -121,6 +123,7 @@
space={object.space}
{onChange}
{focus}
{object}
/>
</div>
</div>
@ -141,6 +144,7 @@
space={object.space}
{onChange}
{focus}
{object}
/>
</div>
{/if}
@ -154,6 +158,7 @@
space={object.space}
{onChange}
{focus}
{object}
/>
</div>
{/if}

View File

@ -56,6 +56,7 @@
let handleMove: (e: Event) => void
let checklists: TodoItem[] = []
const mixins: Mixin<Doc>[] = []
const allowedCollections = ['labels']
const ignoreKeys = [
'isArchived',
'location',
@ -184,7 +185,7 @@
</div>
<svelte:fragment slot="custom-attributes" let:direction>
{#if direction === 'column'}
<DocAttributeBar {object} {mixins} {ignoreKeys} />
<DocAttributeBar {object} {mixins} {ignoreKeys} {allowedCollections} />
<!-- TODO: adjust rest actions -->
<CardActions bind:value={object} />
{:else}

View File

@ -21,6 +21,7 @@
import type { Ref, WithLookup } from '@anticrm/core'
import notification from '@anticrm/notification'
import view from '@anticrm/view'
import tags from '@anticrm/tags'
import { getClient, UserBoxList } from '@anticrm/presentation'
import {
Button,
@ -35,7 +36,6 @@
} from '@anticrm/ui'
import { ContextMenu } from '@anticrm/view-resources'
import board from '../plugin'
import CardLabels from './editor/CardLabels.svelte'
import DatePresenter from './presenters/DatePresenter.svelte'
import { hasDate, openCardPanel, updateCard, updateCardMembers } from '../utils/CardUtils'
import CheckListsPresenter from './presenters/ChecklistsPresenter.svelte'
@ -94,9 +94,6 @@
class="abs-full-content background-theme-content-accent h-full w-full flex-center fs-title"
/>
{/if}
<div class="ml-1">
<CardLabels bind:value={object} isInline={true} />
</div>
{#if !isEditMode}
<div class="absolute mr-1 mt-1" style:top="0" style:right="0">
<Button icon={IconEdit} kind="transparent" on:click={enterEditMode} />
@ -147,9 +144,6 @@
class="abs-full-content background-theme-content-accent h-full w-full flex-center fs-title"
/>
{/if}
<div class="ml-1">
<CardLabels bind:value={object} isInline={true} />
</div>
{#if !isEditMode && !object.cover}
<div class="absolute mr-1 mt-1" style:top="0" style:right="0">
<Button icon={IconEdit} kind="transparent" on:click={enterEditMode} />
@ -211,6 +205,14 @@
<CheckListsPresenter value={object} />
</div>
{/if}
{#if (object.labels ?? 0) > 0}
<div class="float-left">
<Component
is={tags.component.TagsPresenter}
props={{ value: object, _class: object._class, key: 'labels' }}
/>
</div>
{/if}
</div>
</div>
{#if (object.members?.length ?? 0) > 0}

View File

@ -3,6 +3,7 @@
import { Class, FindOptions, Ref } from '@anticrm/core'
import { createQuery } from '@anticrm/presentation'
import task, { SpaceWithStates, State } from '@anticrm/task'
import tags from '@anticrm/tags'
import { TableBrowser } from '@anticrm/view-resources'
import board from '../plugin'
@ -23,7 +24,12 @@
config={[
'title',
'$lookup.state',
{ key: '', presenter: board.component.CardLabels, label: board.string.Labels },
{
key: '',
presenter: tags.component.TagsAttributeEditor,
props: { isEditable: false },
label: board.string.Labels
},
'startDate',
'dueDate',
{ key: 'members', presenter: board.component.UserBoxList, label: board.string.Members, sortingKey: '' },

View File

@ -24,7 +24,6 @@
import plugin from '../../plugin'
import { updateCardMembers } from '../../utils/CardUtils'
import UserBoxList from '../UserBoxList.svelte'
import CardLabels from './CardLabels.svelte'
export let value: Card
const client = getClient()
@ -55,10 +54,6 @@
<div class="ml-4">
<UserBoxList value={value.members ?? []} on:update={updateMembers} />
</div>
<div class="label fs-bold">
<Label label={plugin.string.Labels} />
</div>
<CardLabels {value} />
</div>
{/if}

View File

@ -1,94 +0,0 @@
<!--
// 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 type { Card } from '@anticrm/board'
import { createQuery, getClient } from '@anticrm/presentation'
import tags, { TagReference } from '@anticrm/tags'
import { Button, Icon, IconAdd } from '@anticrm/ui'
import { invokeAction } from '@anticrm/view-resources'
import board from '../../plugin'
import { commonBoardPreference } from '../../utils/BoardUtils'
import { getCardActions } from '../../utils/CardActionUtils'
import LabelPresenter from '../presenters/LabelPresenter.svelte'
export let value: Card
export let isInline: boolean = false
const client = getClient()
let labelsHandler: (e: Event) => void
let isHovered: boolean = false
let labels: TagReference[] = []
const query = createQuery()
$: query.query(tags.class.TagReference, { attachedTo: value._id }, (result) => {
labels = result
})
$: isCompact = $commonBoardPreference?.cardLabelsCompactMode
if (!isInline) {
getCardActions(client, {
_id: board.action.Labels
}).then(async (result) => {
if (result?.[0]) {
labelsHandler = (e: Event) => invokeAction(value, e, result[0].action, result[0].actionProps)
}
})
}
function toggleCompact () {
if (!isInline) return
client.update($commonBoardPreference, { cardLabelsCompactMode: !isCompact })
}
function hoverIn () {
if (isInline) {
isHovered = true
}
}
function hoverOut () {
isHovered = false
}
</script>
<div
class="flex mb-1"
class:labels-inline-container={isInline}
on:click={toggleCompact}
on:mouseover={hoverIn}
on:focus={hoverIn}
on:mouseout={hoverOut}
on:blur={hoverOut}
>
{#if labels && labels.length > 0}
<div class="flex-row-center flex-wrap flex-gap-1 ml-4">
{#each labels as label}
<LabelPresenter
value={label}
size={isInline ? (isCompact ? 'tiny' : 'x-small') : undefined}
{isHovered}
on:click={labelsHandler}
/>
{/each}
</div>
{:else if !isInline}
<Button kind="link" size="large" on:click={labelsHandler}>
<Icon slot="content" icon={IconAdd} size="small" />
</Button>
{/if}
</div>

View File

@ -1,106 +0,0 @@
<script lang="ts">
import { createEventDispatcher } from 'svelte'
import { getClient } from '@anticrm/presentation'
import { Label, Button, EditBox, Icon, IconBack, IconCheck, IconClose, hexColorToNumber } from '@anticrm/ui'
import board from '../../plugin'
import { createCardLabel, getBoardAvailableColors } from '../../utils/BoardUtils'
import ColorPresenter from '../presenters/ColorPresenter.svelte'
import { TagElement } from '@anticrm/tags'
export let object: TagElement | undefined
export let onBack: () => void
let { title, color } = object ?? {}
const client = getClient()
const dispatch = createEventDispatcher()
const colorGroups = (function chunk (colors: number[]): number[][] {
return colors.length ? [colors.slice(0, 5), ...chunk(colors.slice(5))] : []
})(getBoardAvailableColors().map(hexColorToNumber))
async function save () {
if (!title || !color) {
return
}
if (object) {
await client.update(object, { title, color })
} else {
await createCardLabel(client, { title, color })
}
onBack()
}
async function remove () {
if (!object) return
await client.remove(object)
onBack()
}
</script>
<div class="antiPopup w-85">
<div class="relative flex-row-center w-full ">
<div class="absolute ml-1 mt-1 mb-1" style:top="0" style:left="0">
<Button icon={IconBack} kind="transparent" size="small" on:click={onBack} />
</div>
<div class="flex-center flex-grow fs-title mt-1 mb-1">
<Label label={board.string.Labels} />
</div>
<div class="absolute mr-1 mt-1 mb-1" style:top="0" style:right="0">
<Button
icon={IconClose}
kind="transparent"
size="small"
on:click={() => {
dispatch('close')
}}
/>
</div>
</div>
<div class="ap-space bottom-divider" />
<div class="flex-col ml-4 mt-4 mr-4 flex-gap-1">
<div class="text-md font-medium">
<Label label={board.string.Name} />
</div>
<div class="p-2 mt-1 mb-1 border-bg-accent border-radius-1">
<EditBox bind:value={title} maxWidth="100%" focus={true} />
</div>
</div>
<div class="flex-col ml-4 mt-4 mb-4 mr-4 flex-gap-1">
<div class="text-md font-medium">
<Label label={board.string.SelectColor} />
</div>
<div class="flex-col mt-1 mb-1 flex-gap-2">
{#each colorGroups as colorGroup}
<div class="flex-row-stretch flex-gap-2">
{#each colorGroup as c}
<div class="w-14">
<ColorPresenter
value={c}
size="large"
on:click={() => {
color = c
}}
>
{#if c === color}
<div class="flex-center flex-grow fs-title h-full">
<Icon icon={IconCheck} size="small" />
</div>
{/if}
</ColorPresenter>
</div>
{/each}
</div>
{/each}
</div>
</div>
<div class="ap-footer">
{#if object}
<Button size="small" kind="dangerous" label={board.string.Delete} on:click={remove} />
{/if}
<Button label={board.string.Save} size="small" kind="primary" on:click={save} disabled={!color || !title} />
</div>
</div>

View File

@ -1,119 +0,0 @@
<script lang="ts">
import { Card } from '@anticrm/board'
import type { Ref } from '@anticrm/core'
import tags, { TagElement, TagReference } from '@anticrm/tags'
import { createQuery, getClient } from '@anticrm/presentation'
import {
Button,
EditBox,
Icon,
IconEdit,
IconCheck,
IconClose,
Label,
numberToHexColor,
numberToRGB
} from '@anticrm/ui'
import { createEventDispatcher } from 'svelte'
import board from '../../plugin'
import { addCardLabel } from '../../utils/BoardUtils'
export let object: Card
export let search: string = ''
export let onEdit: (label: TagElement) => void
export let onCreate: () => void
const client = getClient()
let hovered: Ref<TagElement> | undefined = undefined
const dispatch = createEventDispatcher()
let labels: TagElement[] = []
const labelsQuery = createQuery()
$: labelsQuery.query(
tags.class.TagElement,
{ title: { $like: '%' + search + '%' }, targetClass: board.class.Card },
(result) => {
labels = result
}
)
let cardLabels: TagReference[] = []
let cardLabelRefs: Ref<TagElement>[] = []
const cardLabelsQuery = createQuery()
$: cardLabelsQuery.query(tags.class.TagReference, { attachedTo: object._id }, (result) => {
cardLabels = result
cardLabelRefs = result.map(({ tag }) => tag)
})
async function toggle (label: TagElement) {
const cardLabel = cardLabels.find(({ tag }) => tag === label._id)
if (cardLabel) {
await client.remove(cardLabel)
return
}
addCardLabel(client, object, label)
}
</script>
<div class="antiPopup w-85 pb-2">
<div class="relative flex-row-center w-full">
<div class="flex-center flex-grow fs-title mt-1 mb-1">
<Label label={board.string.Labels} />
</div>
<div class="absolute mr-1 mt-1 mb-1" style:top="0" style:right="0">
<Button
icon={IconClose}
kind="transparent"
size="small"
on:click={() => {
dispatch('close')
}}
/>
</div>
</div>
<div class="ap-space bottom-divider" />
<div class="flex-col ml-4 mt-2 mb-1 mr-2 flex-gap-1">
<div class="p-2 mt-1 mb-1 border-bg-accent border-radius-1">
<EditBox bind:value={search} maxWidth="100%" placeholder={board.string.SearchLabels} />
</div>
<div class="text-md font-medium">
<Label label={board.string.Labels} />
</div>
{#each labels as label}
<div
class="flex-row-stretch"
on:mouseover={() => {
hovered = label._id
}}
on:focus={() => {
hovered = label._id
}}
on:mouseout={() => {
hovered = undefined
}}
on:blur={() => {
hovered = undefined
}}
>
<div
class="relative flex-row-center justify-center border-radius-1 fs-title w-full h-8 mr-2"
style:background-color={numberToHexColor(label.color)}
style:box-shadow={hovered === label._id ? `-0.4rem 0 ${numberToRGB(label.color, 0.6)}` : ''}
on:click={() => toggle(label)}
>
{label.title}
{#if cardLabelRefs.includes(label._id)}
<div class="absolute flex-center h-full mr-2" style:top="0" style:right="0">
<Icon icon={IconCheck} size="small" />
</div>
{/if}
</div>
<Button icon={IconEdit} kind="transparent" on:click={() => onEdit(label)} />
</div>
{/each}
<div class="mt-3" />
<Button label={board.string.CreateLabel} kind="no-border" on:click={() => onCreate()} />
</div>
</div>

View File

@ -1,30 +0,0 @@
<script lang="ts">
import { Card } from '@anticrm/board'
import { TagElement } from '@anticrm/tags'
import CardLabelsEditor from './CardLabelsEditor.svelte'
import CardLabelsPicker from './CardLabelsPicker.svelte'
export let value: Card
let editMode: {
isEdit?: boolean
object?: TagElement
} = {}
let search: string | undefined = undefined
function setEditMode (isEdit: boolean, object?: TagElement) {
editMode = { isEdit, object }
}
</script>
{#if editMode.isEdit}
<CardLabelsEditor on:close object={editMode.object} onBack={() => setEditMode(false, undefined)} />
{:else}
<CardLabelsPicker
bind:search
on:close
object={value}
onCreate={() => setEditMode(true, undefined)}
onEdit={(o) => setEditMode(true, o)}
/>
{/if}

View File

@ -24,11 +24,9 @@ import CreateCard from './components/CreateCard.svelte'
import EditCard from './components/EditCard.svelte'
import KanbanCard from './components/KanbanCard.svelte'
import KanbanView from './components/KanbanView.svelte'
import CardLabelsPopup from './components/popups/CardLabelsPopup.svelte'
import MoveCard from './components/popups/MoveCard.svelte'
import CopyCard from './components/popups/CopyCard.svelte'
import DateRangePicker from './components/popups/DateRangePicker.svelte'
import CardLabelPresenter from './components/presenters/LabelPresenter.svelte'
import TemplatesIcon from './components/TemplatesIcon.svelte'
import BoardHeader from './components/BoardHeader.svelte'
import BoardMenu from './components/BoardMenu.svelte'
@ -36,7 +34,6 @@ import MenuMainPage from './components/MenuMainPage.svelte'
import Archive from './components/Archive.svelte'
import TableView from './components/TableView.svelte'
import UserBoxList from './components/UserBoxList.svelte'
import CardLabels from './components/editor/CardLabels.svelte'
import CardCoverEditor from './components/editor/CardCoverEditor.svelte'
import CardCoverPresenter from './components/presenters/CardCoverPresenter.svelte'
import CardCoverPicker from './components/popups/CardCoverPicker.svelte'
@ -62,7 +59,6 @@ export default async (): Promise<Resources> => ({
EditCard,
KanbanCard,
CardPresenter,
CardLabelPresenter,
TemplatesIcon,
KanbanView,
BoardPresenter,
@ -72,11 +68,9 @@ export default async (): Promise<Resources> => ({
MenuMainPage,
TableView,
UserBoxList,
CardLabels,
CardCoverEditor,
CardCoverPresenter,
// action popups
LabelsActionPopup: CardLabelsPopup,
DatesActionPopup: DateRangePicker,
CoverActionPopup: CardCoverPicker,
MoveActionPopup: MoveCard,

View File

@ -133,7 +133,6 @@ export default mergeIds(boardId, board, {
BoardMenu: '' as AnyComponent,
Archive: '' as AnyComponent,
MenuMainPage: '' as AnyComponent,
UserBoxList: '' as AnyComponent,
CardLabels: '' as AnyComponent
UserBoxList: '' as AnyComponent
}
})

View File

@ -1,9 +1,8 @@
import { readable } from 'svelte/store'
import board, { Board, Card, CommonBoardPreference } from '@anticrm/board'
import board, { Board, CommonBoardPreference } from '@anticrm/board'
import core, { Ref, TxOperations } from '@anticrm/core'
import type { KanbanTemplate, TodoItem } from '@anticrm/task'
import preference from '@anticrm/preference'
import tags, { TagElement } from '@anticrm/tags'
import { createKanban } from '@anticrm/task'
import { createQuery, getClient } from '@anticrm/presentation'
import {
@ -53,28 +52,6 @@ export function getBoardAvailableColors (): string[] {
]
}
export async function createCardLabel (
client: TxOperations,
{ title, color }: { title: string, color: number }
): Promise<void> {
await client.createDoc(tags.class.TagElement, tags.space.Tags, {
title,
color,
targetClass: board.class.Card,
description: '',
category: board.category.Other
})
}
export async function addCardLabel (client: TxOperations, card: Card, label: TagElement): Promise<void> {
const { title, color, _id: tag } = label
await client.addCollection(tags.class.TagReference, card.space, card._id, card._class, 'labels', {
title,
color,
tag
})
}
export function getDateIcon (item: TodoItem): 'normal' | 'warning' | 'overdue' {
if (item.dueTo === null) return 'normal'
const date = new Date()
@ -86,8 +63,7 @@ export const commonBoardPreference = readable<CommonBoardPreference>(undefined,
createQuery().query(board.class.CommonBoardPreference, { attachedTo: board.app.Board }, (result) => {
if (result.total > 0) return set(result[0])
void getClient().createDoc(board.class.CommonBoardPreference, preference.space.Preference, {
attachedTo: board.app.Board,
cardLabelsCompactMode: false
attachedTo: board.app.Board
})
})
})

View File

@ -80,9 +80,7 @@ export interface MenuPage extends Doc {
/**
* @public
*/
export interface CommonBoardPreference extends Preference {
cardLabelsCompactMode: boolean
}
export interface CommonBoardPreference extends Preference {}
/**
* @public
*/

View File

@ -0,0 +1,36 @@
<script lang="ts">
import { Doc } from '@anticrm/core'
import { createQuery } from '@anticrm/presentation'
import tags, { TagReference } from '@anticrm/tags'
import { getEventPopupPositionElement, Icon, IconAdd, showPopup } from '@anticrm/ui'
import Button from '@anticrm/ui/src/components/Button.svelte'
import TagReferencePresenter from './TagReferencePresenter.svelte'
import TagsEditorPopup from './TagsEditorPopup.svelte'
export let object: Doc
export let isEditable: boolean = true
let items: TagReference[] = []
const query = createQuery()
$: query.query(tags.class.TagReference, { attachedTo: object._id }, (result) => {
items = result
})
async function tagsHandler (evt: MouseEvent): Promise<void> {
if (!isEditable) return
showPopup(TagsEditorPopup, { object }, getEventPopupPositionElement(evt))
}
</script>
{#if items.length}
<div class="flex-row-center flex-wrap flex-gap-1 ml-4" on:click={tagsHandler}>
{#each items as value}
<TagReferencePresenter {value} />
{/each}
</div>
{:else if isEditable}
<Button kind="link" on:click={tagsHandler}>
<Icon icon={IconAdd} slot="content" size="small" />
</Button>
{/if}

View File

@ -0,0 +1,34 @@
<script lang="ts">
import { Doc, Ref } from '@anticrm/core'
import { createQuery, getClient } from '@anticrm/presentation'
import tags, { TagElement } from '@anticrm/tags'
import TagsPopup from './TagsPopup.svelte'
export let object: Doc
let selected: Ref<TagElement>[] = []
const query = createQuery()
$: query.query(tags.class.TagReference, { attachedTo: object._id }, (result) => {
selected = result.map(({ tag }) => tag)
})
const client = getClient()
async function addRef ({ title, color, _id: tag }: TagElement): Promise<void> {
await client.addCollection(tags.class.TagReference, object.space, object._id, object._class, 'labels', {
title,
color,
tag
})
}
async function removeTag (tag: TagElement): Promise<void> {
const tagRef = await client.findOne(tags.class.TagReference, { tag: tag._id })
if (tagRef) await client.remove(tagRef)
}
async function onUpdate (event: CustomEvent<{ action: string; tag: TagElement }>) {
const result = event.detail
if (result === undefined) return
if (result.action === 'add') addRef(result.tag)
else if (result.action === 'remove') removeTag(result.tag)
}
</script>
<TagsPopup targetClass={object._class} {selected} on:update={onUpdate} />

View File

@ -27,6 +27,8 @@ import TagsPresenter from './components/TagsPresenter.svelte'
import TagsView from './components/TagsView.svelte'
import TagElementCountPresenter from './components/TagElementCountPresenter.svelte'
import TagsFilter from './components/TagsFilter.svelte'
import TagsAttributeEditor from './components/TagsAttributeEditor.svelte'
import TagsEditorPopup from './components/TagsEditorPopup.svelte'
export default async (): Promise<Resources> => ({
component: {
@ -41,7 +43,9 @@ export default async (): Promise<Resources> => ({
TagsItemPresenter,
CategoryPresenter,
TagsCategoryBar,
TagElementCountPresenter
TagElementCountPresenter,
TagsAttributeEditor,
TagsEditorPopup
},
actionImpl: {
Open: (value: TagElement, evt: MouseEvent) => {

View File

@ -81,7 +81,9 @@ const tagsPlugin = plugin(tagsId, {
TagsView: '' as AnyComponent,
TagsEditor: '' as AnyComponent,
TagsDropdownEditor: '' as AnyComponent,
TagsCategoryBar: '' as AnyComponent
TagsCategoryBar: '' as AnyComponent,
TagsAttributeEditor: '' as AnyComponent,
TagsPresenter: '' as AnyComponent
},
category: {
NoCategory: '' as Ref<TagCategory>

View File

@ -17,12 +17,13 @@
import { AttributesBar, getClient, KeyedAttribute } from '@anticrm/presentation'
import setting from '@anticrm/setting'
import { Button, getCurrentLocation, Label, navigate, Tooltip } from '@anticrm/ui'
import { collectionsFilter, getFiltredKeys } from '../utils'
import { getFiltredKeys, isCollectionAttr } from '../utils'
export let object: Doc
export let _class: Ref<Class<Doc>>
export let to: Ref<Class<Doc>> | undefined
export let ignoreKeys: string[] = []
export let allowedCollections: string[] = []
export let vertical: boolean
const client = getClient()
const hierarchy = client.getHierarchy()
@ -32,7 +33,7 @@
function updateKeys (ignoreKeys: string[]): void {
const filtredKeys = getFiltredKeys(hierarchy, _class, ignoreKeys, to)
keys = collectionsFilter(hierarchy, filtredKeys, false)
keys = filtredKeys.filter((key) => !isCollectionAttr(hierarchy, key) || allowedCollections.includes(key.key))
}
$: updateKeys(ignoreKeys)

View File

@ -19,9 +19,26 @@
export let object: Doc
export let mixins: Mixin<Doc>[]
export let ignoreKeys: string[]
export let allowedCollections: string[] = []
</script>
<ClassAttributeBar _class={object._class} {object} {ignoreKeys} to={undefined} vertical on:update />
<ClassAttributeBar
_class={object._class}
{object}
{ignoreKeys}
to={undefined}
{allowedCollections}
vertical
on:update
/>
{#each mixins as mixin}
<ClassAttributeBar _class={mixin._id} {object} {ignoreKeys} to={object._class} vertical on:update />
<ClassAttributeBar
_class={mixin._id}
{object}
{ignoreKeys}
to={object._class}
{allowedCollections}
vertical
on:update
/>
{/each}

View File

@ -374,6 +374,6 @@ export function collectionsFilter (hierarchy: Hierarchy, keys: KeyedAttribute[],
return result
}
function isCollectionAttr (hierarchy: Hierarchy, key: KeyedAttribute): boolean {
export function isCollectionAttr (hierarchy: Hierarchy, key: KeyedAttribute): boolean {
return hierarchy.isDerived(key.attr.type._class, core.class.Collection)
}