diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index 3e53d5041d..0d5012eff3 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -26143,6 +26143,9 @@ importers: '@hcengineering/view': specifier: workspace:^0.7.0 version: link:../view + '@hcengineering/workbench': + specifier: workspace:^0.7.0 + version: link:../workbench fast-equals: specifier: ^5.2.2 version: 5.3.2 diff --git a/packages/theme/styles/prose.scss b/packages/theme/styles/prose.scss index 323f6e264d..a267da6a86 100644 --- a/packages/theme/styles/prose.scss +++ b/packages/theme/styles/prose.scss @@ -23,7 +23,7 @@ table.proseTable { --table-handle-size: 0.875rem; --table-handle-indent: calc(var(--table-handle-size) * -1 - 1px); --table-handle-col-indent: calc(var(--table-handle-size) * -0.5); - --table-handle-row-indent: calc(var(--table-handle-size) * -1 - 0.75rem); + --table-handle-row-indent: calc(var(--table-handle-size) * -1); --table-insert-marker-indent: calc(-1.25rem - 1px); --table-selection-z-index: 100; diff --git a/plugins/text-editor-resources/src/components/CollaborativeTextEditor.svelte b/plugins/text-editor-resources/src/components/CollaborativeTextEditor.svelte index 81b73719e2..822faa3958 100644 --- a/plugins/text-editor-resources/src/components/CollaborativeTextEditor.svelte +++ b/plugins/text-editor-resources/src/components/CollaborativeTextEditor.svelte @@ -423,7 +423,7 @@ editor = new Editor({ extensions: [kit], element, - editable: false, + editable: !readonly, editorProps: { attributes: mergeAttributes(defaultEditorAttributes, editorAttributes, { class: 'flex-grow' }) }, diff --git a/plugins/text-editor-resources/src/components/extension/table/TableNodeView.svelte b/plugins/text-editor-resources/src/components/extension/table/TableNodeView.svelte index 5e16911d55..191a4991ea 100644 --- a/plugins/text-editor-resources/src/components/extension/table/TableNodeView.svelte +++ b/plugins/text-editor-resources/src/components/extension/table/TableNodeView.svelte @@ -195,7 +195,7 @@ &__col { right: calc(var(--table-offscreen-spacing) - 1.5rem); top: 0; - bottom: 0; + bottom: 1rem; margin: 1.5rem 0; .table-button { @@ -204,7 +204,7 @@ } &__row { - bottom: -0.25rem; + bottom: 1rem; left: var(--table-offscreen-spacing); right: var(--table-offscreen-spacing); diff --git a/plugins/text-editor-resources/src/components/extension/table/decorations/columnHandlerDecoration.ts b/plugins/text-editor-resources/src/components/extension/table/decorations/columnHandlerDecoration.ts index f94bfb45c2..788fedb1d6 100644 --- a/plugins/text-editor-resources/src/components/extension/table/decorations/columnHandlerDecoration.ts +++ b/plugins/text-editor-resources/src/components/extension/table/decorations/columnHandlerDecoration.ts @@ -194,7 +194,24 @@ class ColumnHandler { const dropMarker = getDropMarker() const dragMarker = getColDragMarker() + const handleMove = (event: MouseEvent): void => { + if (dropMarker !== null && dragMarker !== null) { + const currentLeft = startLeft + event.clientX - startX + dropIndex = calculateColumnDropIndex(col, columns, currentLeft) + + const dragMarkerWidthPx = columns[col].widthPx + const dragMarkerLeftPx = Math.max(0, Math.min(currentLeft, tableWidthPx - dragMarkerWidthPx)) + const dropMarkerLeftPx = + dropIndex <= col ? columns[dropIndex].leftPx : columns[dropIndex].leftPx + columns[dropIndex].widthPx + + updateColDropMarker(dropMarker, dropMarkerLeftPx - Math.floor(dropMarkerWidthPx / 2) - 1, dropMarkerWidthPx) + updateColDragMarker(dragMarker, dragMarkerLeftPx, dragMarkerWidthPx) + } + } + const handleFinish = (): void => { + window.removeEventListener('mousemove', handleMove) + if (dropMarker !== null) hideDropMarker(dropMarker) if (dragMarker !== null) hideDragMarker(dragMarker) @@ -211,21 +228,6 @@ class ColumnHandler { } } - const handleMove = (event: MouseEvent): void => { - if (dropMarker !== null && dragMarker !== null) { - const currentLeft = startLeft + event.clientX - startX - dropIndex = calculateColumnDropIndex(col, columns, currentLeft) - - const dragMarkerWidthPx = columns[col].widthPx - const dragMarkerLeftPx = Math.max(0, Math.min(currentLeft, tableWidthPx - dragMarkerWidthPx)) - const dropMarkerLeftPx = - dropIndex <= col ? columns[dropIndex].leftPx : columns[dropIndex].leftPx + columns[dropIndex].widthPx - - updateColDropMarker(dropMarker, dropMarkerLeftPx - Math.floor(dropMarkerWidthPx / 2) - 1, dropMarkerWidthPx) - updateColDragMarker(dragMarker, dragMarkerLeftPx, dragMarkerWidthPx) - } - } - window.addEventListener('mouseup', handleFinish, { once: true }) window.addEventListener('mousemove', handleMove) }) diff --git a/plugins/text-editor-resources/src/components/extension/table/decorations/rowHandlerDecoration.ts b/plugins/text-editor-resources/src/components/extension/table/decorations/rowHandlerDecoration.ts index 2af89e7449..727f972197 100644 --- a/plugins/text-editor-resources/src/components/extension/table/decorations/rowHandlerDecoration.ts +++ b/plugins/text-editor-resources/src/components/extension/table/decorations/rowHandlerDecoration.ts @@ -194,7 +194,24 @@ class RowHandler { const dropMarker = getDropMarker() const dragMarker = getRowDragMarker() + const handleMove = (event: MouseEvent): void => { + if (dropMarker !== null && dragMarker !== null) { + const cursorTop = startTop + event.clientY - startY + dropIndex = calculateRowDropIndex(row, rows, cursorTop) + + const dragMarkerHeightPx = rows[row].heightPx + const dragMarkerTopPx = Math.max(0, Math.min(cursorTop, tableHeightPx - dragMarkerHeightPx)) + const dropMarkerTopPx = + dropIndex <= row ? rows[dropIndex].topPx : rows[dropIndex].topPx + rows[dropIndex].heightPx + + updateRowDropMarker(dropMarker, dropMarkerTopPx - dropMarkerWidthPx / 2, dropMarkerWidthPx) + updateRowDragMarker(dragMarker, dragMarkerTopPx, dragMarkerHeightPx) + } + } + const handleFinish = (): void => { + window.removeEventListener('mousemove', handleMove) + if (dropMarker !== null) hideDropMarker(dropMarker) if (dragMarker !== null) hideDragMarker(dragMarker) @@ -211,21 +228,6 @@ class RowHandler { } } - const handleMove = (event: MouseEvent): void => { - if (dropMarker !== null && dragMarker !== null) { - const cursorTop = startTop + event.clientY - startY - dropIndex = calculateRowDropIndex(row, rows, cursorTop) - - const dragMarkerHeightPx = rows[row].heightPx - const dragMarkerTopPx = Math.max(0, Math.min(cursorTop, tableHeightPx - dragMarkerHeightPx)) - const dropMarkerTopPx = - dropIndex <= row ? rows[dropIndex].topPx : rows[dropIndex].topPx + rows[dropIndex].heightPx - - updateRowDropMarker(dropMarker, dropMarkerTopPx - dropMarkerWidthPx / 2, dropMarkerWidthPx) - updateRowDragMarker(dragMarker, dragMarkerTopPx, dragMarkerHeightPx) - } - } - window.addEventListener('mouseup', handleFinish, { once: true }) window.addEventListener('mousemove', handleMove) }) diff --git a/plugins/view-resources/package.json b/plugins/view-resources/package.json index 21738536ae..303374751c 100644 --- a/plugins/view-resources/package.json +++ b/plugins/view-resources/package.json @@ -61,6 +61,7 @@ "@hcengineering/query": "^0.7.17", "@hcengineering/emoji": "workspace:^0.7.0", "@hcengineering/theme": "workspace:^0.7.0", + "@hcengineering/workbench": "workspace:^0.7.0", "@hcengineering/hls": "workspace:^0.7.0", "fast-equals": "^5.2.2" } diff --git a/plugins/view-resources/src/actionImpl.ts b/plugins/view-resources/src/actionImpl.ts index 8bc89c50f9..91b56e5a70 100644 --- a/plugins/view-resources/src/actionImpl.ts +++ b/plugins/view-resources/src/actionImpl.ts @@ -19,6 +19,7 @@ import { copyTextToClipboardOldBrowser, getClient, getMarkup, + hasResource, updateAttribute } from '@hcengineering/presentation' import { markupToJSON } from '@hcengineering/text' @@ -48,6 +49,7 @@ import { selectionStore } from './selection' import { deleteObjects, getObjectId, getObjectLinkFragment, restrictionStore } from './utils' +import workbenchPlugin from '@hcengineering/workbench' /** * Action to be used for copying text to clipboard. @@ -328,8 +330,13 @@ async function OpenInNewTab ( const panelComponent = hierarchy.classHierarchyMixin(d._class, view.mixin.ObjectPanel) const component = props?.component ?? panelComponent?.component ?? view.component.EditDoc const loc = await getObjectLinkFragment(hierarchy, d, {}, component) - const url = locationToUrl(loc) - window.open(url, '_blank') + if (hasResource(workbenchPlugin.function.OpenInNewTab) === true) { + const res = await getResource(workbenchPlugin.function.OpenInNewTab) + await res(loc) + } else { + const url = locationToUrl(loc) + window.open(url, '_blank') + } } /** diff --git a/plugins/workbench-resources/src/connect.ts b/plugins/workbench-resources/src/connect.ts index 44452542bd..15e9d84f6a 100644 --- a/plugins/workbench-resources/src/connect.ts +++ b/plugins/workbench-resources/src/connect.ts @@ -453,7 +453,7 @@ export async function connect (title: string): Promise { const hasEmail = (si: SocialId): boolean => { return [SocialIdType.EMAIL, SocialIdType.GOOGLE, SocialIdType.GITHUB].some((type) => type === si.type) } - const email = me.fullSocialIds.find((si) => hasEmail(si))?.key + const email = me.fullSocialIds.find((si) => hasEmail(si) && si.isDeleted !== true)?.key const socialId = me.fullSocialIds.find((si) => si._id === me.primarySocialId)?.key const data: Record = { diff --git a/plugins/workbench-resources/src/index.ts b/plugins/workbench-resources/src/index.ts index 43433c3c85..8f386fa28b 100644 --- a/plugins/workbench-resources/src/index.ts +++ b/plugins/workbench-resources/src/index.ts @@ -25,7 +25,7 @@ import Workbench from './components/Workbench.svelte' import ServerManager from './components/ServerManager.svelte' import WorkbenchTabs from './components/WorkbenchTabs.svelte' import { isAdminUser } from '@hcengineering/presentation' -import { canCloseTab, closeCurrentTab, closeTab, pinTab, unpinTab } from './workbench' +import { canCloseTab, closeCurrentTab, closeTab, OpenInNewTab, pinTab, unpinTab } from './workbench' import { closeWidget, closeWidgetTab, createWidgetTab, getSidebarObject } from './sidebar' async function hasArchiveSpaces (spaces: Space[]): Promise { @@ -66,7 +66,8 @@ export default async (): Promise => ({ CloseWidget: closeWidget, GetSidebarObject: getSidebarObject, LogIn: logIn, - LogOut: logOut + LogOut: logOut, + OpenInNewTab }, actionImpl: { Navigate: doNavigate, diff --git a/plugins/workbench-resources/src/workbench.ts b/plugins/workbench-resources/src/workbench.ts index 4025e223f8..9afad672ea 100644 --- a/plugins/workbench-resources/src/workbench.ts +++ b/plugins/workbench-resources/src/workbench.ts @@ -176,6 +176,19 @@ export function getTabLocation (tab: Pick): Location { return parseLocation(url) } +export async function OpenInNewTab (loc: Location): Promise { + const client = getClient() + const data = await getTabDataByLocation(loc) + const name = data.name ?? (await translate(data.label, {}, get(languageStore))) + const url = locationToUrl(loc) + await client.createDoc(workbench.class.WorkbenchTab, core.space.Workspace, { + attachedTo: getCurrentAccount().uuid, + location: url, + isPinned: false, + name + }) +} + export async function closeTab (tab: WorkbenchTab): Promise { const tabs = get(tabsStore) const index = tabs.findIndex((t) => t._id === tab._id) diff --git a/plugins/workbench/src/plugin.ts b/plugins/workbench/src/plugin.ts index ed17cc6fec..47313e82ea 100644 --- a/plugins/workbench/src/plugin.ts +++ b/plugins/workbench/src/plugin.ts @@ -17,7 +17,7 @@ import type { Class, Doc, Mixin, Ref, Space } from '@hcengineering/core' import type { Asset, IntlString, Metadata, Plugin, Resource } from '@hcengineering/platform' import { plugin } from '@hcengineering/platform' -import { AnyComponent, ComponentExtensionId } from '@hcengineering/ui' +import { AnyComponent, ComponentExtensionId, Location } from '@hcengineering/ui' import { Action, ViewAction } from '@hcengineering/view' import type { @@ -95,7 +95,8 @@ export const workbenchPlugin = plugin(workbenchId, { CloseWidget: '' as Resource<(widget: Ref) => Promise>, GetSidebarObject: '' as Resource<() => Partial>>, LogIn: '' as Resource<(loginInfo: { account: string, token?: string }) => Promise>, - LogOut: '' as Resource<() => Promise> + LogOut: '' as Resource<() => Promise>, + OpenInNewTab: '' as Resource<(loc: Location) => Promise> }, actionImpl: { Navigate: '' as ViewAction<{ diff --git a/server-plugins/gmail-resources/src/index.ts b/server-plugins/gmail-resources/src/index.ts index c9a53fa173..080d77ebe5 100644 --- a/server-plugins/gmail-resources/src/index.ts +++ b/server-plugins/gmail-resources/src/index.ts @@ -222,7 +222,8 @@ async function processEmailNotifications (control: TriggerControl, notifications const emails = await control.findAll(control.ctx, contact.class.SocialIdentity, { attachedTo: employee._id, type: { $in: [SocialIdType.EMAIL, SocialIdType.GOOGLE] }, - verifiedOn: { $gt: 0 } + verifiedOn: { $gt: 0 }, + isDeleted: { $ne: true } }) if (emails.length === 0) continue diff --git a/server-plugins/process-resources/src/transform.ts b/server-plugins/process-resources/src/transform.ts index f648ec635d..88762a5ec1 100644 --- a/server-plugins/process-resources/src/transform.ts +++ b/server-plugins/process-resources/src/transform.ts @@ -18,6 +18,7 @@ import core, { Doc, matchQuery, Ref, Timestamp } from '@hcengineering/core' import { Execution, parseContext } from '@hcengineering/process' import { ProcessControl } from '@hcengineering/server-process' import { getContextValue } from './utils' +import cardPlugin from '@hcengineering/card' // #region ArrayReduce @@ -408,8 +409,17 @@ export async function RoleContext ( ): Promise[]> { const targetRole = props.target if (targetRole === undefined) return [] - const users = await control.client.findAll(contact.class.UserRole, { role: targetRole }) - return users.map((it) => it.user) + const targetCard = + control.cache.get(execution.card) ?? (await control.client.findOne(cardPlugin.class.Card, { _id: execution.card })) + if (targetCard === undefined) return [] + const targetSpace = + control.cache.get(targetCard.space) ?? (await control.client.findOne(core.class.Space, { _id: targetCard.space })) + if (targetSpace === undefined) return [] + const mixin = control.client.getHierarchy().as(targetSpace, core.mixin.SpacesTypeData) + const accs = (mixin as any)[targetRole] + if (accs === undefined || accs.length === 0) return [] + const users = await control.client.findAll(contact.mixin.Employee, { personUuid: { $in: accs } }) + return users.map((it) => it._id) } export async function CurrentUser (