Fix indexes, use DocIndexState for fields shown in search (#4341)

* fix indexes, rework to use DocIndexState

Signed-off-by: Vyacheslav Tumanov <me@slavatumanov.me>

* fix icons for issues

Signed-off-by: Vyacheslav Tumanov <me@slavatumanov.me>

* remove commented lines

Signed-off-by: Vyacheslav Tumanov <me@slavatumanov.me>

---------

Signed-off-by: Vyacheslav Tumanov <me@slavatumanov.me>
This commit is contained in:
Vyacheslav Tumanov 2024-01-13 13:56:43 +05:00 committed by GitHub
parent 5d2f274089
commit a1690d6c0f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 57 additions and 27 deletions

View File

@ -20,11 +20,11 @@
import IssueStatusIcon from './IssueStatusIcon.svelte' import IssueStatusIcon from './IssueStatusIcon.svelte'
export let status: string export let status: string | string[]
export let space: Ref<Space> export let space: Ref<Space> | Ref<Space>[]
$: st = $statusStore.byId.get(status as Ref<Status>) $: st = $statusStore.byId.get(Array.isArray(status) ? (status[0] as Ref<Status>) : (status as Ref<Status>))
$: spaceProject = space as Ref<Project> $: spaceProject = Array.isArray(space) ? (space[0] as Ref<Project>) : (space as Ref<Project>)
</script> </script>
{#if st} {#if st}

View File

@ -178,7 +178,7 @@ export class FullTextPushStage implements FullTextPipelineStage {
} }
} }
} }
const parentDoc: DocIndexState | undefined = undefined
if (doc.attachedToClass != null && doc.attachedTo != null) { if (doc.attachedToClass != null && doc.attachedTo != null) {
const propagate: Ref<Class<Doc>>[] = collectPropagate(pipeline, doc.attachedToClass) const propagate: Ref<Class<Doc>>[] = collectPropagate(pipeline, doc.attachedToClass)
if (propagate.some((it) => pipeline.hierarchy.isDerived(doc.objectClass, it))) { if (propagate.some((it) => pipeline.hierarchy.isDerived(doc.objectClass, it))) {
@ -210,13 +210,21 @@ export class FullTextPushStage implements FullTextPipelineStage {
} }
} }
} }
const [spaceDoc] = await metrics.with(
'find-space',
{},
async (ctx) =>
await this.dbStorage.findAll(ctx, core.class.DocIndexState, {
_id: doc.space as any as Ref<DocIndexState>
})
)
const allAttributes = pipeline.hierarchy.getAllAttributes(elasticDoc._class) const allAttributes = pipeline.hierarchy.getAllAttributes(elasticDoc._class)
// Include child ref attributes // Include child ref attributes
await this.indexRefAttributes(allAttributes, doc, elasticDoc, metrics) await this.indexRefAttributes(allAttributes, doc, elasticDoc, metrics)
await updateDocWithPresenter(pipeline.hierarchy, elasticDoc) await updateDocWithPresenter(pipeline.hierarchy, doc, elasticDoc, { parentDoc, spaceDoc })
this.checkIntegrity(elasticDoc) this.checkIntegrity(elasticDoc)
bulk.push(elasticDoc) bulk.push(elasticDoc)

View File

@ -107,4 +107,4 @@ export const fieldStateId = 'fld-v11'
/** /**
* @public * @public
*/ */
export const fullTextPushStageId = 'fts-v7' export const fullTextPushStageId = 'fts-v8'

View File

