diff --git a/packages/core/src/utils.ts b/packages/core/src/utils.ts index 6405f085fc..16b06a78aa 100644 --- a/packages/core/src/utils.ts +++ b/packages/core/src/utils.ts @@ -185,3 +185,17 @@ export interface IdMap extends Map, T> {} export function toIdMap (arr: T[]): IdMap { return new Map(arr.map((p) => [p._id, p])) } + +/** + * @public + */ +export function concatLink (host: string, path: string): string { + if (!host.endsWith('/') && !path.startsWith('/')) { + return `${host}/${path}` + } else if (host.endsWith('/') && path.startsWith('/')) { + const newPath = path.slice(1) + return `${host}${newPath}` + } else { + return `${host}${path}` + } +} diff --git a/plugins/gmail-resources/src/components/Connect.svelte b/plugins/gmail-resources/src/components/Connect.svelte index 3d66bef828..9b4fa2e80d 100644 --- a/plugins/gmail-resources/src/components/Connect.svelte +++ b/plugins/gmail-resources/src/components/Connect.svelte @@ -19,6 +19,7 @@ import { createEventDispatcher } from 'svelte' import login from '@hcengineering/login' import gmail from '../plugin' + import { concatLink } from '@hcengineering/core' const dispatch = createEventDispatcher() @@ -27,7 +28,8 @@ async function sendRequest (): Promise { connecting = true - const url = new URL(gmailUrl + '/signin') + const link = concatLink(gmailUrl, '/signin') + const url = new URL(link) url.search = new URLSearchParams({ redirectURL: window.location.href }).toString() diff --git a/plugins/telegram-resources/src/components/Connect.svelte b/plugins/telegram-resources/src/components/Connect.svelte index 91fac5c132..e0d0f419d1 100644 --- a/plugins/telegram-resources/src/components/Connect.svelte +++ b/plugins/telegram-resources/src/components/Connect.svelte @@ -19,6 +19,7 @@ import login from '@hcengineering/login' import PinPad from './PinPad.svelte' import telegram from '../plugin' + import { concatLink } from '@hcengineering/core' const dispatch = createEventDispatcher() @@ -60,7 +61,7 @@ async function sendRequest (path: string, data: any): Promise { connecting = true - const response = await fetch(url + path, { + const response = await fetch(concatLink(url, path), { method: 'POST', headers: { Authorization: 'Bearer ' + getMetadata(login.metadata.LoginToken), diff --git a/plugins/telegram-resources/src/components/Reconnect.svelte b/plugins/telegram-resources/src/components/Reconnect.svelte index f2e4de24ad..3bfb1f2be7 100644 --- a/plugins/telegram-resources/src/components/Reconnect.svelte +++ b/plugins/telegram-resources/src/components/Reconnect.svelte @@ -21,7 +21,7 @@ import telegram from '../plugin' import { getClient } from '@hcengineering/presentation' import setting from '@hcengineering/setting' - import { getCurrentAccount, Ref, Space } from '@hcengineering/core' + import { concatLink, getCurrentAccount, Ref, Space } from '@hcengineering/core' const dispatch = createEventDispatcher() @@ -63,7 +63,7 @@ async function sendRequest (path: string, data: any): Promise { connecting = true - const response = await fetch(url + path, { + const response = await fetch(concatLink(url, path), { method: 'POST', headers: { Authorization: 'Bearer ' + getMetadata(login.metadata.LoginToken), diff --git a/plugins/telegram-resources/src/index.ts b/plugins/telegram-resources/src/index.ts index b66221bc6d..4c612d533e 100644 --- a/plugins/telegram-resources/src/index.ts +++ b/plugins/telegram-resources/src/index.ts @@ -21,6 +21,7 @@ import Connect from './components/Connect.svelte' import Reconnect from './components/Reconnect.svelte' import IconTelegram from './components/icons/TelegramColor.svelte' import TxSharedCreate from './components/activity/TxSharedCreate.svelte' +import { concatLink } from '@hcengineering/core' export default async (): Promise => ({ component: { @@ -35,7 +36,7 @@ export default async (): Promise => ({ handler: { DisconnectHandler: async () => { const url = getMetadata(login.metadata.TelegramUrl) ?? '' - await fetch(url + '/signout', { + await fetch(concatLink(url, '/signout'), { method: 'POST', headers: { Authorization: 'Bearer ' + (getMetadata(login.metadata.LoginToken) ?? ''), diff --git a/server-plugins/chunter-resources/src/index.ts b/server-plugins/chunter-resources/src/index.ts index ff12eebca6..dfe94d641c 100644 --- a/server-plugins/chunter-resources/src/index.ts +++ b/server-plugins/chunter-resources/src/index.ts @@ -28,7 +28,8 @@ import core, { TxProcessor, TxUpdateDoc, TxRemoveDoc, - TxCollectionCUD + TxCollectionCUD, + concatLink } from '@hcengineering/core' import login from '@hcengineering/login' import { getMetadata } from '@hcengineering/platform' @@ -41,7 +42,9 @@ import { workbenchId } from '@hcengineering/workbench' export async function channelHTMLPresenter (doc: Doc, control: TriggerControl): Promise { const channel = doc as ChunterSpace const front = getMetadata(login.metadata.FrontUrl) ?? '' - return `${channel.name}` + const path = `${workbenchId}/${control.workspace.name}/${chunterId}/${channel._id}` + const link = concatLink(front, path) + return `${channel.name}` } /** diff --git a/server-plugins/contact-resources/src/index.ts b/server-plugins/contact-resources/src/index.ts index 967df45f6f..4d99da0892 100644 --- a/server-plugins/contact-resources/src/index.ts +++ b/server-plugins/contact-resources/src/index.ts @@ -15,7 +15,7 @@ // import contact, { Contact, contactId, formatName, Organization, Person } from '@hcengineering/contact' -import core, { Doc, Tx, TxCreateDoc, TxRemoveDoc, TxUpdateDoc } from '@hcengineering/core' +import core, { concatLink, Doc, Tx, TxCreateDoc, TxRemoveDoc, TxUpdateDoc } from '@hcengineering/core' import login from '@hcengineering/login' import { getMetadata } from '@hcengineering/platform' import type { TriggerControl } from '@hcengineering/server-core' @@ -75,9 +75,9 @@ export async function OnContactDelete (tx: Tx, { findAll, hierarchy, storageFx } export function personHTMLPresenter (doc: Doc, control: TriggerControl): string { const person = doc as Person const front = getMetadata(login.metadata.FrontUrl) ?? '' - return `${formatName(person.name)}` + const path = `${workbenchId}/${control.workspace.name}/${contactId}#${view.component.EditDoc}|${person._id}|${person._class}|content` + const link = concatLink(front, path) + return `${formatName(person.name)}` } /** @@ -94,7 +94,9 @@ export function personTextPresenter (doc: Doc): string { export function organizationHTMLPresenter (doc: Doc, control: TriggerControl): string { const organization = doc as Organization const front = getMetadata(login.metadata.FrontUrl) ?? '' - return `${organization.name}` + const path = `${workbenchId}/${control.workspace.name}/${contactId}#${view.component.EditDoc}|${organization._id}|${organization._class}|content` + const link = concatLink(front, path) + return `${organization.name}` } /** diff --git a/server-plugins/inventory-resources/src/index.ts b/server-plugins/inventory-resources/src/index.ts index fe9c2a20f1..bd803a8930 100644 --- a/server-plugins/inventory-resources/src/index.ts +++ b/server-plugins/inventory-resources/src/index.ts @@ -13,7 +13,7 @@ // limitations under the License. // -import { Doc } from '@hcengineering/core' +import { concatLink, Doc } from '@hcengineering/core' import { inventoryId, Product } from '@hcengineering/inventory' import login from '@hcengineering/login' import { getMetadata } from '@hcengineering/platform' @@ -27,7 +27,9 @@ import { workbenchId } from '@hcengineering/workbench' export async function productHTMLPresenter (doc: Doc, control: TriggerControl): Promise { const product = doc as Product const front = getMetadata(login.metadata.FrontUrl) ?? '' - return `${product.name}` + const path = `${workbenchId}/${control.workspace.name}/${inventoryId}/Products/#${view.component.EditDoc}|${product._id}|${product._class}|content` + const link = concatLink(front, path) + return `${product.name}` } /** diff --git a/server-plugins/lead-resources/src/index.ts b/server-plugins/lead-resources/src/index.ts index 04683d16d9..4c1cf9663c 100644 --- a/server-plugins/lead-resources/src/index.ts +++ b/server-plugins/lead-resources/src/index.ts @@ -15,6 +15,7 @@ import core, { AttachedDoc, + concatLink, Doc, Tx, TxCollectionCUD, @@ -37,7 +38,9 @@ import { addAssigneeNotification } from '@hcengineering/server-task-resources' export async function leadHTMLPresenter (doc: Doc, control: TriggerControl): Promise { const lead = doc as Lead const front = getMetadata(login.metadata.FrontUrl) ?? '' - return `${lead.title}` + const path = `${workbenchId}/${control.workspace.name}/${leadId}/${lead.space}/#${view.component.EditDoc}|${lead._id}|${lead._class}|content` + const link = concatLink(front, path) + return `${lead.title}` } /** diff --git a/server-plugins/recruit-resources/src/index.ts b/server-plugins/recruit-resources/src/index.ts index 7b81aa31c2..bcdd90b026 100644 --- a/server-plugins/recruit-resources/src/index.ts +++ b/server-plugins/recruit-resources/src/index.ts @@ -16,6 +16,7 @@ import contact from '@hcengineering/contact' import core, { AttachedDoc, + concatLink, Doc, Tx, TxCollectionCUD, @@ -39,7 +40,9 @@ import { workbenchId } from '@hcengineering/workbench' export async function vacancyHTMLPresenter (doc: Doc, control: TriggerControl): Promise { const vacancy = doc as Vacancy const front = getMetadata(login.metadata.FrontUrl) ?? '' - return `${vacancy.name}` + const path = `${workbenchId}/${control.workspace.name}/${recruitId}/${vacancy._id}/#${recruit.component.EditVacancy}|${vacancy._id}|${vacancy._class}|content` + const link = concatLink(front, path) + return `${vacancy.name}` } /** @@ -56,7 +59,9 @@ export async function vacancyTextPresenter (doc: Doc): Promise { export async function applicationHTMLPresenter (doc: Doc, control: TriggerControl): Promise { const applicant = doc as Applicant const front = getMetadata(login.metadata.FrontUrl) ?? '' - return `APP-${applicant.number}` + const path = `${workbenchId}/${control.workspace.name}/${recruitId}/${applicant.space}/#${view.component.EditDoc}|${applicant._id}|${applicant._class}|content` + const link = concatLink(front, path) + return `APP-${applicant.number}` } /** diff --git a/server-plugins/task-resources/src/index.ts b/server-plugins/task-resources/src/index.ts index db50381f0a..9e4d3cf9c3 100644 --- a/server-plugins/task-resources/src/index.ts +++ b/server-plugins/task-resources/src/index.ts @@ -14,7 +14,16 @@ // import { Employee } from '@hcengineering/contact' -import core, { AttachedDoc, Doc, Ref, Tx, TxCollectionCUD, TxProcessor, TxUpdateDoc } from '@hcengineering/core' +import core, { + AttachedDoc, + concatLink, + Doc, + Ref, + Tx, + TxCollectionCUD, + TxProcessor, + TxUpdateDoc +} from '@hcengineering/core' import login from '@hcengineering/login' import { NotificationAction } from '@hcengineering/notification' import { getMetadata, Resource } from '@hcengineering/platform' @@ -31,7 +40,9 @@ import { workbenchId } from '@hcengineering/workbench' export async function issueHTMLPresenter (doc: Doc, control: TriggerControl): Promise { const issue = doc as Issue const front = getMetadata(login.metadata.FrontUrl) ?? '' - return `Task-${issue.number}` + const path = `${workbenchId}/${control.workspace.name}/${taskId}/${issue.space}/#${view.component.EditDoc}|${issue._id}|${issue._class}|content` + const link = concatLink(front, path) + return `Task-${issue.number}` } /** diff --git a/server-plugins/tracker-resources/src/index.ts b/server-plugins/tracker-resources/src/index.ts index 48ded257fc..2c32e490fd 100644 --- a/server-plugins/tracker-resources/src/index.ts +++ b/server-plugins/tracker-resources/src/index.ts @@ -16,6 +16,7 @@ import { Employee } from '@hcengineering/contact' import core, { AttachedDoc, + concatLink, Doc, DocumentUpdate, Ref, @@ -59,7 +60,9 @@ export async function issueHTMLPresenter (doc: Doc, control: TriggerControl): Pr const issueName = `${team?.identifier ?? '?'}-${issue.number}` const front = getMetadata(login.metadata.FrontUrl) ?? '' - return `${issueName}` + const path = `${workbenchId}/${control.workspace.name}/${trackerId}/${issue.space}/#${tracker.component.EditIssue}|${issue._id}|${issue._class}|content` + const link = concatLink(front, path) + return `${issueName}` } /** diff --git a/server/account/src/index.ts b/server/account/src/index.ts index ea4e17a48a..b5e715b177 100644 --- a/server/account/src/index.ts +++ b/server/account/src/index.ts @@ -23,6 +23,7 @@ import contact, { } from '@hcengineering/contact' import core, { AccountRole, + concatLink, Data, getWorkspaceId, Ref, @@ -674,7 +675,7 @@ export async function requestPassword (db: Db, productId: string, email: string) restore: email }) - const link = `${front}/login/recovery?id=${token}` + const link = concatLink(front, `/login/recovery?id=${token}`) const text = `We received a request to reset the password for your account. To reset your password, please paste the following link in your web browser's address bar: ${link}. If you have not ordered a password recovery just ignore this letter.` const html = `

We received a request to reset the password for your account. To reset your password, please click the link below: Reset password