Merge branch 'develop' of https://github.com/hcengineering/platform into staging-new

Signed-off-by: Artem Savchenko <armisav@gmail.com>
This commit is contained in:
Artem Savchenko 2025-05-14 10:16:18 +07:00
commit 91fd208296
10 changed files with 84 additions and 56 deletions

View File

@ -16,7 +16,7 @@
import { Attachment } from '@hcengineering/attachment' import { Attachment } from '@hcengineering/attachment'
import { Ref, type WithLookup } from '@hcengineering/core' import { Ref, type WithLookup } from '@hcengineering/core'
import { ListSelectionProvider } from '@hcengineering/view-resources' import { ListSelectionProvider } from '@hcengineering/view-resources'
import { Scroller, updatePopup } from '@hcengineering/ui' import { updatePopup } from '@hcengineering/ui'
import { AttachmentImageSize } from '../types' import { AttachmentImageSize } from '../types'
import AttachmentPreview from './AttachmentPreview.svelte' import AttachmentPreview from './AttachmentPreview.svelte'
@ -43,7 +43,7 @@
</script> </script>
{#if attachments.length} {#if attachments.length}
<Scroller contentDirection={'horizontal'} horizontal gap={'gap-3'} scrollSnap> <div class="gallery">
{#each attachments as attachment} {#each attachments as attachment}
<AttachmentPreview <AttachmentPreview
value={attachment} value={attachment}
@ -54,5 +54,13 @@
on:open={(res) => (attachmentPopupId = res.detail)} on:open={(res) => (attachmentPopupId = res.detail)}
/> />
{/each} {/each}
</Scroller> </div>
{/if} {/if}
<style lang="scss">
.gallery {
display: grid;
grid-gap: 0.75rem;
grid-template-columns: repeat(auto-fill, 20rem);
}
</style>

View File

@ -13,6 +13,7 @@
// limitations under the License. // limitations under the License.
--> -->
<script lang="ts"> <script lang="ts">
import { Analytics } from '@hcengineering/analytics'
import attachment, { Attachment, AttachmentsEvents } from '@hcengineering/attachment' import attachment, { Attachment, AttachmentsEvents } from '@hcengineering/attachment'
import contact from '@hcengineering/contact' import contact from '@hcengineering/contact'
import core, { BlobMetadata, Doc, PersonId, Ref, generateId, type Blob, type Space } from '@hcengineering/core' import core, { BlobMetadata, Doc, PersonId, Ref, generateId, type Blob, type Space } from '@hcengineering/core'
@ -34,11 +35,9 @@
defaultRefActions, defaultRefActions,
getModelRefActions getModelRefActions
} from '@hcengineering/text-editor-resources' } from '@hcengineering/text-editor-resources'
import { AnySvelteComponent, getEventPositionElement, getPopupPositionElement, navigate } from '@hcengineering/ui' import { AnySvelteComponent, getEventPositionElement, getPopupPositionElement } from '@hcengineering/ui'
import { type FileUploadCallbackParams, uploadFiles } from '@hcengineering/uploader' import { uploadFiles, type FileUploadCallbackParams } from '@hcengineering/uploader'
import view from '@hcengineering/view' import { getCollaborationUser, getObjectId, openDoc } from '@hcengineering/view-resources'
import { getCollaborationUser, getObjectId, getObjectLinkFragment } from '@hcengineering/view-resources'
import { Analytics } from '@hcengineering/analytics'
import AttachmentsGrid from './AttachmentsGrid.svelte' import AttachmentsGrid from './AttachmentsGrid.svelte'
@ -324,8 +323,7 @@
on:open-document={async (event) => { on:open-document={async (event) => {
const doc = await client.findOne(event.detail._class, { _id: event.detail._id }) const doc = await client.findOne(event.detail._class, { _id: event.detail._id })
if (doc != null) { if (doc != null) {
const location = await getObjectLinkFragment(client.getHierarchy(), doc, {}, view.component.EditDoc) await openDoc(client.getHierarchy(), doc)
navigate(location)
} }
}} }}
on:focus on:focus

View File

