mirror of
https://github.com/hcengineering/platform.git
synced 2024-11-22 03:14:40 +03:00
Indexer step 1 (#6798)
Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
parent
ec696d029b
commit
70a1666a57
@ -19,7 +19,8 @@ import {
|
|||||||
makeCollaborativeDoc,
|
makeCollaborativeDoc,
|
||||||
type TxOperations,
|
type TxOperations,
|
||||||
type Blob,
|
type Blob,
|
||||||
collaborativeDocParse
|
collaborativeDocParse,
|
||||||
|
type Data
|
||||||
} from '@hcengineering/core'
|
} from '@hcengineering/core'
|
||||||
import { yDocToBuffer } from '@hcengineering/collaboration'
|
import { yDocToBuffer } from '@hcengineering/collaboration'
|
||||||
import document, { type Document, type Teamspace, getFirstRank } from '@hcengineering/document'
|
import document, { type Document, type Teamspace, getFirstRank } from '@hcengineering/document'
|
||||||
@ -325,16 +326,17 @@ async function createDBPageWithAttachments (
|
|||||||
documentMetaMap?: Map<string, DocumentMetadata>
|
documentMetaMap?: Map<string, DocumentMetadata>
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const pageId = docMeta.id as Ref<Document>
|
const pageId = docMeta.id as Ref<Document>
|
||||||
const collabId = makeCollaborativeDoc(pageId, 'content')
|
const collabId = makeCollaborativeDoc(pageId, 'description')
|
||||||
|
|
||||||
const parentId = parentMeta !== undefined ? (parentMeta.id as Ref<Document>) : document.ids.NoParent
|
const parentId = parentMeta !== undefined ? (parentMeta.id as Ref<Document>) : document.ids.NoParent
|
||||||
|
|
||||||
const lastRank = await getFirstRank(client, space, parentId)
|
const lastRank = await getFirstRank(client, space, parentId)
|
||||||
const rank = makeRank(lastRank, undefined)
|
const rank = makeRank(lastRank, undefined)
|
||||||
|
|
||||||
const object: AttachedData<Document> = {
|
const object: Data<Document> = {
|
||||||
name: docMeta.name,
|
title: docMeta.name,
|
||||||
content: collabId,
|
description: collabId,
|
||||||
|
parent: parentId,
|
||||||
attachments: 0,
|
attachments: 0,
|
||||||
children: 0,
|
children: 0,
|
||||||
embeddings: 0,
|
embeddings: 0,
|
||||||
@ -344,15 +346,7 @@ async function createDBPageWithAttachments (
|
|||||||
rank
|
rank
|
||||||
}
|
}
|
||||||
|
|
||||||
await client.addCollection(
|
await client.createDoc(document.class.Document, space, object, pageId)
|
||||||
document.class.Document,
|
|
||||||
space,
|
|
||||||
parentId,
|
|
||||||
document.class.Document,
|
|
||||||
'children',
|
|
||||||
object,
|
|
||||||
pageId
|
|
||||||
)
|
|
||||||
|
|
||||||
const dbPage: DocumentMetadata = {
|
const dbPage: DocumentMetadata = {
|
||||||
id: pageId,
|
id: pageId,
|
||||||
@ -466,7 +460,7 @@ async function importPageDocument (
|
|||||||
}
|
}
|
||||||
|
|
||||||
const id = docMeta.id as Ref<Document>
|
const id = docMeta.id as Ref<Document>
|
||||||
const collabId = makeCollaborativeDoc(id, 'content')
|
const collabId = makeCollaborativeDoc(id, 'description')
|
||||||
const yDoc = jsonToYDocNoSchema(json, 'content')
|
const yDoc = jsonToYDocNoSchema(json, 'content')
|
||||||
const { documentId } = collaborativeDocParse(collabId)
|
const { documentId } = collaborativeDocParse(collabId)
|
||||||
const buffer = yDocToBuffer(yDoc)
|
const buffer = yDocToBuffer(yDoc)
|
||||||
@ -482,14 +476,15 @@ async function importPageDocument (
|
|||||||
|
|
||||||
await uploadFile(docMeta.id, form)
|
await uploadFile(docMeta.id, form)
|
||||||
|
|
||||||
const parentId = parentMeta?.id ?? document.ids.NoParent
|
const parent = (parentMeta?.id as Ref<Document>) ?? document.ids.NoParent
|
||||||
|
|
||||||
const lastRank = await getFirstRank(client, space, parentId as Ref<Document>)
|
const lastRank = await getFirstRank(client, space, parent)
|
||||||
const rank = makeRank(lastRank, undefined)
|
const rank = makeRank(lastRank, undefined)
|
||||||
|
|
||||||
const attachedData: AttachedData<Document> = {
|
const attachedData: Data<Document> = {
|
||||||
name: docMeta.name,
|
title: docMeta.name,
|
||||||
content: collabId,
|
description: collabId,
|
||||||
|
parent,
|
||||||
attachments: 0,
|
attachments: 0,
|
||||||
children: 0,
|
children: 0,
|
||||||
embeddings: 0,
|
embeddings: 0,
|
||||||
@ -499,15 +494,7 @@ async function importPageDocument (
|
|||||||
rank
|
rank
|
||||||
}
|
}
|
||||||
|
|
||||||
await client.addCollection(
|
await client.createDoc(document.class.Document, space, attachedData, id)
|
||||||
document.class.Document,
|
|
||||||
space,
|
|
||||||
parentId as Ref<Document>,
|
|
||||||
document.class.Document,
|
|
||||||
'children',
|
|
||||||
attachedData,
|
|
||||||
id
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function preProcessMarkdown (json: MarkupNode, documentMetaMap: Map<string, DocumentMetadata>): void {
|
function preProcessMarkdown (json: MarkupNode, documentMetaMap: Map<string, DocumentMetadata>): void {
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
type Card,
|
||||||
|
type CollaborativeDoc,
|
||||||
DOMAIN_BLOB,
|
DOMAIN_BLOB,
|
||||||
DOMAIN_CONFIGURATION,
|
DOMAIN_CONFIGURATION,
|
||||||
DOMAIN_DOC_INDEX_STATE,
|
DOMAIN_DOC_INDEX_STATE,
|
||||||
@ -60,6 +62,7 @@ import {
|
|||||||
Prop,
|
Prop,
|
||||||
ReadOnly,
|
ReadOnly,
|
||||||
TypeBoolean,
|
TypeBoolean,
|
||||||
|
TypeCollaborativeDoc,
|
||||||
TypeFileSize,
|
TypeFileSize,
|
||||||
TypeIntlString,
|
TypeIntlString,
|
||||||
TypeRecord,
|
TypeRecord,
|
||||||
@ -111,6 +114,22 @@ export class TDoc extends TObj implements Doc {
|
|||||||
createdOn!: Timestamp
|
createdOn!: Timestamp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Model(core.class.Card, core.class.Obj)
|
||||||
|
@UX(core.string.Object)
|
||||||
|
export class TCard extends TDoc implements Card {
|
||||||
|
@Prop(TypeString(), core.string.Name)
|
||||||
|
title!: string
|
||||||
|
|
||||||
|
@Prop(TypeCollaborativeDoc(), core.string.Description)
|
||||||
|
description!: CollaborativeDoc | null
|
||||||
|
|
||||||
|
@Prop(TypeString(), core.string.Id)
|
||||||
|
identifier?: string | undefined
|
||||||
|
|
||||||
|
@Prop(TypeRef(core.class.Card), core.string.AttachedTo)
|
||||||
|
parent?: Ref<Card> | null
|
||||||
|
}
|
||||||
|
|
||||||
@Model(core.class.AttachedDoc, core.class.Doc)
|
@Model(core.class.AttachedDoc, core.class.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)
|
||||||
|
@ -44,6 +44,7 @@ import {
|
|||||||
TConfiguration,
|
TConfiguration,
|
||||||
TConfigurationElement,
|
TConfigurationElement,
|
||||||
TDoc,
|
TDoc,
|
||||||
|
TCard,
|
||||||
TDocIndexState,
|
TDocIndexState,
|
||||||
TDomainIndexConfiguration,
|
TDomainIndexConfiguration,
|
||||||
TEnum,
|
TEnum,
|
||||||
@ -160,6 +161,7 @@ export function createModel (builder: Builder): void {
|
|||||||
TEnum,
|
TEnum,
|
||||||
TTypeAny,
|
TTypeAny,
|
||||||
TTypeRelatedDocument,
|
TTypeRelatedDocument,
|
||||||
|
TCard,
|
||||||
TDocIndexState,
|
TDocIndexState,
|
||||||
TFullTextSearchContext,
|
TFullTextSearchContext,
|
||||||
TConfiguration,
|
TConfiguration,
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
import activity from '@hcengineering/activity'
|
import activity from '@hcengineering/activity'
|
||||||
import type { Class, CollaborativeDoc, CollectionSize, Domain, Rank, Role, RolesAssignment } from '@hcengineering/core'
|
import type { Class, CollaborativeDoc, CollectionSize, Domain, Rank, Role, RolesAssignment } from '@hcengineering/core'
|
||||||
import { IndexKind, Account, Ref, AccountRole } from '@hcengineering/core'
|
import { Account, AccountRole, IndexKind, Ref } from '@hcengineering/core'
|
||||||
import {
|
import {
|
||||||
type Document,
|
type Document,
|
||||||
type DocumentEmbedding,
|
type DocumentEmbedding,
|
||||||
@ -29,19 +29,19 @@ import {
|
|||||||
Collection,
|
Collection,
|
||||||
Hidden,
|
Hidden,
|
||||||
Index,
|
Index,
|
||||||
|
Mixin,
|
||||||
Model,
|
Model,
|
||||||
Prop,
|
Prop,
|
||||||
|
TypeCollaborativeDoc,
|
||||||
|
TypeCollaborativeDocVersion,
|
||||||
TypeNumber,
|
TypeNumber,
|
||||||
TypeRef,
|
TypeRef,
|
||||||
TypeString,
|
TypeString,
|
||||||
UX,
|
UX
|
||||||
TypeCollaborativeDoc,
|
|
||||||
TypeCollaborativeDocVersion,
|
|
||||||
Mixin
|
|
||||||
} from '@hcengineering/model'
|
} from '@hcengineering/model'
|
||||||
import attachment, { TAttachment } from '@hcengineering/model-attachment'
|
import attachment, { TAttachment } from '@hcengineering/model-attachment'
|
||||||
import chunter from '@hcengineering/model-chunter'
|
import chunter from '@hcengineering/model-chunter'
|
||||||
import core, { TAttachedDoc, TTypedSpace } from '@hcengineering/model-core'
|
import core, { TCard, TTypedSpace } from '@hcengineering/model-core'
|
||||||
import { createPublicLinkAction } from '@hcengineering/model-guest'
|
import { createPublicLinkAction } from '@hcengineering/model-guest'
|
||||||
import { generateClassNotificationTypes } from '@hcengineering/model-notification'
|
import { generateClassNotificationTypes } from '@hcengineering/model-notification'
|
||||||
import preference, { TPreference } from '@hcengineering/model-preference'
|
import preference, { TPreference } from '@hcengineering/model-preference'
|
||||||
@ -50,7 +50,7 @@ import tracker from '@hcengineering/model-tracker'
|
|||||||
import view, { actionTemplates, createAction } from '@hcengineering/model-view'
|
import view, { actionTemplates, createAction } from '@hcengineering/model-view'
|
||||||
import workbench from '@hcengineering/model-workbench'
|
import workbench from '@hcengineering/model-workbench'
|
||||||
import notification from '@hcengineering/notification'
|
import notification from '@hcengineering/notification'
|
||||||
import { getEmbeddedLabel, type Asset } from '@hcengineering/platform'
|
import { type Asset, getEmbeddedLabel } from '@hcengineering/platform'
|
||||||
import tags from '@hcengineering/tags'
|
import tags from '@hcengineering/tags'
|
||||||
import time, { type ToDo, type Todoable } from '@hcengineering/time'
|
import time, { type ToDo, type Todoable } from '@hcengineering/time'
|
||||||
import document from './plugin'
|
import document from './plugin'
|
||||||
@ -69,31 +69,23 @@ export class TDocumentEmbedding extends TAttachment implements DocumentEmbedding
|
|||||||
declare attachedToClass: Ref<Class<Document>>
|
declare attachedToClass: Ref<Class<Document>>
|
||||||
}
|
}
|
||||||
|
|
||||||
@Model(document.class.Document, core.class.AttachedDoc, DOMAIN_DOCUMENT)
|
@Model(document.class.Document, core.class.Card, DOMAIN_DOCUMENT)
|
||||||
@UX(document.string.Document, document.icon.Document, undefined, 'name', undefined, document.string.Documents)
|
@UX(document.string.Document, document.icon.Document, undefined, 'name', undefined, document.string.Documents)
|
||||||
export class TDocument extends TAttachedDoc implements Document, Todoable {
|
export class TDocument extends TCard implements Document, Todoable {
|
||||||
@Prop(TypeRef(document.class.Document), document.string.ParentDocument)
|
@Prop(TypeRef(document.class.Document), document.string.ParentDocument)
|
||||||
declare attachedTo: Ref<Document>
|
declare parent: Ref<Document>
|
||||||
|
|
||||||
@Prop(TypeRef(core.class.Class), core.string.AttachedToClass)
|
|
||||||
@Hidden()
|
|
||||||
declare attachedToClass: Ref<Class<Document>>
|
|
||||||
|
|
||||||
@Prop(TypeRef(core.class.Space), core.string.Space)
|
@Prop(TypeRef(core.class.Space), core.string.Space)
|
||||||
@Index(IndexKind.Indexed)
|
@Index(IndexKind.Indexed)
|
||||||
@Hidden()
|
@Hidden()
|
||||||
declare space: Ref<Teamspace>
|
declare space: Ref<Teamspace>
|
||||||
|
|
||||||
@Prop(TypeString(), core.string.Collection)
|
|
||||||
@Hidden()
|
|
||||||
override collection: 'children' = 'children'
|
|
||||||
|
|
||||||
@Prop(TypeString(), document.string.Name)
|
@Prop(TypeString(), document.string.Name)
|
||||||
@Index(IndexKind.FullText)
|
@Index(IndexKind.FullText)
|
||||||
name!: string
|
declare title: string
|
||||||
|
|
||||||
@Prop(TypeCollaborativeDoc(), document.string.Document)
|
@Prop(TypeCollaborativeDoc(), document.string.Document)
|
||||||
content!: CollaborativeDoc
|
declare description: CollaborativeDoc
|
||||||
|
|
||||||
@Prop(TypeRef(core.class.Account), document.string.LockedBy)
|
@Prop(TypeRef(core.class.Account), document.string.LockedBy)
|
||||||
@Hidden()
|
@Hidden()
|
||||||
@ -136,31 +128,24 @@ export class TDocument extends TAttachedDoc implements Document, Todoable {
|
|||||||
rank!: Rank
|
rank!: Rank
|
||||||
}
|
}
|
||||||
|
|
||||||
@Model(document.class.DocumentSnapshot, core.class.AttachedDoc, DOMAIN_DOCUMENT)
|
@Model(document.class.DocumentSnapshot, core.class.Card, DOMAIN_DOCUMENT)
|
||||||
@UX(document.string.Version)
|
@UX(document.string.Version)
|
||||||
export class TDocumentSnapshot extends TAttachedDoc implements DocumentSnapshot {
|
export class TDocumentSnapshot extends TCard implements DocumentSnapshot {
|
||||||
@Prop(TypeRef(document.class.Document), document.string.ParentDocument)
|
@Prop(TypeRef(document.class.Document), document.string.ParentDocument)
|
||||||
declare attachedTo: Ref<Document>
|
declare parent: Ref<Document>
|
||||||
|
|
||||||
@Prop(TypeRef(core.class.Class), core.string.AttachedToClass)
|
|
||||||
declare attachedToClass: Ref<Class<Document>>
|
|
||||||
|
|
||||||
@Prop(TypeRef(core.class.Space), core.string.Space)
|
@Prop(TypeRef(core.class.Space), core.string.Space)
|
||||||
@Index(IndexKind.Indexed)
|
@Index(IndexKind.Indexed)
|
||||||
@Hidden()
|
@Hidden()
|
||||||
declare space: Ref<Teamspace>
|
declare space: Ref<Teamspace>
|
||||||
|
|
||||||
@Prop(TypeString(), core.string.Collection)
|
|
||||||
@Hidden()
|
|
||||||
override collection: 'snapshots' = 'snapshots'
|
|
||||||
|
|
||||||
@Prop(TypeString(), document.string.Name)
|
@Prop(TypeString(), document.string.Name)
|
||||||
@Index(IndexKind.FullText)
|
@Index(IndexKind.FullText)
|
||||||
name!: string
|
declare title: string
|
||||||
|
|
||||||
@Prop(TypeCollaborativeDocVersion(), document.string.Document)
|
@Prop(TypeCollaborativeDocVersion(), document.string.Document)
|
||||||
@Hidden()
|
@Hidden()
|
||||||
content!: CollaborativeDoc
|
declare description: CollaborativeDoc
|
||||||
}
|
}
|
||||||
|
|
||||||
@Model(document.class.SavedDocument, preference.class.Preference)
|
@Model(document.class.SavedDocument, preference.class.Preference)
|
||||||
|
@ -14,21 +14,21 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import { DOMAIN_TX, MeasureMetricsContext, SortingOrder } from '@hcengineering/core'
|
import { DOMAIN_TX, MeasureMetricsContext, SortingOrder } from '@hcengineering/core'
|
||||||
import { type Document, type Teamspace } from '@hcengineering/document'
|
import { type DocumentSnapshot, type Document, type Teamspace } from '@hcengineering/document'
|
||||||
import {
|
import {
|
||||||
|
tryMigrate,
|
||||||
type MigrateOperation,
|
type MigrateOperation,
|
||||||
type MigrationClient,
|
|
||||||
type MigrationUpgradeClient,
|
|
||||||
type MigrateUpdate,
|
type MigrateUpdate,
|
||||||
|
type MigrationClient,
|
||||||
type MigrationDocumentQuery,
|
type MigrationDocumentQuery,
|
||||||
tryMigrate
|
type MigrationUpgradeClient
|
||||||
} from '@hcengineering/model'
|
} from '@hcengineering/model'
|
||||||
import core, { DOMAIN_SPACE } from '@hcengineering/model-core'
|
import core, { DOMAIN_SPACE } from '@hcengineering/model-core'
|
||||||
import { type Asset } from '@hcengineering/platform'
|
import { type Asset } from '@hcengineering/platform'
|
||||||
import { makeRank } from '@hcengineering/rank'
|
import { makeRank } from '@hcengineering/rank'
|
||||||
|
|
||||||
import document, { documentId, DOMAIN_DOCUMENT } from './index'
|
|
||||||
import { loadCollaborativeDoc, saveCollaborativeDoc, yDocCopyXmlField } from '@hcengineering/collaboration'
|
import { loadCollaborativeDoc, saveCollaborativeDoc, yDocCopyXmlField } from '@hcengineering/collaboration'
|
||||||
|
import document, { documentId, DOMAIN_DOCUMENT } from './index'
|
||||||
|
|
||||||
async function migrateDocumentIcons (client: MigrationClient): Promise<void> {
|
async function migrateDocumentIcons (client: MigrationClient): Promise<void> {
|
||||||
await client.update<Teamspace>(
|
await client.update<Teamspace>(
|
||||||
@ -111,9 +111,9 @@ async function migrateContentField (client: MigrationClient): Promise<void> {
|
|||||||
|
|
||||||
for (const document of documents) {
|
for (const document of documents) {
|
||||||
try {
|
try {
|
||||||
const ydoc = await loadCollaborativeDoc(storage, client.workspaceId, document.content, ctx)
|
const ydoc = await loadCollaborativeDoc(storage, client.workspaceId, document.description, ctx)
|
||||||
if (ydoc === undefined) {
|
if (ydoc === undefined) {
|
||||||
ctx.error('document content not found', { document: document.name })
|
ctx.error('document content not found', { document: document.title })
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,9 +123,9 @@ async function migrateContentField (client: MigrationClient): Promise<void> {
|
|||||||
|
|
||||||
yDocCopyXmlField(ydoc, '', 'content')
|
yDocCopyXmlField(ydoc, '', 'content')
|
||||||
|
|
||||||
await saveCollaborativeDoc(storage, client.workspaceId, document.content, ydoc, ctx)
|
await saveCollaborativeDoc(storage, client.workspaceId, document.description, ydoc, ctx)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
ctx.error('error document content migration', { error: err, document: document.name })
|
ctx.error('error document content migration', { error: err, document: document.title })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -154,6 +154,54 @@ async function migrateRank (client: MigrationClient): Promise<void> {
|
|||||||
await client.bulk(DOMAIN_DOCUMENT, operations)
|
await client.bulk(DOMAIN_DOCUMENT, operations)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function renameFields (client: MigrationClient): Promise<void> {
|
||||||
|
const documents = await client.find<Document>(DOMAIN_DOCUMENT, {
|
||||||
|
_class: document.class.Document,
|
||||||
|
content: { $exists: true }
|
||||||
|
})
|
||||||
|
|
||||||
|
for (const document of documents) {
|
||||||
|
await client.update(
|
||||||
|
DOMAIN_DOCUMENT,
|
||||||
|
{ _id: document._id },
|
||||||
|
{
|
||||||
|
$rename: {
|
||||||
|
attachedTo: 'parent',
|
||||||
|
content: 'description',
|
||||||
|
name: 'title'
|
||||||
|
},
|
||||||
|
$unset: {
|
||||||
|
attachedToClass: '',
|
||||||
|
collection: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const spnapshots = await client.find<DocumentSnapshot>(DOMAIN_DOCUMENT, {
|
||||||
|
_class: document.class.DocumentSnapshot,
|
||||||
|
content: { $exists: true }
|
||||||
|
})
|
||||||
|
|
||||||
|
for (const snapshot of spnapshots) {
|
||||||
|
await client.update(
|
||||||
|
DOMAIN_DOCUMENT,
|
||||||
|
{ _id: snapshot._id },
|
||||||
|
{
|
||||||
|
$rename: {
|
||||||
|
attachedTo: 'parent',
|
||||||
|
content: 'description',
|
||||||
|
name: 'title'
|
||||||
|
},
|
||||||
|
$unset: {
|
||||||
|
attachedToClass: '',
|
||||||
|
collection: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const documentOperation: MigrateOperation = {
|
export const documentOperation: MigrateOperation = {
|
||||||
async migrate (client: MigrationClient): Promise<void> {
|
async migrate (client: MigrationClient): Promise<void> {
|
||||||
await tryMigrate(client, documentId, [
|
await tryMigrate(client, documentId, [
|
||||||
@ -176,6 +224,10 @@ export const documentOperation: MigrateOperation = {
|
|||||||
{
|
{
|
||||||
state: 'migrateRank',
|
state: 'migrateRank',
|
||||||
func: migrateRank
|
func: migrateRank
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: 'renameFields',
|
||||||
|
func: renameFields
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
import type { Asset, IntlString, Plugin } from '@hcengineering/platform'
|
import type { Asset, IntlString, Plugin } from '@hcengineering/platform'
|
||||||
import type { DocumentQuery } from './storage'
|
import type { DocumentQuery } from './storage'
|
||||||
|
import { CollaborativeDoc } from './collaboration'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @public
|
* @public
|
||||||
@ -73,6 +74,13 @@ export interface Doc<S extends Space = Space> extends Obj {
|
|||||||
createdOn?: Timestamp // Marked as optional since it will be filled by platform.
|
createdOn?: Timestamp // Marked as optional since it will be filled by platform.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Card extends Doc {
|
||||||
|
title: string
|
||||||
|
description: CollaborativeDoc | null
|
||||||
|
identifier?: string
|
||||||
|
parent?: Ref<Card> | null
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
|
@ -21,6 +21,7 @@ import type {
|
|||||||
ArrOf,
|
ArrOf,
|
||||||
AttachedDoc,
|
AttachedDoc,
|
||||||
Blob,
|
Blob,
|
||||||
|
Card,
|
||||||
Class,
|
Class,
|
||||||
Collection,
|
Collection,
|
||||||
Configuration,
|
Configuration,
|
||||||
@ -82,6 +83,7 @@ export default plugin(coreId, {
|
|||||||
class: {
|
class: {
|
||||||
Obj: '' as Ref<Class<Obj>>,
|
Obj: '' as Ref<Class<Obj>>,
|
||||||
Doc: '' as Ref<Class<Doc>>,
|
Doc: '' as Ref<Class<Doc>>,
|
||||||
|
Card: '' as Ref<Class<Card>>,
|
||||||
Blob: '' as Ref<Class<Blob>>,
|
Blob: '' as Ref<Class<Blob>>,
|
||||||
AttachedDoc: '' as Ref<Class<AttachedDoc>>,
|
AttachedDoc: '' as Ref<Class<AttachedDoc>>,
|
||||||
Class: '' as Ref<Class<Class<Obj>>>,
|
Class: '' as Ref<Class<Class<Obj>>>,
|
||||||
|
@ -15,9 +15,10 @@
|
|||||||
//
|
//
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { AttachedData, Ref, generateId } from '@hcengineering/core'
|
import { Analytics } from '@hcengineering/analytics'
|
||||||
import { Document, Teamspace, DocumentEvents } from '@hcengineering/document'
|
import { Data, generateId, Ref } from '@hcengineering/core'
|
||||||
import { Card, SpaceSelector, getClient } from '@hcengineering/presentation'
|
import { Document, DocumentEvents, Teamspace } from '@hcengineering/document'
|
||||||
|
import { Card, getClient, SpaceSelector } from '@hcengineering/presentation'
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
createFocusManager,
|
createFocusManager,
|
||||||
@ -31,14 +32,13 @@
|
|||||||
import view from '@hcengineering/view'
|
import view from '@hcengineering/view'
|
||||||
import { IconPicker, ObjectBox } from '@hcengineering/view-resources'
|
import { IconPicker, ObjectBox } from '@hcengineering/view-resources'
|
||||||
import { createEventDispatcher } from 'svelte'
|
import { createEventDispatcher } from 'svelte'
|
||||||
import { Analytics } from '@hcengineering/analytics'
|
|
||||||
|
|
||||||
import document from '../plugin'
|
import document from '../plugin'
|
||||||
import { createEmptyDocument } from '../utils'
|
import { createEmptyDocument } from '../utils'
|
||||||
import TeamspacePresenter from './teamspace/TeamspacePresenter.svelte'
|
import TeamspacePresenter from './teamspace/TeamspacePresenter.svelte'
|
||||||
|
|
||||||
export function canClose (): boolean {
|
export function canClose (): boolean {
|
||||||
return object.name === ''
|
return object.title === ''
|
||||||
}
|
}
|
||||||
|
|
||||||
export let space: Ref<Teamspace>
|
export let space: Ref<Teamspace>
|
||||||
@ -46,8 +46,8 @@
|
|||||||
|
|
||||||
const id: Ref<Document> = generateId()
|
const id: Ref<Document> = generateId()
|
||||||
|
|
||||||
const object: Pick<AttachedData<Document>, 'name' | 'icon' | 'color'> = {
|
const object: Pick<Data<Document>, 'title' | 'icon' | 'color'> = {
|
||||||
name: ''
|
title: ''
|
||||||
}
|
}
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
@ -57,7 +57,7 @@
|
|||||||
let _parent = parent
|
let _parent = parent
|
||||||
|
|
||||||
$: if (_space !== space) _parent = undefined
|
$: if (_space !== space) _parent = undefined
|
||||||
$: canSave = getTitle(object.name).length > 0 && _space !== undefined
|
$: canSave = getTitle(object.title).length > 0 && _space !== undefined
|
||||||
|
|
||||||
function chooseIcon (): void {
|
function chooseIcon (): void {
|
||||||
const { icon, color } = object
|
const { icon, color } = object
|
||||||
@ -75,7 +75,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function create (): Promise<void> {
|
async function create (): Promise<void> {
|
||||||
await createEmptyDocument(client, id, _space, _parent ?? document.ids.NoParent, object)
|
await createEmptyDocument(client, id, _space, _parent, object)
|
||||||
Analytics.handleEvent(DocumentEvents.DocumentCreated, { id, parent: _parent })
|
Analytics.handleEvent(DocumentEvents.DocumentCreated, { id, parent: _parent })
|
||||||
dispatch('close', id)
|
dispatch('close', id)
|
||||||
}
|
}
|
||||||
@ -140,7 +140,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<EditBox
|
<EditBox
|
||||||
placeholder={document.string.DocumentNamePlaceholder}
|
placeholder={document.string.DocumentNamePlaceholder}
|
||||||
bind:value={object.name}
|
bind:value={object.title}
|
||||||
kind={'large-style'}
|
kind={'large-style'}
|
||||||
autoFocus
|
autoFocus
|
||||||
focusIndex={1}
|
focusIndex={1}
|
||||||
|
@ -56,12 +56,12 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<CollaboratorEditor
|
<CollaboratorEditor
|
||||||
collaborativeDoc={object.content}
|
collaborativeDoc={object.description}
|
||||||
objectClass={object._class}
|
objectClass={object._class}
|
||||||
objectId={object._id}
|
objectId={object._id}
|
||||||
objectSpace={object.space}
|
objectSpace={object.space}
|
||||||
objectAttr="content"
|
objectAttr="description"
|
||||||
field="content"
|
field="description"
|
||||||
{user}
|
{user}
|
||||||
{userComponent}
|
{userComponent}
|
||||||
{focusIndex}
|
{focusIndex}
|
||||||
|
@ -28,6 +28,6 @@
|
|||||||
<DocumentIcon {value} size={'medium'} defaultIcon={document.icon.Document} />
|
<DocumentIcon {value} size={'medium'} defaultIcon={document.icon.Document} />
|
||||||
</div>
|
</div>
|
||||||
<span class="overflow-label">
|
<span class="overflow-label">
|
||||||
{value.name}
|
{value.title}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -52,13 +52,13 @@
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<span class="label nowrap" class:no-underline={noUnderline || disabled} class:fs-bold={accent}>
|
<span class="label nowrap" class:no-underline={noUnderline || disabled} class:fs-bold={accent}>
|
||||||
{value.name}
|
{value.title}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</DocNavLink>
|
</DocNavLink>
|
||||||
{:else if type === 'text'}
|
{:else if type === 'text'}
|
||||||
<span class="overflow-label" use:tooltip={{ label: document.string.Document }}>
|
<span class="overflow-label" use:tooltip={{ label: document.string.Document }}>
|
||||||
{value.name}
|
{value.title}
|
||||||
</span>
|
</span>
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -27,5 +27,5 @@
|
|||||||
<div class="icon">
|
<div class="icon">
|
||||||
<Icon icon={document.icon.DocumentApplication} size={'small'} />
|
<Icon icon={document.icon.DocumentApplication} size={'small'} />
|
||||||
</div>
|
</div>
|
||||||
{value.name}
|
{value.title}
|
||||||
</div>
|
</div>
|
||||||
|
@ -80,7 +80,7 @@
|
|||||||
const client = getClient()
|
const client = getClient()
|
||||||
|
|
||||||
let doc: WithLookup<Document> | undefined
|
let doc: WithLookup<Document> | undefined
|
||||||
let name = ''
|
let title = ''
|
||||||
let innerWidth: number
|
let innerWidth: number
|
||||||
|
|
||||||
let headings: Heading[] = []
|
let headings: Heading[] = []
|
||||||
@ -141,10 +141,10 @@
|
|||||||
$: _id !== undefined &&
|
$: _id !== undefined &&
|
||||||
query.query(document.class.Document, { _id }, async (result) => {
|
query.query(document.class.Document, { _id }, async (result) => {
|
||||||
;[doc] = result
|
;[doc] = result
|
||||||
name = doc?.name ?? ''
|
title = doc?.title ?? ''
|
||||||
})
|
})
|
||||||
|
|
||||||
$: canSave = name.trim().length > 0
|
$: canSave = title.trim().length > 0
|
||||||
|
|
||||||
async function saveTitle (ev: Event): Promise<void> {
|
async function saveTitle (ev: Event): Promise<void> {
|
||||||
ev.preventDefault()
|
ev.preventDefault()
|
||||||
@ -153,10 +153,10 @@
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const nameTrimmed = name.trim()
|
const nameTrimmed = title.trim()
|
||||||
|
|
||||||
if (nameTrimmed.length > 0 && nameTrimmed !== doc.name) {
|
if (nameTrimmed.length > 0 && nameTrimmed !== doc.title) {
|
||||||
await client.update(doc, { name: nameTrimmed })
|
await client.update(doc, { title: nameTrimmed })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -322,7 +322,7 @@
|
|||||||
<DocumentTitle
|
<DocumentTitle
|
||||||
focusIndex={1}
|
focusIndex={1}
|
||||||
fill
|
fill
|
||||||
bind:value={name}
|
bind:value={title}
|
||||||
{readonly}
|
{readonly}
|
||||||
placeholder={document.string.DocumentNamePlaceholder}
|
placeholder={document.string.DocumentNamePlaceholder}
|
||||||
on:blur={(evt) => saveTitle(evt)}
|
on:blur={(evt) => saveTitle(evt)}
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
let space: Ref<Teamspace> = value.space
|
let space: Ref<Teamspace> = value.space
|
||||||
let parent: Ref<Document> = value.attachedTo
|
let parent: Ref<Document> = value.parent
|
||||||
|
|
||||||
let children: Ref<Document>[] = []
|
let children: Ref<Document>[] = []
|
||||||
$: void updateChildren(value)
|
$: void updateChildren(value)
|
||||||
@ -58,15 +58,15 @@
|
|||||||
async function findChildren (doc: Document): Promise<Array<Ref<Document>>> {
|
async function findChildren (doc: Document): Promise<Array<Ref<Document>>> {
|
||||||
const documents = await client.findAll(
|
const documents = await client.findAll(
|
||||||
document.class.Document,
|
document.class.Document,
|
||||||
{ space: doc.space, attachedTo: { $ne: document.ids.NoParent } },
|
{ space: doc.space, parent: { $ne: document.ids.NoParent } },
|
||||||
{ projection: { _id: 1, attachedTo: 1 } }
|
{ projection: { _id: 1, parent: 1 } }
|
||||||
)
|
)
|
||||||
|
|
||||||
const byParent = new Map<Ref<Document>, Array<Ref<Document>>>()
|
const byParent = new Map<Ref<Document>, Array<Ref<Document>>>()
|
||||||
for (const document of documents) {
|
for (const document of documents) {
|
||||||
const group = byParent.get(document.attachedTo) ?? []
|
const group = byParent.get(document.parent) ?? []
|
||||||
group.push(document._id)
|
group.push(document._id)
|
||||||
byParent.set(document.attachedTo, group)
|
byParent.set(document.parent, group)
|
||||||
}
|
}
|
||||||
|
|
||||||
const result: Ref<Document>[] = []
|
const result: Ref<Document>[] = []
|
||||||
@ -83,7 +83,7 @@
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
$: canSave = space !== value.space || parent !== value.attachedTo
|
$: canSave = space !== value.space || parent !== value.parent
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Card
|
<Card
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
{#if value}
|
{#if value}
|
||||||
<div class="flex-col">
|
<div class="flex-col">
|
||||||
<span class="overflow-label mt-10px">
|
<span class="overflow-label mt-10px">
|
||||||
{value.name}
|
{value.title}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -109,7 +109,7 @@
|
|||||||
: {
|
: {
|
||||||
fill: doc.color !== undefined ? getPlatformColorDef(doc.color, $themeStore.dark).icon : 'currentColor'
|
fill: doc.color !== undefined ? getPlatformColorDef(doc.color, $themeStore.dark).icon : 'currentColor'
|
||||||
}}
|
}}
|
||||||
title={doc.name}
|
title={doc.title}
|
||||||
selected={selected === doc._id && draggedItem === undefined}
|
selected={selected === doc._id && draggedItem === undefined}
|
||||||
isFold
|
isFold
|
||||||
{level}
|
{level}
|
||||||
|
@ -99,9 +99,9 @@
|
|||||||
descendants.clear()
|
descendants.clear()
|
||||||
|
|
||||||
for (const doc of result) {
|
for (const doc of result) {
|
||||||
const current = descendants.get(doc.attachedTo) ?? []
|
const current = descendants.get(doc.parent) ?? []
|
||||||
current.push(doc)
|
current.push(doc)
|
||||||
descendants.set(doc.attachedTo, current)
|
descendants.set(doc.parent, current)
|
||||||
documentById.set(doc._id, doc)
|
documentById.set(doc._id, doc)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -243,7 +243,7 @@
|
|||||||
void moveDocumentBefore(doc, target)
|
void moveDocumentBefore(doc, target)
|
||||||
} else if (pos === 'after') {
|
} else if (pos === 'after') {
|
||||||
void moveDocumentAfter(doc, target)
|
void moveDocumentAfter(doc, target)
|
||||||
} else if (doc.attachedTo !== object) {
|
} else if (doc.parent !== object) {
|
||||||
void moveDocument(doc, target.space, target._id)
|
void moveDocument(doc, target.space, target._id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -315,7 +315,7 @@
|
|||||||
: {
|
: {
|
||||||
fill: item.color !== undefined ? getPlatformColorDef(item.color, $themeStore.dark).icon : 'currentColor'
|
fill: item.color !== undefined ? getPlatformColorDef(item.color, $themeStore.dark).icon : 'currentColor'
|
||||||
}}
|
}}
|
||||||
title={item.name}
|
title={item.title}
|
||||||
selected
|
selected
|
||||||
isFold
|
isFold
|
||||||
empty
|
empty
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
<div class="container flex-col flex-gap-2 flex-no-shrink">
|
<div class="container flex-col flex-gap-2 flex-no-shrink">
|
||||||
<div class="flex-between h-8">
|
<div class="flex-between h-8">
|
||||||
<div class="fs-bold overflow-label">
|
<div class="fs-bold overflow-label">
|
||||||
{value.name}
|
{value.title}
|
||||||
</div>
|
</div>
|
||||||
<div class="time">
|
<div class="time">
|
||||||
<TimeSince value={value.createdOn} />
|
<TimeSince value={value.createdOn} />
|
||||||
|
@ -57,7 +57,7 @@ import {
|
|||||||
|
|
||||||
const toObjectSearchResult = (e: WithLookup<Document>): ObjectSearchResult => ({
|
const toObjectSearchResult = (e: WithLookup<Document>): ObjectSearchResult => ({
|
||||||
doc: e,
|
doc: e,
|
||||||
title: e.name,
|
title: e.title,
|
||||||
icon: document.icon.Document,
|
icon: document.icon.Document,
|
||||||
component: DocumentItem
|
component: DocumentItem
|
||||||
})
|
})
|
||||||
|
@ -14,8 +14,8 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import {
|
import {
|
||||||
type AttachedData,
|
|
||||||
type Client,
|
type Client,
|
||||||
|
type Data,
|
||||||
type QuerySelector,
|
type QuerySelector,
|
||||||
type Ref,
|
type Ref,
|
||||||
SortingOrder,
|
SortingOrder,
|
||||||
@ -26,7 +26,7 @@ import { type Document, type Teamspace, documentId, getFirstRank } from '@hcengi
|
|||||||
import { getMetadata, translate } from '@hcengineering/platform'
|
import { getMetadata, translate } from '@hcengineering/platform'
|
||||||
import presentation, { getClient } from '@hcengineering/presentation'
|
import presentation, { getClient } from '@hcengineering/presentation'
|
||||||
import { makeRank } from '@hcengineering/rank'
|
import { makeRank } from '@hcengineering/rank'
|
||||||
import { getCurrentResolvedLocation, getPanelURI, type Location, type ResolvedLocation } from '@hcengineering/ui'
|
import { type Location, type ResolvedLocation, getCurrentResolvedLocation, getPanelURI } from '@hcengineering/ui'
|
||||||
import { accessDeniedStore } from '@hcengineering/view-resources'
|
import { accessDeniedStore } from '@hcengineering/view-resources'
|
||||||
import { workbenchId } from '@hcengineering/workbench'
|
import { workbenchId } from '@hcengineering/workbench'
|
||||||
import slugify from 'slugify'
|
import slugify from 'slugify'
|
||||||
@ -39,46 +39,47 @@ export async function moveDocument (doc: Document, space: Ref<Teamspace>, parent
|
|||||||
const prevRank = await getFirstRank(client, space, parent)
|
const prevRank = await getFirstRank(client, space, parent)
|
||||||
const rank = makeRank(prevRank, undefined)
|
const rank = makeRank(prevRank, undefined)
|
||||||
|
|
||||||
await client.update(doc, { space, attachedTo: parent, rank })
|
await client.update(doc, { space, parent, rank })
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function moveDocumentBefore (doc: Document, before: Document): Promise<void> {
|
export async function moveDocumentBefore (doc: Document, before: Document): Promise<void> {
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
|
|
||||||
const { space, attachedTo } = before
|
const { space, parent } = before
|
||||||
const query = { rank: { $lt: before.rank } as unknown as QuerySelector<Document['rank']> }
|
const query = { rank: { $lt: before.rank } as unknown as QuerySelector<Document['rank']> }
|
||||||
const lastRank = await getFirstRank(client, space, attachedTo, SortingOrder.Descending, query)
|
const lastRank = await getFirstRank(client, space, parent, SortingOrder.Descending, query)
|
||||||
const rank = makeRank(lastRank, before.rank)
|
const rank = makeRank(lastRank, before.rank)
|
||||||
|
|
||||||
await client.update(doc, { space, attachedTo, rank })
|
await client.update(doc, { space, parent, rank })
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function moveDocumentAfter (doc: Document, after: Document): Promise<void> {
|
export async function moveDocumentAfter (doc: Document, after: Document): Promise<void> {
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
|
|
||||||
const { space, attachedTo } = after
|
const { space, parent } = after
|
||||||
const query = { rank: { $gt: after.rank } as unknown as QuerySelector<Document['rank']> }
|
const query = { rank: { $gt: after.rank } as unknown as QuerySelector<Document['rank']> }
|
||||||
const nextRank = await getFirstRank(client, space, attachedTo, SortingOrder.Ascending, query)
|
const nextRank = await getFirstRank(client, space, parent, SortingOrder.Ascending, query)
|
||||||
const rank = makeRank(after.rank, nextRank)
|
const rank = makeRank(after.rank, nextRank)
|
||||||
|
|
||||||
await client.update(doc, { space, attachedTo, rank })
|
await client.update(doc, { space, parent, rank })
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createEmptyDocument (
|
export async function createEmptyDocument (
|
||||||
client: TxOperations,
|
client: TxOperations,
|
||||||
id: Ref<Document>,
|
id: Ref<Document>,
|
||||||
space: Ref<Teamspace>,
|
space: Ref<Teamspace>,
|
||||||
parent: Ref<Document>,
|
parentId?: Ref<Document>,
|
||||||
data: Partial<Pick<AttachedData<Document>, 'name' | 'icon' | 'color'>> = {}
|
data: Partial<Pick<Data<Document>, 'title' | 'icon' | 'color'>> = {}
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const name = await translate(document.string.Untitled, {})
|
const title = await translate(document.string.Untitled, {})
|
||||||
|
const parent = parentId ?? document.ids.NoParent
|
||||||
|
|
||||||
const lastRank = await getFirstRank(client, space, parent)
|
const lastRank = await getFirstRank(client, space, parent)
|
||||||
const rank = makeRank(lastRank, undefined)
|
const rank = makeRank(lastRank, undefined)
|
||||||
|
|
||||||
const object: AttachedData<Document> = {
|
const object: Data<Document> = {
|
||||||
name,
|
title,
|
||||||
content: makeCollaborativeDoc(id, 'content'),
|
description: makeCollaborativeDoc(id, 'description'),
|
||||||
attachments: 0,
|
attachments: 0,
|
||||||
children: 0,
|
children: 0,
|
||||||
embeddings: 0,
|
embeddings: 0,
|
||||||
@ -86,18 +87,11 @@ export async function createEmptyDocument (
|
|||||||
comments: 0,
|
comments: 0,
|
||||||
references: 0,
|
references: 0,
|
||||||
rank,
|
rank,
|
||||||
|
parent: parent ?? document.ids.NoParent,
|
||||||
...data
|
...data
|
||||||
}
|
}
|
||||||
|
|
||||||
await client.addCollection(
|
await client.createDoc(document.class.Document, space, object, id)
|
||||||
document.class.Document,
|
|
||||||
space,
|
|
||||||
parent ?? document.ids.NoParent,
|
|
||||||
document.class.Document,
|
|
||||||
'children',
|
|
||||||
object,
|
|
||||||
id
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function resolveLocation (loc: Location): Promise<ResolvedLocation | undefined> {
|
export async function resolveLocation (loc: Location): Promise<ResolvedLocation | undefined> {
|
||||||
@ -171,7 +165,7 @@ export function getDocumentLink (doc: Document): Location {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getDocumentLinkId (doc: Document): string {
|
export function getDocumentLinkId (doc: Document): string {
|
||||||
const slug = slugify(doc.name, { lower: true })
|
const slug = slugify(doc.title, { lower: true })
|
||||||
return `${slug}-${doc._id}`
|
return `${slug}-${doc._id}`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,5 +182,5 @@ export function parseDocumentId (shortLink?: string): Ref<Document> | undefined
|
|||||||
|
|
||||||
export async function documentTitleProvider (client: Client, ref: Ref<Document>, doc?: Document): Promise<string> {
|
export async function documentTitleProvider (client: Client, ref: Ref<Document>, doc?: Document): Promise<string> {
|
||||||
const object = doc ?? (await client.findOne(document.class.Document, { _id: ref }))
|
const object = doc ?? (await client.findOne(document.class.Document, { _id: ref }))
|
||||||
return object?.name ?? ''
|
return object?.title ?? ''
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import { Attachment } from '@hcengineering/attachment'
|
import { Attachment } from '@hcengineering/attachment'
|
||||||
import { Account, AttachedDoc, Class, CollaborativeDoc, Rank, Ref, TypedSpace } from '@hcengineering/core'
|
import { Account, Card, Class, CollaborativeDoc, Rank, Ref, TypedSpace } from '@hcengineering/core'
|
||||||
import { Preference } from '@hcengineering/preference'
|
import { Preference } from '@hcengineering/preference'
|
||||||
import { IconProps } from '@hcengineering/view'
|
import { IconProps } from '@hcengineering/view'
|
||||||
|
|
||||||
@ -22,11 +22,12 @@ import { IconProps } from '@hcengineering/view'
|
|||||||
export interface Teamspace extends TypedSpace, IconProps {}
|
export interface Teamspace extends TypedSpace, IconProps {}
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export interface Document extends AttachedDoc<Document, 'children', Teamspace>, IconProps {
|
export interface Document extends Card, IconProps {
|
||||||
attachedTo: Ref<Document>
|
parent: Ref<Document>
|
||||||
|
|
||||||
name: string
|
description: CollaborativeDoc
|
||||||
content: CollaborativeDoc
|
|
||||||
|
space: Ref<Teamspace>
|
||||||
|
|
||||||
lockedBy?: Ref<Account> | null
|
lockedBy?: Ref<Account> | null
|
||||||
|
|
||||||
@ -42,10 +43,10 @@ export interface Document extends AttachedDoc<Document, 'children', Teamspace>,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export interface DocumentSnapshot extends AttachedDoc<Document, 'snapshots', Teamspace> {
|
export interface DocumentSnapshot extends Card {
|
||||||
attachedTo: Ref<Document>
|
parent: Ref<Document>
|
||||||
name: string
|
title: string
|
||||||
content: CollaborativeDoc
|
description: CollaborativeDoc
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
|
@ -21,13 +21,13 @@ import { type Document, type Teamspace } from './types'
|
|||||||
export async function getFirstRank (
|
export async function getFirstRank (
|
||||||
client: TxOperations,
|
client: TxOperations,
|
||||||
space: Ref<Teamspace>,
|
space: Ref<Teamspace>,
|
||||||
attachedTo: Ref<Document>,
|
parent: Ref<Document>,
|
||||||
sort: SortingOrder = SortingOrder.Descending,
|
sort: SortingOrder = SortingOrder.Descending,
|
||||||
extra: DocumentQuery<Document> = {}
|
extra: DocumentQuery<Document> = {}
|
||||||
): Promise<Rank | undefined> {
|
): Promise<Rank | undefined> {
|
||||||
const doc = await client.findOne(
|
const doc = await client.findOne(
|
||||||
document.class.Document,
|
document.class.Document,
|
||||||
{ space, attachedTo, ...extra },
|
{ space, parent, ...extra },
|
||||||
{ sort: { rank: sort }, projection: { rank: 1 } }
|
{ sort: { rank: sort }, projection: { rank: 1 } }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -365,7 +365,15 @@
|
|||||||
remoteProvider.awareness?.setLocalStateField('lastUpdate', Date.now())
|
remoteProvider.awareness?.setLocalStateField('lastUpdate', Date.now())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function parseField (collaborativeDoc: CollaborativeDoc): string | undefined {
|
||||||
|
if (collaborativeDoc === undefined) return undefined
|
||||||
|
const _id = collaborativeDoc.split(':')
|
||||||
|
if (_id === undefined) return undefined
|
||||||
|
return _id[0]?.split('%')?.[1]
|
||||||
|
}
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
|
const _field = parseField(collaborativeDoc) ?? field
|
||||||
await ph
|
await ph
|
||||||
|
|
||||||
editor = new Editor({
|
editor = new Editor({
|
||||||
@ -398,7 +406,7 @@
|
|||||||
Placeholder.configure({ placeholder: placeHolderStr }),
|
Placeholder.configure({ placeholder: placeHolderStr }),
|
||||||
Collaboration.configure({
|
Collaboration.configure({
|
||||||
document: ydoc,
|
document: ydoc,
|
||||||
field
|
field: _field
|
||||||
}),
|
}),
|
||||||
CollaborationCursor.configure({
|
CollaborationCursor.configure({
|
||||||
provider: remoteProvider,
|
provider: remoteProvider,
|
||||||
|
@ -11,7 +11,7 @@ import serverCore, { TriggerControl } from '@hcengineering/server-core'
|
|||||||
import slugify from 'slugify'
|
import slugify from 'slugify'
|
||||||
|
|
||||||
function getDocumentId (doc: Document): string {
|
function getDocumentId (doc: Document): string {
|
||||||
const slug = slugify(doc.name, { lower: true })
|
const slug = slugify(doc.title, { lower: true })
|
||||||
return `${slug}-${doc._id}`
|
return `${slug}-${doc._id}`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ export async function documentHTMLPresenter (doc: Doc, control: TriggerControl):
|
|||||||
const front = control.branding?.front ?? getMetadata(serverCore.metadata.FrontUrl) ?? ''
|
const front = control.branding?.front ?? getMetadata(serverCore.metadata.FrontUrl) ?? ''
|
||||||
const path = `${workbenchId}/${control.workspace.workspaceUrl}/${documentId}/${getDocumentId(document)}`
|
const path = `${workbenchId}/${control.workspace.workspaceUrl}/${documentId}/${getDocumentId(document)}`
|
||||||
const link = concatLink(front, path)
|
const link = concatLink(front, path)
|
||||||
return `<a href="${link}">${document.name}</a>`
|
return `<a href="${link}">${document.title}</a>`
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function documentLinkIdProvider (doc: Document): Promise<string> {
|
export async function documentLinkIdProvider (doc: Document): Promise<string> {
|
||||||
@ -35,7 +35,7 @@ export async function documentLinkIdProvider (doc: Document): Promise<string> {
|
|||||||
*/
|
*/
|
||||||
export async function documentTextPresenter (doc: Doc): Promise<string> {
|
export async function documentTextPresenter (doc: Doc): Promise<string> {
|
||||||
const document = doc as Document
|
const document = doc as Document
|
||||||
return document.name
|
return document.title
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
||||||
|
Loading…
Reference in New Issue
Block a user