Open workspace in new tab (#2345)

Signed-off-by: Denis Bunakalya <denis.bunakalya@xored.com>
This commit is contained in:
Denis Bunakalya 2022-11-07 11:42:29 +03:00 committed by GitHub
parent e64172c867
commit 9638843e4d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 124 additions and 55 deletions

View File

@ -93,10 +93,10 @@
)
}
}
function focusTarget (action: Action, target: HTMLElement): void {
function focusTarget (action: Action, target: HTMLElement, isPopupHidden?: boolean): void {
if (focusSpeed && target !== activeElement) {
activeElement = target
showActionPopup(action, target)
!isPopupHidden && showActionPopup(action, target)
}
}
export function clearFocus (): void {
@ -148,7 +148,7 @@
<span class="overflow-label pr-1 flex-grow"><Label label={action.label} /></span>
</button>
</a>
{:else if action.component !== undefined}
{:else if action.component !== undefined && !action.isSubmenuRightClicking}
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
<button
bind:this={btns[i]}
@ -168,11 +168,17 @@
bind:this={btns[i]}
class="ap-menuItem flex-row-center withIcon"
class:hover={btns[i] === activeElement}
on:mouseover={() => focusTarget(action, btns[i])}
on:mouseover={() => focusTarget(action, btns[i], action.isSubmenuRightClicking)}
on:click={(evt) => {
if (!action.inline) dispatch('close')
action.action(ctx, evt)
}}
on:contextmenu={(evt) => {
if (action.component) {
evt.preventDefault()
showActionPopup(action, btns[i])
}
}}
>
{#if action.icon}
<div class="icon mr-3"><Icon icon={action.icon} size={'small'} /></div>

View File

@ -72,6 +72,7 @@ export interface Action {
// Submenu component
component?: AnyComponent | AnySvelteComponent
props?: Record<string, any>
isSubmenuRightClicking?: boolean
group?: string
}

View File

@ -14,21 +14,18 @@
// limitations under the License.
-->
<script lang="ts">
import { OK, setMetadata, Severity, Status } from '@hcengineering/platform'
import { OK, Severity, Status } from '@hcengineering/platform'
import {
Button,
fetchMetadataLocalStorage,
getCurrentLocation,
Label,
Location,
navigate,
setMetadataLocalStorage,
deviceOptionsStore as deviceInfo,
Scroller
} from '@hcengineering/ui'
import { workbenchId } from '@hcengineering/workbench'
import login from '../plugin'
import { getWorkspaces, selectWorkspace, Workspace } from '../utils'
import { getWorkspaces, selectWorkspace, Workspace, navigateToWorkspace } from '../utils'
import StatusControl from './StatusControl.svelte'
export let navigateUrl: string | undefined = undefined
@ -41,22 +38,7 @@
const [loginStatus, result] = await selectWorkspace(workspace)
status = loginStatus
if (result !== undefined) {
setMetadata(login.metadata.LoginToken, result.token)
const tokens: Record<string, string> = fetchMetadataLocalStorage(login.metadata.LoginTokens) ?? {}
tokens[result.workspace] = result.token
setMetadataLocalStorage(login.metadata.LoginTokens, tokens)
setMetadataLocalStorage(login.metadata.LoginEndpoint, result.endpoint)
setMetadataLocalStorage(login.metadata.LoginEmail, result.email)
if (navigateUrl !== undefined) {
const url = JSON.parse(decodeURIComponent(navigateUrl)) as Location
if (url.path[1] === workspace) {
navigate(url)
return
}
}
navigate({ path: [workbenchId, workspace] })
}
navigateToWorkspace(workspace, result, navigateUrl)
}
async function _getWorkspaces (): Promise<Workspace[]> {

View File

@ -23,9 +23,17 @@ import {
serialize,
Status,
unknownError,
unknownStatus
unknownStatus,
setMetadata
} from '@hcengineering/platform'
import { fetchMetadataLocalStorage, getCurrentLocation, navigate } from '@hcengineering/ui'
import {
fetchMetadataLocalStorage,
getCurrentLocation,
navigate,
setMetadataLocalStorage,
Location
} from '@hcengineering/ui'
import { workbenchId } from '@hcengineering/workbench'
export interface WorkspaceLoginInfo extends LoginInfo {
workspace: string
@ -268,6 +276,34 @@ export async function selectWorkspace (workspace: string): Promise<[Status, Work
}
}
export function setLoginInfo (loginInfo: WorkspaceLoginInfo): void {
setMetadata(login.metadata.LoginToken, loginInfo.token)
const tokens: Record<string, string> = fetchMetadataLocalStorage(login.metadata.LoginTokens) ?? {}
tokens[loginInfo.workspace] = loginInfo.token
setMetadataLocalStorage(login.metadata.LoginTokens, tokens)
setMetadataLocalStorage(login.metadata.LoginEndpoint, loginInfo.endpoint)
setMetadataLocalStorage(login.metadata.LoginEmail, loginInfo.email)
}
export function navigateToWorkspace (workspace: string, loginInfo?: WorkspaceLoginInfo, navigateUrl?: string): void {
if (loginInfo == null) {
return
}
setLoginInfo(loginInfo)
if (navigateUrl !== undefined) {
const url = JSON.parse(decodeURIComponent(navigateUrl)) as Location
if (url.path[1] === workspace) {
navigate(url)
return
}
}
navigate({ path: [workbenchId, workspace] })
}
export async function checkJoined (inviteId: string): Promise<[Status, WorkspaceLoginInfo | undefined]> {
const accountsUrl = getMetadata(login.metadata.AccountsUrl)

View File

@ -25,6 +25,7 @@
"OpenPlatformGuide": "Open Platform Guide",
"AccessWorkspaceSettings": "Access your workspace settings",
"HowToWorkFaster": "Learn how to work faster",
"HiddenApplication": "Hidden application"
"HiddenApplication": "Hidden application",
"OpenInNewTab": "Open in a new tab"
}
}

View File

@ -25,6 +25,7 @@
"OpenPlatformGuide": "Открыть руководство пользователя",
"AccessWorkspaceSettings": "Открыть настройки рабочего пространства",
"HowToWorkFaster": "Узнайте как работать эффективнее",
"HiddenApplication": "Скрытое приложение"
"HiddenApplication": "Скрытое приложение",
"OpenInNewTab": "Открыть в новой вкладке"
}
}

