Filters improve (#2572)

Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
Denis Bykhov 2023-01-31 23:18:07 +06:00 committed by GitHub
parent 67e86538bb
commit f7e220d0f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 263 additions and 98 deletions

View File

@ -35,6 +35,7 @@ import { DOMAIN_MODEL, IndexKind } from '@hcengineering/core'
import { import {
Builder, Builder,
Collection, Collection,
Hidden,
Index, Index,
Model, Model,
Prop, Prop,
@ -76,6 +77,7 @@ export class TChannelProvider extends TDoc implements ChannelProvider {
export class TContact extends TDoc implements Contact { export class TContact extends TDoc implements Contact {
@Prop(TypeString(), contact.string.Name) @Prop(TypeString(), contact.string.Name)
@Index(IndexKind.FullText) @Index(IndexKind.FullText)
@Hidden()
name!: string name!: string
avatar?: string | null avatar?: string | null

View File

@ -70,17 +70,21 @@ import core from './component'
export class TObj implements Obj { export class TObj implements Obj {
@Prop(TypeRef(core.class.Class), core.string.ClassLabel) @Prop(TypeRef(core.class.Class), core.string.ClassLabel)
@Index(IndexKind.Indexed) @Index(IndexKind.Indexed)
@Hidden()
_class!: Ref<Class<this>> _class!: Ref<Class<this>>
} }
@Model(core.class.Doc, core.class.Obj) @Model(core.class.Doc, core.class.Obj)
@UX(core.string.Object)
export class TDoc extends TObj implements Doc { export class TDoc extends TObj implements Doc {
@Prop(TypeRef(core.class.Doc), core.string.Id) @Prop(TypeRef(core.class.Doc), core.string.Id)
@Hidden()
// @Index(IndexKind.Indexed) // - automatically indexed by default. // @Index(IndexKind.Indexed) // - automatically indexed by default.
_id!: Ref<this> _id!: Ref<this>
@Prop(TypeRef(core.class.Space), core.string.Space) @Prop(TypeRef(core.class.Space), core.string.Space)
@Index(IndexKind.Indexed) @Index(IndexKind.Indexed)
@Hidden()
space!: Ref<Space> space!: Ref<Space>
@Prop(TypeTimestamp(), core.string.Modified) @Prop(TypeTimestamp(), core.string.Modified)
@ -94,10 +98,12 @@ export class TDoc extends TObj implements Doc {
export class TAttachedDoc extends TDoc implements AttachedDoc { export class TAttachedDoc extends TDoc implements AttachedDoc {
@Prop(TypeRef(core.class.Doc), core.string.AttachedTo) @Prop(TypeRef(core.class.Doc), core.string.AttachedTo)
@Index(IndexKind.Indexed) @Index(IndexKind.Indexed)
@Hidden()
attachedTo!: Ref<Doc> attachedTo!: Ref<Doc>
@Prop(TypeRef(core.class.Class), core.string.AttachedToClass) @Prop(TypeRef(core.class.Class), core.string.AttachedToClass)
@Index(IndexKind.Indexed) @Index(IndexKind.Indexed)
@Hidden()
attachedToClass!: Ref<Class<Doc>> attachedToClass!: Ref<Class<Doc>>
@Prop(TypeString(), core.string.Collection) @Prop(TypeString(), core.string.Collection)

View File

@ -16,7 +16,6 @@
import type { Employee, Organization } from '@hcengineering/contact' import type { Employee, Organization } from '@hcengineering/contact'
import { Doc, FindOptions, IndexKind, Lookup, Ref, Timestamp } from '@hcengineering/core' import { Doc, FindOptions, IndexKind, Lookup, Ref, Timestamp } from '@hcengineering/core'
import { import {
ArrOf,
Builder, Builder,
Collection, Collection,
Index, Index,
@ -125,7 +124,7 @@ export class TCandidate extends TPerson implements Candidate {
@Mixin(recruit.mixin.VacancyList, contact.class.Organization) @Mixin(recruit.mixin.VacancyList, contact.class.Organization)
@UX(recruit.string.VacancyList, recruit.icon.RecruitApplication, undefined, 'name') @UX(recruit.string.VacancyList, recruit.icon.RecruitApplication, undefined, 'name')
export class TVacancyList extends TOrganization implements VacancyList { export class TVacancyList extends TOrganization implements VacancyList {
@Prop(ArrOf(TypeRef(recruit.class.Vacancy)), recruit.string.Vacancies) @Prop(Collection(recruit.class.Vacancy), recruit.string.Vacancies)
vacancies!: number vacancies!: number
} }
@ -192,7 +191,7 @@ export function createModel (builder: Builder): void {
editor: recruit.component.Applications editor: recruit.component.Applications
}) })
builder.mixin(recruit.class.Vacancy, core.class.Class, view.mixin.ArrayEditor, { builder.mixin(recruit.class.Vacancy, core.class.Class, view.mixin.CollectionEditor, {
editor: recruit.component.VacancyList editor: recruit.component.VacancyList
}) })

View File

@ -121,6 +121,7 @@ export class TTask extends TAttachedDoc implements Task {
@Prop(TypeString(), task.string.TaskNumber) @Prop(TypeString(), task.string.TaskNumber)
@Index(IndexKind.FullText) @Index(IndexKind.FullText)
@Hidden()
number!: number number!: number
// @Prop(TypeRef(contact.class.Employee), task.string.TaskAssignee) // @Prop(TypeRef(contact.class.Employee), task.string.TaskAssignee)

View File

@ -512,7 +512,7 @@ export function createModel (builder: Builder): void {
) )
builder.mixin(core.class.Space, core.class.Class, view.mixin.AttributePresenter, { builder.mixin(core.class.Space, core.class.Class, view.mixin.AttributePresenter, {
presenter: view.component.SpacePresenter presenter: view.component.SpaceRefPresenter
}) })
// Selection stuff // Selection stuff

View File

@ -64,7 +64,8 @@ export default mergeIds(viewId, view, {
MarkupEditor: '' as AnyComponent, MarkupEditor: '' as AnyComponent,
MarkupEditorPopup: '' as AnyComponent, MarkupEditorPopup: '' as AnyComponent,
ListView: '' as AnyComponent, ListView: '' as AnyComponent,
IndexedDocumentPreview: '' as AnyComponent IndexedDocumentPreview: '' as AnyComponent,
SpaceRefPresenter: '' as AnyComponent
}, },
string: { string: {
Table: '' as IntlString, Table: '' as IntlString,

View File

@ -150,6 +150,7 @@ export default plugin(coreId, {
Name: '' as IntlString, Name: '' as IntlString,
Enum: '' as IntlString, Enum: '' as IntlString,
Description: '' as IntlString, Description: '' as IntlString,
Hyperlink: '' as IntlString Hyperlink: '' as IntlString,
Object: '' as IntlString
} }
}) })

View File

@ -394,6 +394,34 @@ export class Hierarchy {
return result return result
} }
getOwnAttributes (clazz: Ref<Classifier>): Map<string, AnyAttribute> {
const result = new Map<string, AnyAttribute>()
const attributes = this.attributes.get(clazz)
if (attributes !== undefined) {
for (const [name, attr] of attributes) {
result.set(name, attr)
}
}
return result
}
getParentClass (_class: Ref<Class<Obj>>): Ref<Class<Obj>> {
const baseDomain = this.getDomain(_class)
const ancestors = this.getAncestors(_class)
let result: Ref<Class<Obj>> = _class
for (const ancestor of ancestors) {
try {
const domain = this.getClass(ancestor).domain
if (domain === baseDomain) {
result = ancestor
}
} catch {}
}
return result
}
getAttribute (classifier: Ref<Classifier>, name: string): AnyAttribute { getAttribute (classifier: Ref<Classifier>, name: string): AnyAttribute {
const attr = this.findAttribute(classifier, name) const attr = this.findAttribute(classifier, name)
if (attr === undefined) { if (attr === undefined) {

View File

@ -25,6 +25,7 @@
"Array": "Array", "Array": "Array",
"Enum": "Enum", "Enum": "Enum",
"Members": "Members", "Members": "Members",
"Hyperlink": "URL" "Hyperlink": "URL",
"Object": "Object"
} }
} }

View File

@ -25,6 +25,7 @@
"Array": "Массив", "Array": "Массив",
"Enum": "Справочник", "Enum": "Справочник",
"Members": "Участники", "Members": "Участники",
"Hyperlink": "URL" "Hyperlink": "URL",
"Object": "Объект"
} }
} }

View File

@ -148,18 +148,9 @@
transition-duration: 0.15s; transition-duration: 0.15s;
.btn-icon { .btn-icon {
color: var(--content-color);
transition: color 0.15s; transition: color 0.15s;
pointer-events: none; pointer-events: none;
} }
&:hover {
color: var(--accent-color);
transition-duration: 0;
.btn-icon {
color: var(--caption-color);
}
}
&.disabled { &.disabled {
color: rgb(var(--caption-color) / 40%); color: rgb(var(--caption-color) / 40%);
@ -167,6 +158,14 @@
opacity: 0.5; opacity: 0.5;
} }
} }
&:hover {
color: var(--caption-color);
transition-duration: 0;
.btn-icon {
color: var(--caption-color);
}
}
&.jf-left { &.jf-left {
justify-content: flex-start; justify-content: flex-start;

View File

@ -20,6 +20,7 @@
import view, { Viewlet, ViewletPreference } from '@hcengineering/view' import view, { Viewlet, ViewletPreference } from '@hcengineering/view'
import { import {
ActionContext, ActionContext,
FilterBar,
FilterButton, FilterButton,
getViewOptions, getViewOptions,
setActiveViewletId, setActiveViewletId,
@ -31,10 +32,11 @@
import { deviceOptionsStore as deviceInfo } from '@hcengineering/ui' import { deviceOptionsStore as deviceInfo } from '@hcengineering/ui'
let search = '' let search = ''
let resultQuery: DocumentQuery<Doc> = {} let searchQuery: DocumentQuery<Doc> = {}
let resultQuery: DocumentQuery<Doc> = searchQuery
function updateResultQuery (search: string): void { function updateResultQuery (search: string): void {
resultQuery = search === '' ? {} : { $search: search } searchQuery = search === '' ? {} : { $search: search }
} }
let viewlet: Viewlet | undefined let viewlet: Viewlet | undefined
@ -109,6 +111,13 @@
</div> </div>
</div> </div>
<FilterBar
_class={contact.class.Contact}
{viewOptions}
query={searchQuery}
on:change={(e) => (resultQuery = e.detail)}
/>
{#if viewlet} {#if viewlet}
{#if loading} {#if loading}
<Loading /> <Loading />

View File

@ -19,6 +19,7 @@
import { Button, Icon, IconAdd, Label, Loading, SearchEdit, showPopup } from '@hcengineering/ui' import { Button, Icon, IconAdd, Label, Loading, SearchEdit, showPopup } from '@hcengineering/ui'
import view, { BuildModelKey, Viewlet, ViewletPreference } from '@hcengineering/view' import view, { BuildModelKey, Viewlet, ViewletPreference } from '@hcengineering/view'
import { import {
FilterBar,
FilterButton, FilterButton,
getViewOptions, getViewOptions,
setActiveViewletId, setActiveViewletId,
@ -30,9 +31,10 @@
import { deviceOptionsStore as deviceInfo } from '@hcengineering/ui' import { deviceOptionsStore as deviceInfo } from '@hcengineering/ui'
let search: string = '' let search: string = ''
let searchQuery: DocumentQuery<Doc> = {}
let resultQuery: DocumentQuery<Doc> = {} let resultQuery: DocumentQuery<Doc> = {}
$: resultQuery = search === '' ? {} : { $search: search } $: searchQuery = search === '' ? {} : { $search: search }
type ApplicationInfo = { count: number; modifiedOn: number } type ApplicationInfo = { count: number; modifiedOn: number }
let applications: Map<Ref<Vacancy>, ApplicationInfo> = new Map<Ref<Vacancy>, ApplicationInfo>() let applications: Map<Ref<Vacancy>, ApplicationInfo> = new Map<Ref<Vacancy>, ApplicationInfo>()
@ -169,6 +171,13 @@
</div> </div>
</div> </div>
<FilterBar
_class={recruit.class.Vacancy}
{viewOptions}
query={searchQuery}
on:change={(e) => (resultQuery = e.detail)}
/>
{#if descr} {#if descr}
{#if loading} {#if loading}
<Loading /> <Loading />

View File

@ -123,8 +123,8 @@
} }
} }
const filtredKeys = Array.from(keysMap.values()) const filtredKeys = Array.from(keysMap.values())
const { attributes, collections } = categorizeFields(hierarchy, filtredKeys, collectionArrays, allowedCollections) const { attributes, collections } = categorizeFields(hierarchy, filtredKeys, collectionArrays, allowedCollections)
keys = attributes.map((it) => it.key) keys = attributes.map((it) => it.key)
const editors: { key: KeyedAttribute; editor: AnyComponent; category: AttributeCategory }[] = [] const editors: { key: KeyedAttribute; editor: AnyComponent; category: AttributeCategory }[] = []
@ -171,7 +171,7 @@
$: getEditorOrDefault(realObjectClass, showAllMixins, _id) $: getEditorOrDefault(realObjectClass, showAllMixins, _id)
function getEditorOrDefault (_class: Ref<Class<Doc>>, showAllMixins: boolean, _id: Ref<Doc>): void { function getEditorOrDefault (_class: Ref<Class<Doc>>, showAllMixins: boolean, _id: Ref<Doc>): void {
parentClass = getParentClass(_class) parentClass = hierarchy.getParentClass(_class)
mainEditor = getEditor(_class) mainEditor = getEditor(_class)
updateKeys(showAllMixins) updateKeys(showAllMixins)
} }
@ -210,21 +210,6 @@
$: icon = getIcon(realObjectClass) $: icon = getIcon(realObjectClass)
function getParentClass (_class: Ref<Class<Doc>>): Ref<Class<Doc>> {
const baseDomain = hierarchy.getDomain(_class)
const ancestors = hierarchy.getAncestors(_class)
let result: Ref<Class<Doc>> = _class
for (const ancestor of ancestors) {
try {
const domain = hierarchy.getClass(ancestor).domain
if (domain === baseDomain) {
result = ancestor
}
} catch {}
}
return result
}
let title: string = '' let title: string = ''
$: if (object !== undefined) { $: if (object !== undefined) {

View File

@ -34,7 +34,7 @@
_id: type.of _id: type.of
}, },
(res) => { (res) => {
items = res[0].enumValues.map((p) => { items = res[0]?.enumValues?.map((p) => {
return { id: p, label: p } return { id: p, label: p }
}) })
}, },

View File

@ -0,0 +1,22 @@
<!--
// Copyright © 2023 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 core, { Ref, Space } from '@hcengineering/core'
import { ObjectPresenter } from '..'
export let value: Ref<Space>
</script>
<ObjectPresenter objectId={value} _class={core.class.Space} />

View File

@ -14,10 +14,17 @@
--> -->
<script lang="ts"> <script lang="ts">
import core, { AnyAttribute, ArrOf, Class, Doc, Ref, Type } from '@hcengineering/core' import core, { AnyAttribute, ArrOf, Class, Doc, Ref, Type } from '@hcengineering/core'
import { IntlString } from '@hcengineering/platform' import { Asset, IntlString } from '@hcengineering/platform'
import preferencePlugin from '@hcengineering/preference' import preferencePlugin from '@hcengineering/preference'
import presentation, { Card, createQuery, getAttributePresenterClass, getClient } from '@hcengineering/presentation' import presentation, { Card, createQuery, getAttributePresenterClass, getClient } from '@hcengineering/presentation'
import { Button, getPlatformColorForText, ToggleButton } from '@hcengineering/ui' import {
Button,
getEventPositionElement,
getPlatformColorForText,
SelectPopup,
showPopup,
ToggleButton
} from '@hcengineering/ui'
import { BuildModelKey, Viewlet, ViewletPreference } from '@hcengineering/view' import { BuildModelKey, Viewlet, ViewletPreference } from '@hcengineering/view'
import { deepEqual } from 'fast-equals' import { deepEqual } from 'fast-equals'
import { createEventDispatcher } from 'svelte' import { createEventDispatcher } from 'svelte'
@ -55,14 +62,16 @@
label: IntlString label: IntlString
value: string | BuildModelKey value: string | BuildModelKey
_class: Ref<Class<Doc>> _class: Ref<Class<Doc>>
icon: Asset | undefined
} }
function getObjectConfig (_class: Ref<Class<Doc>>, param: string): AttributeConfig { function getObjectConfig (_class: Ref<Class<Doc>>, param: string): AttributeConfig {
const clazz = client.getHierarchy().getClass(_class) const clazz = hierarchy.getClass(_class)
return { return {
value: param, value: param,
label: clazz.label, label: clazz.label,
enabled: true, enabled: true,
icon: clazz.icon,
_class _class
} }
} }
@ -70,6 +79,7 @@
function getBaseConfig (viewlet: Viewlet): AttributeConfig[] { function getBaseConfig (viewlet: Viewlet): AttributeConfig[] {
const lookup = buildConfigLookup(hierarchy, viewlet.attachTo, viewlet.config, viewlet.options?.lookup) const lookup = buildConfigLookup(hierarchy, viewlet.attachTo, viewlet.config, viewlet.options?.lookup)
const result: AttributeConfig[] = [] const result: AttributeConfig[] = []
const clazz = hierarchy.getClass(viewlet.attachTo)
for (const param of viewlet.config) { for (const param of viewlet.config) {
if (typeof param === 'string') { if (typeof param === 'string') {
if (param.length === 0) { if (param.length === 0) {
@ -79,7 +89,8 @@
value: param, value: param,
enabled: true, enabled: true,
label: getKeyLabel(client, viewlet.attachTo, param, lookup), label: getKeyLabel(client, viewlet.attachTo, param, lookup),
_class: viewlet.attachTo _class: viewlet.attachTo,
icon: clazz.icon
}) })
} }
} else { } else {
@ -87,7 +98,8 @@
value: param, value: param,
label: param.label as IntlString, label: param.label as IntlString,
enabled: true, enabled: true,
_class: viewlet.attachTo _class: viewlet.attachTo,
icon: clazz.icon
}) })
} }
} }
@ -126,13 +138,15 @@
parent = pclazz.extends parent = pclazz.extends
} }
if (presenter === undefined) return if (presenter === undefined) return
const clazz = hierarchy.getClass(attribute.attributeOf)
if (useMixinProxy) { if (useMixinProxy) {
const newValue = { const newValue = {
value: attribute.attributeOf + '.' + attribute.name, value: attribute.attributeOf + '.' + attribute.name,
label: attribute.label, label: attribute.label,
enabled: false, enabled: false,
_class: attribute.attributeOf _class: attribute.attributeOf,
icon: clazz.icon
} }
if (!isExist(result, newValue)) { if (!isExist(result, newValue)) {
result.push(newValue) result.push(newValue)
@ -142,7 +156,8 @@
value, value,
label: attribute.label, label: attribute.label,
enabled: false, enabled: false,
_class: attribute.attributeOf _class: attribute.attributeOf,
icon: clazz.icon
} }
if (!isExist(result, newValue)) { if (!isExist(result, newValue)) {
result.push(newValue) result.push(newValue)
@ -169,11 +184,21 @@
} }
hierarchy.getDescendants(viewlet.attachTo).forEach((it) => { hierarchy.getDescendants(viewlet.attachTo).forEach((it) => {
const ancestor = hierarchy.getAncestors(it)[1] hierarchy.getOwnAttributes(it).forEach((attr) => {
hierarchy.getAllAttributes(it, ancestor).forEach((attr) => { processAttribute(attr, result, true)
if (attr.isCustom === true) { })
})
const ancestors = new Set(hierarchy.getAncestors(viewlet.attachTo))
const parent = hierarchy.getParentClass(viewlet.attachTo)
const parentMixins = hierarchy
.getDescendants(parent)
.map((p) => hierarchy.getClass(p))
.filter((p) => hierarchy.isMixin(p._id) && p.extends && ancestors.has(p.extends))
parentMixins.forEach((it) => {
hierarchy.getOwnAttributes(it._id).forEach((attr) => {
processAttribute(attr, result, true) processAttribute(attr, result, true)
}
}) })
}) })
@ -252,6 +277,24 @@
const color = getPlatformColorForText(attribute._class) const color = getPlatformColorForText(attribute._class)
return `border: 1px solid ${color + (attribute.enabled ? 'ff' : 'cc')};` return `border: 1px solid ${color + (attribute.enabled ? 'ff' : 'cc')};`
} }
function groupByClasses (attributes: AttributeConfig[]): Map<Ref<Class<Doc>>, AttributeConfig[]> {
const res = new Map()
for (const attribute of attributes) {
if (attribute.enabled) continue
const arr = res.get(attribute._class) ?? []
arr.push(attribute)
res.set(attribute._class, arr)
}
return res
}
$: enabled = attributes.filter((p) => p.enabled)
$: classes = groupByClasses(attributes)
function getClassLabel (_class: Ref<Class<Doc>>): IntlString {
return hierarchy.getClass(_class).label
}
</script> </script>
<Card <Card
@ -264,7 +307,7 @@
}} }}
> >
<div class="flex-row-stretch flex-wrap"> <div class="flex-row-stretch flex-wrap">
{#each attributes as attribute, i} {#each enabled as attribute, i}
<div <div
class="m-0-5 border-radius-1 overflow-label" class="m-0-5 border-radius-1 overflow-label"
style={getStyle(attribute)} style={getStyle(attribute)}
@ -281,7 +324,41 @@
selected = undefined selected = undefined
}} }}
> >
<ToggleButton backgroundColor={getColor(attribute)} label={attribute.label} bind:value={attribute.enabled} /> <ToggleButton
backgroundColor={getColor(attribute)}
icon={attribute.icon}
label={attribute.label}
bind:value={attribute.enabled}
/>
</div>
{/each}
</div>
<div class="flex-row-stretch flex-wrap">
{#each Array.from(classes.keys()) as _class}
<div class="m-0-5">
<Button
label={getClassLabel(_class)}
on:click={(e) => {
showPopup(
SelectPopup,
{
value: classes.get(_class)?.map((it) => ({ id: it.value, label: it.label }))
},
getEventPositionElement(e),
(val) => {
console.log('val')
console.log(val)
if (val !== undefined) {
const value = classes.get(_class)?.find((it) => it.value === val)
if (value) {
value.enabled = true
attributes = attributes
}
}
}
)
}}
/>
</div> </div>
{/each} {/each}
</div> </div>

View File

@ -22,11 +22,20 @@
Doc, Doc,
Ref, Ref,
RefTo, RefTo,
Type, Space,
Space Type
} from '@hcengineering/core' } from '@hcengineering/core'
import { getClient } from '@hcengineering/presentation' import { getClient } from '@hcengineering/presentation'
import { closePopup, closeTooltip, Icon, Label, showPopup, Submenu, resizeObserver } from '@hcengineering/ui' import {
closePopup,
closeTooltip,
Icon,
Label,
resizeObserver,
Scroller,
showPopup,
Submenu
} from '@hcengineering/ui'
import { Filter, KeyFilter } from '@hcengineering/view' import { Filter, KeyFilter } from '@hcengineering/view'
import { createEventDispatcher } from 'svelte' import { createEventDispatcher } from 'svelte'
import { FilterQuery } from '../../filter' import { FilterQuery } from '../../filter'
@ -86,9 +95,6 @@
} }
function buildFilterForAttr (_class: Ref<Class<Doc>>, attribute: AnyAttribute, result: KeyFilter[]): void { function buildFilterForAttr (_class: Ref<Class<Doc>>, attribute: AnyAttribute, result: KeyFilter[]): void {
if (attribute.isCustom !== true) {
return
}
if (attribute.label === undefined || attribute.hidden) { if (attribute.label === undefined || attribute.hidden) {
return return
} }
@ -101,6 +107,7 @@
result.push(filter) result.push(filter)
} }
} }
function buildFilterFor ( function buildFilterFor (
_class: Ref<Class<Doc>>, _class: Ref<Class<Doc>>,
allAttributes: Map<string, AnyAttribute>, allAttributes: Map<string, AnyAttribute>,
@ -118,7 +125,7 @@
const desc = hierarchy.getDescendants(_class) const desc = hierarchy.getDescendants(_class)
for (const d of desc) { for (const d of desc) {
const extra = hierarchy.getAllAttributes(d, _class) const extra = hierarchy.getOwnAttributes(d)
for (const [k, v] of extra) { for (const [k, v] of extra) {
if (!allAttributes.has(k)) { if (!allAttributes.has(k)) {
allAttributes.set(k, v) allAttributes.set(k, v)
@ -127,6 +134,23 @@
} }
} }
const ancestors = new Set(hierarchy.getAncestors(_class))
const parent = hierarchy.getParentClass(_class)
const parentMixins = hierarchy
.getDescendants(parent)
.map((p) => hierarchy.getClass(p))
.filter((p) => hierarchy.isMixin(p._id) && p.extends && ancestors.has(p.extends))
for (const d of parentMixins) {
const extra = hierarchy.getOwnAttributes(d._id)
for (const [k, v] of extra) {
if (!allAttributes.has(k)) {
allAttributes.set(k, v)
buildFilterForAttr(d._id, v, result)
}
}
}
return result return result
} }
@ -207,8 +231,7 @@
</script> </script>
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}> <div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}>
<div class="scroll"> <Scroller>
<div class="box">
{#each getTypes(_class) as type, i} {#each getTypes(_class) as type, i}
{#if filter === undefined && type.component === view.component.ObjectFilter && hasNested(type)} {#if filter === undefined && type.component === view.component.ObjectFilter && hasNested(type)}
<Submenu <Submenu
@ -243,8 +266,7 @@
</button> </button>
{/if} {/if}
{/each} {/each}
</div> </Scroller>
</div>
</div> </div>
<style lang="scss"> <style lang="scss">

View File

@ -62,6 +62,7 @@ import TimestampPresenter from './components/TimestampPresenter.svelte'
import UpDownNavigator from './components/UpDownNavigator.svelte' import UpDownNavigator from './components/UpDownNavigator.svelte'
import ValueSelector from './components/ValueSelector.svelte' import ValueSelector from './components/ValueSelector.svelte'
import ViewletSettingButton from './components/ViewletSettingButton.svelte' import ViewletSettingButton from './components/ViewletSettingButton.svelte'
import SpaceRefPresenter from './components/SpaceRefPresenter.svelte'
import { import {
afterResult, afterResult,
@ -172,7 +173,8 @@ export default async (): Promise<Resources> => ({
HTMLEditor, HTMLEditor,
ListView, ListView,
GrowPresenter, GrowPresenter,
IndexedDocumentPreview IndexedDocumentPreview,
SpaceRefPresenter
}, },
popup: { popup: {
PositionElementAlignment PositionElementAlignment