@ -13,13 +13,11 @@
// limitations under the License. // limitations under the License.
--> -->
<script lang="ts"> <script lang="ts">
import { Doc, Class, Ref, updateAttribute } from '@hcengineering/core' import { Class, Doc, Ref, updateAttribute } from '@hcengineering/core'
import { IntlString } from '@hcengineering/platform' import { IntlString } from '@hcengineering/platform'
import { createQuery, getAttribute, getClient, KeyedAttribute } from '@hcengineering/presentation' import { createQuery, getAttribute, getClient, KeyedAttribute } from '@hcengineering/presentation'
import { navigate } from '@hcengineering/ui' import { openDoc } from '@hcengineering/view-resources'
import view from '@hcengineering/view'
import { getObjectLinkFragment } from '@hcengineering/view-resources'
import { createEventDispatcher } from 'svelte' import { createEventDispatcher } from 'svelte'
import AttachmentStyledBox from './AttachmentStyledBox.svelte' import AttachmentStyledBox from './AttachmentStyledBox.svelte'
@ -137,8 +135,7 @@
save(object, description) save(object, description)
const doc = await client.findOne(event.detail._class, { _id: event.detail._id }) const doc = await client.findOne(event.detail._class, { _id: event.detail._id })
if (doc != null) { if (doc != null) {
const location = await getObjectLinkFragment(client.getHierarchy(), doc, {}, view.component.EditDoc) await openDoc(client.getHierarchy(), doc)
navigate(location)
} }
}} }}
/> />

View File

@ -20,9 +20,7 @@
import { getClient } from '@hcengineering/presentation' import { getClient } from '@hcengineering/presentation'
import { Heading } from '@hcengineering/text-editor' import { Heading } from '@hcengineering/text-editor'
import { TableOfContents } from '@hcengineering/text-editor-resources' import { TableOfContents } from '@hcengineering/text-editor-resources'
import { navigate } from '@hcengineering/ui' import { openDoc } from '@hcengineering/view-resources'
import view from '@hcengineering/view'
import { getObjectLinkFragment } from '@hcengineering/view-resources'
import { createEventDispatcher } from 'svelte' import { createEventDispatcher } from 'svelte'
import ContentEditor from './ContentEditor.svelte' import ContentEditor from './ContentEditor.svelte'
@ -107,8 +105,7 @@
on:open-document={async (event) => { on:open-document={async (event) => {
const doc = await client.findOne(event.detail._class, { _id: event.detail._id }) const doc = await client.findOne(event.detail._class, { _id: event.detail._id })
if (doc != null) { if (doc != null) {
const location = await getObjectLinkFragment(client.getHierarchy(), doc, {}, view.component.EditDoc) await openDoc(client.getHierarchy(), doc)
navigate(location)
} }
}} }}
bind:this={editor} bind:this={editor}

View File