View File

@ -45,6 +45,7 @@
"@hcengineering/notification-resources": "~0.6.0",
"@hcengineering/preference": "^0.6.1",
"@hcengineering/contact": "~0.6.5",
"@hcengineering/view-resources": "~0.6.0"
"@hcengineering/view-resources": "~0.6.0",
"@hcengineering/login-resources": "~0.6.2"
}
}

View File

@ -16,7 +16,14 @@
import contact, { Employee, EmployeeAccount, formatName } from '@hcengineering/contact'
import { AccountRole, getCurrentAccount } from '@hcengineering/core'
import login from '@hcengineering/login'
import { setMetadata } from '@hcengineering/platform'
import {
getWorkspaces,
selectWorkspace,
Workspace,
navigateToWorkspace,
setLoginInfo
} from '@hcengineering/login-resources'
import { setMetadata, getEmbeddedLabel } from '@hcengineering/platform'
import { Avatar, createQuery } from '@hcengineering/presentation'
import setting, { settingId, SettingsCategory } from '@hcengineering/setting'
import { Action, fetchMetadataLocalStorage } from '@hcengineering/ui'
@ -31,10 +38,14 @@
locationToUrl
} from '@hcengineering/ui'
import view from '@hcengineering/view'
import { workbenchId } from '@hcengineering/workbench'
import HelpAndSupport from './HelpAndSupport.svelte'
import workbench from '../plugin'
let items: SettingsCategory[] = []
let workspaces: Workspace[] = []
getWorkspaces().then((ws: Workspace[]) => (workspaces = ws))
const settingsQuery = createQuery()
settingsQuery.query(
@ -84,10 +95,6 @@
navigate({ path: [login.component.LoginApp] })
}
function selectWorkspace (): void {
navigate({ path: [login.component.LoginApp, 'selectWorkspace'] })
}
function inviteWorkspace (): void {
showPopup(login.component.InviteLink, {})
}
@ -130,8 +137,37 @@
return actions
}
function getWorkspaceItems () {
return workspaces.map((w) => ({
label: getEmbeddedLabel(w.workspace),
action: async () => {
const loginInfo = (await selectWorkspace(w.workspace))[1]
navigateToWorkspace(w.workspace, loginInfo)
},
isSubmenuRightClicking: true,
component: Menu,
props: {
actions: [
{
label: workbench.string.OpenInNewTab,
action: async () => {
const loginInfo = (await selectWorkspace(w.workspace))[1]
if (!loginInfo) {
return
}
setLoginInfo(loginInfo)
const url = locationToUrl({ path: [workbenchId, w.workspace] })
window.open(url, '_blank')?.focus()
}
}
]
}
}))
}
let actions: Action[] = []
$: if (items) {
$: if (items && workspaces) {
actions = []
const subActions: Action[] = getMenu(items, ['settings', 'settings-editor'])
actions.push({
@ -146,7 +182,9 @@
{
icon: setting.icon.SelectWorkspace,
label: setting.string.SelectWorkspace,
action: async () => selectWorkspace(),
action: async () => {},
component: Menu,
props: { actions: getWorkspaceItems() },
group: 'end'
},
{

View File

@ -15,28 +15,30 @@
<script lang="ts">
import { getMetadata } from '@hcengineering/platform'
import { connect, versionError } from '@hcengineering/presentation'
import { Loading, Notifications } from '@hcengineering/ui'
import { Loading, Notifications, location } from '@hcengineering/ui'
import Workbench from './Workbench.svelte'
import workbench from '../plugin'
</script>
{#await connect(getMetadata(workbench.metadata.PlatformTitle) ?? 'Platform')}
<Loading />
{:then client}
{#if !client && versionError}
<div class="antiPopup version-popup">
<h1>Server is under maintenance.</h1>
{versionError}
</div>
{:else if client}
<Notifications>
<Workbench {client} />
</Notifications>
{/if}
{:catch error}
<div>{error} -- {error.stack}</div>
{/await}
{#key $location.path[1]}
{#await connect(getMetadata(workbench.metadata.PlatformTitle) ?? 'Platform')}
<Loading />
{:then client}
{#if !client && versionError}
<div class="antiPopup version-popup">
<h1>Server is under maintenance.</h1>
{versionError}
</div>
{:else if client}
<Notifications>
<Workbench {client} />
</Notifications>
{/if}
{:catch error}
<div>{error} -- {error.stack}</div>
{/await}
{/key}
<style lang="scss">
.version-popup {

View File

@ -44,7 +44,8 @@ export default mergeIds(workbenchId, workbench, {
ContactUs: '' as IntlString,
OpenPlatformGuide: '' as IntlString,
AccessWorkspaceSettings: '' as IntlString,
HowToWorkFaster: '' as IntlString
HowToWorkFaster: '' as IntlString,
OpenInNewTab: '' as IntlString
},
component: {
SpacePanel: '' as AnyComponent