@ -1,8 +1,8 @@
import { Hierarchy, Ref, RefTo, Class, Doc, SearchResultDoc, docKey } from '@hcengineering/core' import { Class, Doc, DocIndexState, docKey, Hierarchy, Ref, RefTo, SearchResultDoc } from '@hcengineering/core'
import { getResource } from '@hcengineering/platform' import { getResource } from '@hcengineering/platform'
import plugin from './plugin' import plugin from './plugin'
import { IndexedDoc, SearchPresenter, ClassSearchConfigProps, SearchScoring } from './types' import { ClassSearchConfigProps, IndexedDoc, SearchPresenter, SearchScoring } from './types'
interface IndexedReader { interface IndexedReader {
get: (attribute: string) => any get: (attribute: string) => any
@ -13,22 +13,26 @@ interface IndexedReader {
function createIndexedReader ( function createIndexedReader (
_class: Ref<Class<Doc>>, _class: Ref<Class<Doc>>,
hierarchy: Hierarchy, hierarchy: Hierarchy,
doc: IndexedDoc, doc: DocIndexState,
otherDocs?: Record<string, DocIndexState | undefined>,
refAttribute?: string refAttribute?: string
): IndexedReader { ): IndexedReader {
return { return {
get: (attr: string) => { get: (attr: string) => {
const realAttr = hierarchy.findAttribute(_class, attr) const realAttr = hierarchy.findAttribute(_class, attr)
if (realAttr !== undefined) { if (realAttr !== undefined) {
return doc[docKey(attr, { refAttribute, _class: realAttr.attributeOf })] return doc.attributes[docKey(attr, { refAttribute, _class: realAttr.attributeOf })]
} }
return undefined return undefined
}, },
getDoc: (attr: string) => { getDoc: (attr: string) => {
const realAttr = hierarchy.findAttribute(_class, attr) const realAttr = hierarchy.findAttribute(_class, attr)
if (realAttr !== undefined) { if (realAttr !== undefined) {
const refAtrr = realAttr.type as RefTo<Doc> const anotherDoc = otherDocs?.[attr]
return createIndexedReader(refAtrr.to, hierarchy, doc, docKey(attr, { _class })) if (anotherDoc !== undefined) {
const refAtrr = realAttr.type as RefTo<Doc>
return createIndexedReader(refAtrr.to, hierarchy, anotherDoc, otherDocs, docKey(attr, { _class }))
}
} }
return undefined return undefined
} }
@ -66,13 +70,24 @@ function findSearchPresenter (hierarchy: Hierarchy, _class: Ref<Class<Doc>>): Se
/** /**
* @public * @public
*/ */
export async function updateDocWithPresenter (hierarchy: Hierarchy, doc: IndexedDoc): Promise<void> { export async function updateDocWithPresenter (
const searchPresenter = findSearchPresenter(hierarchy, doc._class) hierarchy: Hierarchy,
doc: DocIndexState,
elasticDoc: IndexedDoc,
refDocs: {
parentDoc: DocIndexState | undefined
spaceDoc: DocIndexState | undefined
}
): Promise<void> {
const searchPresenter = findSearchPresenter(hierarchy, elasticDoc._class)
if (searchPresenter === undefined) { if (searchPresenter === undefined) {
return return
} }
const reader = createIndexedReader(doc._class, hierarchy, doc) const reader = createIndexedReader(elasticDoc._class, hierarchy, doc, {
space: refDocs.spaceDoc,
attachedTo: refDocs.parentDoc
})
const props = [ const props = [
{ {
@ -80,7 +95,7 @@ export async function updateDocWithPresenter (hierarchy: Hierarchy, doc: Indexed
config: searchPresenter.searchConfig.title, config: searchPresenter.searchConfig.title,
provider: searchPresenter.getSearchTitle provider: searchPresenter.getSearchTitle
} }
] ] as any[]
if (searchPresenter.searchConfig.shortTitle !== undefined) { if (searchPresenter.searchConfig.shortTitle !== undefined) {
props.push({ props.push({
@ -90,20 +105,29 @@ export async function updateDocWithPresenter (hierarchy: Hierarchy, doc: Indexed
}) })
} }
if (searchPresenter.searchConfig.iconConfig !== undefined) {
props.push({
name: 'searchIcon',
config: searchPresenter.searchConfig.iconConfig
})
}
for (const prop of props) { for (const prop of props) {
let value let value
if (typeof prop.config === 'string') { if (prop.config.tmpl !== undefined) {
value = reader.get(prop.config)
} else if (prop.config.tmpl !== undefined) {
const tmpl = prop.config.tmpl const tmpl = prop.config.tmpl
const renderProps = readAndMapProps(reader, prop.config.props) const renderProps = readAndMapProps(reader, prop.config.props)
value = fillTemplate(tmpl, renderProps) value = fillTemplate(tmpl, renderProps)
} else if (typeof prop.config === 'string') {
value = reader.get(prop.config)
} else if (prop.provider !== undefined) { } else if (prop.provider !== undefined) {
const func = await getResource(prop.provider) const func = (await getResource(prop.provider)) as any
const renderProps = readAndMapProps(reader, prop.config.props) const renderProps = readAndMapProps(reader, prop.config.props)
value = func(hierarchy, { _class: doc._class, ...renderProps }) value = func(hierarchy, { _class: elasticDoc._class, ...renderProps })
} else if (prop.name === 'searchIcon') {
value = readAndMapProps(reader, prop.config.props)
} }
doc[prop.name] = value elasticDoc[prop.name] = value
} }
} }
@ -126,6 +150,7 @@ export function mapSearchResultDoc (hierarchy: Hierarchy, raw: IndexedDoc): Sear
id: raw.id, id: raw.id,
title: raw.searchTitle, title: raw.searchTitle,
shortTitle: raw.searchShortTitle, shortTitle: raw.searchShortTitle,
iconProps: raw.searchIcon,
doc: { doc: {
_id: raw.id, _id: raw.id,
_class: raw._class _class: raw._class
@ -138,10 +163,6 @@ export function mapSearchResultDoc (hierarchy: Hierarchy, raw: IndexedDoc): Sear
} }
if (searchPresenter?.searchConfig.iconConfig !== undefined) { if (searchPresenter?.searchConfig.iconConfig !== undefined) {
doc.iconComponent = searchPresenter.searchConfig.iconConfig.component doc.iconComponent = searchPresenter.searchConfig.iconConfig.component
doc.iconProps = readAndMapProps(
createIndexedReader(raw._class, hierarchy, raw),
searchPresenter.searchConfig.iconConfig.props
)
} }
return doc return doc

View File

@ -165,6 +165,7 @@ export interface IndexedDoc {
attachedToClass?: Ref<Class<Doc>> attachedToClass?: Ref<Class<Doc>>
searchTitle?: string searchTitle?: string
searchShortTitle?: string searchShortTitle?: string
searchIcon?: any
[key: string]: any [key: string]: any
} }