mirror of
https://github.com/hcengineering/platform.git
synced 2025-01-03 08:57:14 +03:00
Inbox keyboard action (#2977)
This commit is contained in:
parent
12974b5bb7
commit
ad4394d541
@ -269,9 +269,10 @@ export function createModel (builder: Builder): void {
|
|||||||
label: notification.string.Archive,
|
label: notification.string.Archive,
|
||||||
icon: view.icon.Archive,
|
icon: view.icon.Archive,
|
||||||
input: 'focus',
|
input: 'focus',
|
||||||
|
keyBinding: ['Backspace'],
|
||||||
category: notification.category.Notification,
|
category: notification.category.Notification,
|
||||||
target: notification.class.DocUpdates,
|
target: notification.class.DocUpdates,
|
||||||
context: { mode: 'context', application: notification.app.Notification, group: 'edit' }
|
context: { mode: ['context', 'browser'], group: 'edit' }
|
||||||
},
|
},
|
||||||
notification.action.Hide
|
notification.action.Hide
|
||||||
)
|
)
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||||
import { AnyComponent, Component, Label, Loading, Scroller } from '@hcengineering/ui'
|
import { AnyComponent, Component, Label, Loading, Scroller } from '@hcengineering/ui'
|
||||||
import view from '@hcengineering/view'
|
import view from '@hcengineering/view'
|
||||||
|
import { ActionContext, ListSelectionProvider, SelectDirection } from '@hcengineering/view-resources'
|
||||||
import NotificationView from './NotificationView.svelte'
|
import NotificationView from './NotificationView.svelte'
|
||||||
|
|
||||||
export let visibileNav: boolean
|
export let visibileNav: boolean
|
||||||
@ -39,8 +40,11 @@
|
|||||||
},
|
},
|
||||||
(res) => {
|
(res) => {
|
||||||
docs = res
|
docs = res
|
||||||
if (loading && docs.length > 0) {
|
listProvider.update(docs)
|
||||||
select(docs[0].attachedTo, docs[0].attachedToClass)
|
if (loading || _id === undefined) {
|
||||||
|
changeSelected(selected)
|
||||||
|
} else if (docs.find((p) => p.attachedTo === _id) === undefined) {
|
||||||
|
changeSelected(selected)
|
||||||
}
|
}
|
||||||
loading = false
|
loading = false
|
||||||
},
|
},
|
||||||
@ -51,16 +55,32 @@
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
function select (objectId: Ref<Doc>, objectClass: Ref<Class<Doc>>) {
|
$: changeSelected(selected)
|
||||||
const targetClass = hierarchy.getClass(objectClass)
|
|
||||||
const panelComponent = hierarchy.as(targetClass, view.mixin.ObjectPanel)
|
function changeSelected (index: number) {
|
||||||
component = panelComponent.component ?? view.component.EditDoc
|
if (docs[index] !== undefined) {
|
||||||
_id = objectId
|
select(docs[index])
|
||||||
_class = objectClass
|
} else if (docs.length) {
|
||||||
|
if (index < docs.length - 1) {
|
||||||
|
selected++
|
||||||
|
} else {
|
||||||
|
selected--
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
selected = 0
|
||||||
|
component = undefined
|
||||||
|
_id = undefined
|
||||||
|
_class = undefined
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectHandler (e: CustomEvent) {
|
function select (value: DocUpdates) {
|
||||||
select(e.detail._id, e.detail._class)
|
listProvider.updateFocus(value)
|
||||||
|
const targetClass = hierarchy.getClass(value.attachedToClass)
|
||||||
|
const panelComponent = hierarchy.as(targetClass, view.mixin.ObjectPanel)
|
||||||
|
component = panelComponent.component ?? view.component.EditDoc
|
||||||
|
_id = value.attachedTo
|
||||||
|
_class = value.attachedToClass
|
||||||
}
|
}
|
||||||
|
|
||||||
let component: AnyComponent | undefined
|
let component: AnyComponent | undefined
|
||||||
@ -69,12 +89,28 @@
|
|||||||
|
|
||||||
let viewlets: Map<ActivityKey, TxViewlet>
|
let viewlets: Map<ActivityKey, TxViewlet>
|
||||||
|
|
||||||
|
const listProvider = new ListSelectionProvider((offset: 1 | -1 | 0, of?: Doc, dir?: SelectDirection) => {
|
||||||
|
if (dir === 'vertical') {
|
||||||
|
const value = selected + offset
|
||||||
|
if (docs[value] !== undefined) {
|
||||||
|
selected = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const descriptors = createQuery()
|
const descriptors = createQuery()
|
||||||
descriptors.query(activity.class.TxViewlet, {}, (result) => {
|
descriptors.query(activity.class.TxViewlet, {}, (result) => {
|
||||||
viewlets = new Map(result.map((r) => [activityKey(r.objectClass, r.txClass), r]))
|
viewlets = new Map(result.map((r) => [activityKey(r.objectClass, r.txClass), r]))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
let selected = 0
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<ActionContext
|
||||||
|
context={{
|
||||||
|
mode: 'browser'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
<div class="flex h-full">
|
<div class="flex h-full">
|
||||||
{#if visibileNav}
|
{#if visibileNav}
|
||||||
<div class="antiPanel-component border-right filled indent aside">
|
<div class="antiPanel-component border-right filled indent aside">
|
||||||
@ -88,8 +124,15 @@
|
|||||||
{#if loading}
|
{#if loading}
|
||||||
<Loading />
|
<Loading />
|
||||||
{:else}
|
{:else}
|
||||||
{#each docs as doc}
|
{#each docs as doc, i}
|
||||||
<NotificationView value={doc} selected={doc.attachedTo === _id} {viewlets} on:click={selectHandler} />
|
<NotificationView
|
||||||
|
value={doc}
|
||||||
|
selected={selected === i}
|
||||||
|
{viewlets}
|
||||||
|
on:click={() => {
|
||||||
|
selected = i
|
||||||
|
}}
|
||||||
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
{/if}
|
{/if}
|
||||||
</Scroller>
|
</Scroller>
|
||||||
@ -99,9 +142,7 @@
|
|||||||
{#if component && _id && _class}
|
{#if component && _id && _class}
|
||||||
<Component is={component} props={{ embedded: true, _id, _class }} />
|
<Component is={component} props={{ embedded: true, _id, _class }} />
|
||||||
{:else}
|
{:else}
|
||||||
<div class="antiPanel-component filled w-full">
|
<div class="antiPanel-component filled w-full" />
|
||||||
<Loading />
|
|
||||||
</div>
|
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -24,7 +24,6 @@
|
|||||||
import { AnySvelteComponent, Label, TimeSince, getEventPositionElement, showPopup } from '@hcengineering/ui'
|
import { AnySvelteComponent, Label, TimeSince, getEventPositionElement, showPopup } from '@hcengineering/ui'
|
||||||
import view from '@hcengineering/view'
|
import view from '@hcengineering/view'
|
||||||
import { Menu } from '@hcengineering/view-resources'
|
import { Menu } from '@hcengineering/view-resources'
|
||||||
import { createEventDispatcher } from 'svelte'
|
|
||||||
import TxView from './TxView.svelte'
|
import TxView from './TxView.svelte'
|
||||||
|
|
||||||
export let value: DocUpdates
|
export let value: DocUpdates
|
||||||
@ -60,10 +59,10 @@
|
|||||||
query.query(contact.class.EmployeeAccount, { _id: tx.modifiedBy as Ref<EmployeeAccount> }, (r) => ([account] = r))
|
query.query(contact.class.EmployeeAccount, { _id: tx.modifiedBy as Ref<EmployeeAccount> }, (r) => ([account] = r))
|
||||||
$: employee = account && $employeeByIdStore.get(account.employee)
|
$: employee = account && $employeeByIdStore.get(account.employee)
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
|
||||||
|
|
||||||
const docQuery = createQuery()
|
const docQuery = createQuery()
|
||||||
$: docQuery.query(value.attachedToClass, { _id: value.attachedTo }, (res) => ([doc] = res))
|
$: docQuery.query(value.attachedToClass, { _id: value.attachedTo }, (res) => {
|
||||||
|
;[doc] = res
|
||||||
|
})
|
||||||
|
|
||||||
$: newTxes = value.txes.length
|
$: newTxes = value.txes.length
|
||||||
|
|
||||||
@ -74,12 +73,7 @@
|
|||||||
|
|
||||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
{#if doc}
|
{#if doc}
|
||||||
<div
|
<div class="container cursor-pointer bottom-divider" class:selected on:contextmenu|preventDefault={showMenu} on:click>
|
||||||
class="container cursor-pointer bottom-divider"
|
|
||||||
class:selected
|
|
||||||
on:contextmenu|preventDefault={showMenu}
|
|
||||||
on:click={() => dispatch('click', { _id: value.attachedTo, _class: value.attachedToClass })}
|
|
||||||
>
|
|
||||||
<div class="header flex">
|
<div class="header flex">
|
||||||
<Avatar avatar={employee?.avatar} size="medium" />
|
<Avatar avatar={employee?.avatar} size="medium" />
|
||||||
<div class="ml-2 w-full clear-mins">
|
<div class="ml-2 w-full clear-mins">
|
||||||
|
@ -133,12 +133,20 @@ export async function unsubscribe (object: DocUpdates): Promise<void> {
|
|||||||
/**
|
/**
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export async function hide (object: DocUpdates): Promise<void> {
|
export async function hide (object: DocUpdates | DocUpdates[]): Promise<void> {
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
|
if (Array.isArray(object)) {
|
||||||
|
for (const value of object) {
|
||||||
|
await client.update(value, {
|
||||||
|
hidden: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
await client.update(object, {
|
await client.update(object, {
|
||||||
hidden: true
|
hidden: true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @public
|
* @public
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Doc, DocumentQuery, Ref } from '@hcengineering/core'
|
import { Doc, DocumentQuery, Ref } from '@hcengineering/core'
|
||||||
import { Issue, Project } from '@hcengineering/tracker'
|
import { Issue, Project } from '@hcengineering/tracker'
|
||||||
import { Viewlet, ViewOptions } from '@hcengineering/view'
|
import { ViewOptions, Viewlet } from '@hcengineering/view'
|
||||||
import {
|
import {
|
||||||
ActionContext,
|
ActionContext,
|
||||||
List,
|
List,
|
||||||
@ -23,7 +23,6 @@
|
|||||||
SelectDirection,
|
SelectDirection,
|
||||||
selectionStore
|
selectionStore
|
||||||
} from '@hcengineering/view-resources'
|
} from '@hcengineering/view-resources'
|
||||||
import { onDestroy } from 'svelte'
|
|
||||||
import tracker from '../../../plugin'
|
import tracker from '../../../plugin'
|
||||||
|
|
||||||
export let query: DocumentQuery<Issue> | undefined = undefined
|
export let query: DocumentQuery<Issue> | undefined = undefined
|
||||||
@ -43,10 +42,6 @@
|
|||||||
list.select(offset, of)
|
list.select(offset, of)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
onDestroy(() => {
|
|
||||||
ListSelectionProvider.Pop()
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ActionContext
|
<ActionContext
|
||||||
|
@ -146,15 +146,17 @@ export class ListSelectionProvider implements SelectionFocusProvider {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if (this._docs.length > 0) {
|
if (this._docs.length > 0) {
|
||||||
if (this._current?.focus === undefined) {
|
if (this._current === undefined) {
|
||||||
this.delegate(0, undefined, 'vertical')
|
this.delegate(0, undefined, 'vertical')
|
||||||
} else {
|
} else {
|
||||||
// Check if we don't have object, we need to select first one.
|
// Check if we don't have object, we need to select first one.
|
||||||
this.delegate(0, this._current?.focus, 'vertical')
|
this.delegate(0, this._current?.focus, 'vertical')
|
||||||
}
|
}
|
||||||
|
if (this._current?.focus === undefined) {
|
||||||
updateFocus({ focus: this._current?.focus, provider: this })
|
updateFocus({ focus: this._current?.focus, provider: this })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
docs (): Doc[] {
|
docs (): Doc[] {
|
||||||
return this._docs
|
return this._docs
|
||||||
|
@ -132,7 +132,10 @@ async function CommentCreate (tx: TxCUD<Doc>, control: TriggerControl): Promise<
|
|||||||
const actualTx = TxProcessor.extractTx(tx)
|
const actualTx = TxProcessor.extractTx(tx)
|
||||||
if (actualTx._class !== core.class.TxCreateDoc) return []
|
if (actualTx._class !== core.class.TxCreateDoc) return []
|
||||||
const doc = TxProcessor.createDoc2Doc(actualTx as TxCreateDoc<Comment>)
|
const doc = TxProcessor.createDoc2Doc(actualTx as TxCreateDoc<Comment>)
|
||||||
if (!hierarchy.isDerived(doc._class, chunter.class.Comment)) {
|
if (
|
||||||
|
!hierarchy.isDerived(doc._class, chunter.class.Comment) ||
|
||||||
|
hierarchy.isDerived(doc._class, chunter.class.Backlink)
|
||||||
|
) {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
const res: Tx[] = []
|
const res: Tx[] = []
|
||||||
|
@ -94,6 +94,16 @@ export async function OnBacklinkCreate (tx: Tx, control: TriggerControl): Promis
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
res.push(collabTx)
|
res.push(collabTx)
|
||||||
|
res = res.concat(
|
||||||
|
await createCollabDocInfo(
|
||||||
|
[receiver._id],
|
||||||
|
tx as TxCUD<Doc>,
|
||||||
|
doc._id,
|
||||||
|
doc._class,
|
||||||
|
control,
|
||||||
|
tx._id as Ref<TxCUD<Doc>>
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const notifyTx = await createNotificationTxes(
|
const notifyTx = await createNotificationTxes(
|
||||||
|
Loading…
Reference in New Issue
Block a user