@ -13,48 +13,47 @@
// limitations under the License. // limitations under the License.
--> -->
<script lang="ts"> <script lang="ts">
import { createEventDispatcher, onDestroy, tick } from 'svelte'
import { merge } from 'effector'
import { type Ref, type Blob, generateId } from '@hcengineering/core'
import { getResource, setPlatformStatus, unknownError } from '@hcengineering/platform'
import { getClient } from '@hcengineering/presentation'
import view from '@hcengineering/view'
import attachment, { Attachment } from '@hcengineering/attachment' import attachment, { Attachment } from '@hcengineering/attachment'
import documents, { DocumentState } from '@hcengineering/controlled-documents' import documents, { DocumentState } from '@hcengineering/controlled-documents'
import { type Blob, type Ref, generateId } from '@hcengineering/core'
import { getResource, setPlatformStatus, unknownError } from '@hcengineering/platform'
import { getClient } from '@hcengineering/presentation'
import { Editor, Heading } from '@hcengineering/text-editor' import { Editor, Heading } from '@hcengineering/text-editor'
import { import {
CollaboratorEditor, CollaboratorEditor,
TableOfContents,
TableOfContentsContent,
FocusExtension, FocusExtension,
HeadingsExtension, HeadingsExtension,
IsEmptyContentExtension, IsEmptyContentExtension,
NodeHighlightExtension, NodeHighlightExtension,
NodeHighlightType, NodeHighlightType,
highlightUpdateCommand, TableOfContents,
getNodeElement TableOfContentsContent,
getNodeElement,
highlightUpdateCommand
} from '@hcengineering/text-editor-resources' } from '@hcengineering/text-editor-resources'
import { navigate, EditBox, Scroller, Label } from '@hcengineering/ui' import { EditBox, Label, Scroller } from '@hcengineering/ui'
import { getCollaborationUser, getObjectLinkFragment } from '@hcengineering/view-resources' import { getCollaborationUser, openDoc } from '@hcengineering/view-resources'
import { merge } from 'effector'
import { createEventDispatcher, onDestroy, tick } from 'svelte'
import plugin from '../../plugin' import plugin from '../../plugin'
import { import {
$areDocumentCommentPopupsOpened as areDocumentCommentPopupsOpened, $areDocumentCommentPopupsOpened as areDocumentCommentPopupsOpened,
$controlledDocument as controlledDocument,
$isEditable as isEditable,
$documentCommentHighlightedLocation as documentCommentHighlightedLocation,
$areDocumentCommentPopupsOpened as arePopupsOpened, $areDocumentCommentPopupsOpened as arePopupsOpened,
$canAddDocumentComments as canAddDocumentComments, $canAddDocumentComments as canAddDocumentComments,
$canViewDocumentComments as canViewDocumentComments, $canViewDocumentComments as canViewDocumentComments,
$controlledDocument as controlledDocument,
$documentCommentHighlightedLocation as documentCommentHighlightedLocation,
$documentComments as documentComments, $documentComments as documentComments,
documentCommentsDisplayRequested, documentCommentsDisplayRequested,
documentCommentsHighlightUpdated, documentCommentsHighlightUpdated,
documentCommentsLocationNavigateRequested, documentCommentsLocationNavigateRequested,
$documentReleasedVersions as documentReleasedVersions $documentReleasedVersions as documentReleasedVersions,
$isEditable as isEditable
} from '../../stores/editors/document' } from '../../stores/editors/document'
import DocumentTitle from './DocumentTitle.svelte'
import DocumentPrintTitlePage from '../print/DocumentPrintTitlePage.svelte'
import { syncDocumentMetaTitle } from '../../utils' import { syncDocumentMetaTitle } from '../../utils'
import DocumentPrintTitlePage from '../print/DocumentPrintTitlePage.svelte'
import DocumentTitle from './DocumentTitle.svelte'
const client = getClient() const client = getClient()
const hierarchy = client.getHierarchy() const hierarchy = client.getHierarchy()
@ -295,8 +294,7 @@
on:open-document={async (event) => { on:open-document={async (event) => {
const doc = await client.findOne(event.detail._class, { _id: event.detail._id }) const doc = await client.findOne(event.detail._class, { _id: event.detail._id })
if (doc != null) { if (doc != null) {
const location = await getObjectLinkFragment(client.getHierarchy(), doc, {}, view.component.EditDoc) await openDoc(client.getHierarchy(), doc)
navigate(location)
} }
}} }}
attachFile={async (file) => { attachFile={async (file) => {

View File

@ -15,6 +15,7 @@
// //
--> -->
<script lang="ts"> <script lang="ts">
import { Analytics } from '@hcengineering/analytics'
import attachment, { Attachment } from '@hcengineering/attachment' import attachment, { Attachment } from '@hcengineering/attachment'
import core, { Doc, Ref, WithLookup, generateId, type Blob } from '@hcengineering/core' import core, { Doc, Ref, WithLookup, generateId, type Blob } from '@hcengineering/core'
import { Document, DocumentEvents } from '@hcengineering/document' import { Document, DocumentEvents } from '@hcengineering/document'
@ -35,7 +36,6 @@
TimeSince, TimeSince,
createFocusManager, createFocusManager,
getPlatformColorDef, getPlatformColorDef,
navigate,
showPopup, showPopup,
themeStore themeStore
} from '@hcengineering/ui' } from '@hcengineering/ui'
@ -45,14 +45,13 @@
IconPicker, IconPicker,
ParentsNavigator, ParentsNavigator,
RelationsEditor, RelationsEditor,
getObjectLinkFragment, openDoc,
restrictionStore, restrictionStore,
showMenu showMenu
} from '@hcengineering/view-resources' } from '@hcengineering/view-resources'
import { createEventDispatcher, onDestroy, onMount } from 'svelte' import { createEventDispatcher, onDestroy, onMount } from 'svelte'
import { Analytics } from '@hcengineering/analytics'
import { starDocument, unstarDocument, unlockContent } from '..' import { starDocument, unlockContent, unstarDocument } from '..'
import document from '../plugin' import document from '../plugin'
import { getDocumentUrl } from '../utils' import { getDocumentUrl } from '../utils'
import DocumentEditor from './DocumentEditor.svelte' import DocumentEditor from './DocumentEditor.svelte'
@ -389,8 +388,7 @@
on:open-document={async (event) => { on:open-document={async (event) => {
const doc = await client.findOne(event.detail._class, { _id: event.detail._id }) const doc = await client.findOne(event.detail._class, { _id: event.detail._id })
if (doc != null) { if (doc != null) {
const location = await getObjectLinkFragment(client.getHierarchy(), doc, {}, view.component.EditDoc) await openDoc(client.getHierarchy(), doc)
navigate(location)
} }
}} }}
on:loaded={() => { on:loaded={() => {

View File

@ -108,6 +108,7 @@
const newValue = !$isSharingEnabled const newValue = !$isSharingEnabled
const audio = newValue && $isShareWithSound const audio = newValue && $isShareWithSound
await setShare(newValue, audio) await setShare(newValue, audio)
dispatch('close')
} }
async function leave (): Promise<void> { async function leave (): Promise<void> {

View File

@ -408,7 +408,12 @@ export async function getReferenceLabel<T extends Doc> (
const identifier = (await labelProviderFn?.(client, id, doc)) ?? '' const identifier = (await labelProviderFn?.(client, id, doc)) ?? ''
const title = (await titleProviderFn?.(client, id, doc)) ?? '' const title = (await titleProviderFn?.(client, id, doc)) ?? ''
const label = identifier !== '' && title !== '' && identifier !== title ? `${identifier} ${title}` : title ?? '' const label =
identifier !== '' && title !== '' && identifier !== title
? `${identifier} ${title}`
: title !== ''
? title
: identifier
return label return label
} }
@ -451,7 +456,6 @@ export async function getTargetObjectFromUrl (
urlOrLocation: string | Location urlOrLocation: string | Location
): Promise<{ _id: Ref<Doc>, _class: Ref<Class<Doc>> } | undefined> { ): Promise<{ _id: Ref<Doc>, _class: Ref<Class<Doc>> } | undefined> {
const client = getClient() const client = getClient()
const hierarchy = client.getHierarchy()
let location: Location let location: Location
if (typeof urlOrLocation === 'string') { if (typeof urlOrLocation === 'string') {
@ -469,19 +473,43 @@ export async function getTargetObjectFromUrl (
const appAlias = (location.path[2] ?? '').trim() const appAlias = (location.path[2] ?? '').trim()
if (!(appAlias.length > 0)) return if (!(appAlias.length > 0)) return
const excludedApps = getMetadata(workbench.metadata.ExcludedApplications) ?? [] const excludedApps = getMetadata(workbench.metadata.ExcludedApplications) ?? []
const apps: Application[] = client const apps: Application[] = client
.getModel() .getModel()
.findAllSync<Application>(workbench.class.Application, { hidden: false, _id: { $nin: excludedApps } }) .findAllSync<Application>(workbench.class.Application, { hidden: false, _id: { $nin: excludedApps } })
const app = apps.find((p) => p.alias === appAlias) const app = apps.find((p) => p.alias === appAlias)
const locationResolver = app?.locationResolver
const locationDataResolver = app?.locationDataResolver
if (app?.locationResolver === undefined) return if ((location.fragment ?? '') !== '') {
const locationResolverFn = await getResource(app.locationResolver) const obj = await getObjectFromFragment(location.fragment ?? '')
const resolvedLocation = await locationResolverFn(location) if (obj !== undefined) return obj
}
const locationParts = decodeURIComponent(resolvedLocation?.loc?.fragment ?? '').split('|') if (locationResolver !== undefined) {
const locationResolverFn = await getResource(locationResolver)
const resolvedLocation = await locationResolverFn(location)
const obj = await getObjectFromFragment(resolvedLocation?.loc?.fragment ?? '')
if (obj !== undefined) return obj
}
if (locationDataResolver !== undefined) {
const locationDataResolverFn = await getResource(locationDataResolver)
const locationData = await locationDataResolverFn(location)
if (locationData.objectId !== undefined && locationData.objectClass !== undefined) {
return { _id: locationData.objectId, _class: locationData.objectClass }
}
}
}
async function getObjectFromFragment (
fragment: string
): Promise<{ _id: Ref<Doc>, _class: Ref<Class<Doc>> } | undefined> {
const client = getClient()
const hierarchy = client.getHierarchy()
const locationParts = decodeURIComponent(fragment).split('|')
const id = locationParts[1] as Ref<Doc> const id = locationParts[1] as Ref<Doc>
const objectclass = locationParts[2] as Ref<Class<Doc>> const objectclass = locationParts[2] as Ref<Class<Doc>>
if (id === undefined || objectclass === undefined) return if (id === undefined || objectclass === undefined) return

View File

@ -399,7 +399,10 @@
} }
} }
loc.query = resolved.loc.query ?? loc.query ?? currentQuery ?? resolved.defaultLocation.query loc.query = resolved.loc.query ?? loc.query ?? currentQuery ?? resolved.defaultLocation.query
loc.fragment = resolved.loc.fragment ?? loc.fragment ?? resolved.defaultLocation.fragment loc.fragment =
(loc.fragment ?? '') !== '' && resolved.loc.fragment === resolved.defaultLocation.fragment
? loc.fragment
: resolved.loc.fragment ?? resolved.defaultLocation.fragment
return loc return loc
} }

View File

@ -14,7 +14,7 @@
"build": "compile", "build": "compile",
"build:watch": "compile", "build:watch": "compile",
"test": "jest --passWithNoTests --silent", "test": "jest --passWithNoTests --silent",
"_phase:bundle": "rushx bundle", "_phase:bundle": "rushx bundle --external=ws",
"_phase:docker-build": "rushx docker:build", "_phase:docker-build": "rushx docker:build",
"_phase:docker-staging": "rushx docker:staging", "_phase:docker-staging": "rushx docker:staging",
"bundle": "node ../../../common/scripts/esbuild.js --external=ws", "bundle": "node ../../../common/scripts/esbuild.js --external=ws",