mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-17 13:54:11 +00:00
tracker key actions (#2598)
Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
parent
243bc1dede
commit
c5be92d870
@ -284,7 +284,9 @@ export function createModel (builder: Builder): void {
|
||||
input: 'any',
|
||||
category: board.category.Card,
|
||||
target: board.class.Card,
|
||||
context: { mode: 'context', application: board.app.Board, group: 'create' }
|
||||
keyBinding: ['Enter'],
|
||||
context: { mode: 'context', application: board.app.Board, group: 'create' },
|
||||
override: [view.action.Open]
|
||||
},
|
||||
board.action.Open
|
||||
)
|
||||
|
@ -30,7 +30,7 @@ import {
|
||||
Persons,
|
||||
Status
|
||||
} from '@hcengineering/contact'
|
||||
import { Class, DateRangeMode, Domain, Ref, Timestamp, DOMAIN_MODEL, IndexKind } from '@hcengineering/core'
|
||||
import { Class, DateRangeMode, Domain, DOMAIN_MODEL, IndexKind, Ref, Timestamp } from '@hcengineering/core'
|
||||
import {
|
||||
Builder,
|
||||
Collection,
|
||||
@ -48,7 +48,7 @@ import attachment from '@hcengineering/model-attachment'
|
||||
import chunter from '@hcengineering/model-chunter'
|
||||
import core, { TAccount, TAttachedDoc, TDoc, TSpace } from '@hcengineering/model-core'
|
||||
import presentation from '@hcengineering/model-presentation'
|
||||
import view, { actionTemplates, createAction, ViewAction, Viewlet } from '@hcengineering/model-view'
|
||||
import view, { createAction, ViewAction, Viewlet } from '@hcengineering/model-view'
|
||||
import workbench from '@hcengineering/model-workbench'
|
||||
import type { Asset, IntlString, Resource } from '@hcengineering/platform'
|
||||
import setting from '@hcengineering/setting'
|
||||
@ -498,15 +498,6 @@ export function createModel (builder: Builder): void {
|
||||
contact.completion.OrganizationCategory
|
||||
)
|
||||
|
||||
createAction(builder, {
|
||||
...actionTemplates.open,
|
||||
target: contact.class.Contact,
|
||||
context: {
|
||||
mode: ['browser', 'context'],
|
||||
group: 'create'
|
||||
}
|
||||
})
|
||||
|
||||
createAction(
|
||||
builder,
|
||||
{
|
||||
|
@ -245,11 +245,15 @@ export function createModel (builder: Builder): void {
|
||||
|
||||
createAction(builder, {
|
||||
...actionTemplates.open,
|
||||
actionProps: {
|
||||
component: document.component.EditDoc
|
||||
},
|
||||
target: document.class.Document,
|
||||
context: {
|
||||
mode: ['browser', 'context'],
|
||||
group: 'create'
|
||||
}
|
||||
},
|
||||
override: [view.action.Open]
|
||||
})
|
||||
builder.mixin(document.class.DocumentVersion, core.class.Class, view.mixin.CollectionEditor, {
|
||||
editor: document.component.DocumentVersions
|
||||
|
@ -179,7 +179,7 @@ export function createModel (builder: Builder): void {
|
||||
label: gmail.string.WrtieEmail,
|
||||
icon: contact.icon.Email,
|
||||
keyBinding: [],
|
||||
input: 'none',
|
||||
input: 'any',
|
||||
category: contact.category.Contact,
|
||||
target: contact.class.Contact,
|
||||
context: {
|
||||
|
@ -620,7 +620,7 @@ export function createModel (builder: Builder): void {
|
||||
},
|
||||
label: recruit.string.CreateTalent,
|
||||
icon: recruit.icon.Create,
|
||||
keyBinding: ['c'],
|
||||
keyBinding: ['keyC'],
|
||||
input: 'none',
|
||||
category: recruit.category.Recruit,
|
||||
target: core.class.Doc,
|
||||
@ -720,7 +720,7 @@ export function createModel (builder: Builder): void {
|
||||
},
|
||||
input: 'focus',
|
||||
category: recruit.category.Recruit,
|
||||
keyBinding: ['e'],
|
||||
keyBinding: ['keyE'],
|
||||
target: recruit.class.Vacancy,
|
||||
context: {
|
||||
mode: ['context', 'browser'],
|
||||
|
@ -117,6 +117,10 @@ export function createModel (builder: Builder): void {
|
||||
component: tags.component.TagsFilter
|
||||
})
|
||||
|
||||
builder.mixin(tags.class.TagElement, core.class.Class, view.mixin.IgnoreActions, {
|
||||
actions: [view.action.Open]
|
||||
})
|
||||
|
||||
builder.createDoc(
|
||||
view.class.FilterMode,
|
||||
core.space.Model,
|
||||
|
@ -48,7 +48,7 @@ import {
|
||||
import attachment from '@hcengineering/model-attachment'
|
||||
import chunter from '@hcengineering/model-chunter'
|
||||
import core, { DOMAIN_SPACE, TAttachedDoc, TDoc, TSpace, TType } from '@hcengineering/model-core'
|
||||
import view, { classPresenter, createAction } from '@hcengineering/model-view'
|
||||
import view, { actionTemplates, classPresenter, createAction } from '@hcengineering/model-view'
|
||||
import workbench, { createNavigateAction } from '@hcengineering/model-workbench'
|
||||
import notification from '@hcengineering/notification'
|
||||
import { Asset, IntlString } from '@hcengineering/platform'
|
||||
@ -1053,6 +1053,29 @@ export function createModel (builder: Builder): void {
|
||||
tracker.category.Tracker
|
||||
)
|
||||
|
||||
createAction(
|
||||
builder,
|
||||
{
|
||||
action: view.actionImpl.ShowPopup,
|
||||
actionProps: {
|
||||
component: tracker.component.CreateIssue,
|
||||
element: 'top'
|
||||
},
|
||||
label: tracker.string.NewIssue,
|
||||
icon: tracker.icon.Issue,
|
||||
keyBinding: ['keyC'],
|
||||
input: 'none',
|
||||
category: tracker.category.Tracker,
|
||||
target: tracker.class.Issue,
|
||||
context: {
|
||||
mode: ['browser'],
|
||||
application: tracker.app.Tracker,
|
||||
group: 'create'
|
||||
}
|
||||
},
|
||||
tracker.action.NewSubIssue
|
||||
)
|
||||
|
||||
createAction(
|
||||
builder,
|
||||
{
|
||||
@ -1156,6 +1179,32 @@ export function createModel (builder: Builder): void {
|
||||
}
|
||||
})
|
||||
|
||||
createAction(builder, {
|
||||
...actionTemplates.open,
|
||||
actionProps: {
|
||||
component: tracker.component.EditIssue
|
||||
},
|
||||
target: tracker.class.Issue,
|
||||
context: {
|
||||
mode: ['browser', 'context'],
|
||||
group: 'create'
|
||||
},
|
||||
override: [view.action.Open]
|
||||
})
|
||||
|
||||
createAction(builder, {
|
||||
...actionTemplates.open,
|
||||
actionProps: {
|
||||
component: tracker.component.EditIssueTemplate
|
||||
},
|
||||
target: tracker.class.IssueTemplate,
|
||||
context: {
|
||||
mode: ['browser', 'context'],
|
||||
group: 'create'
|
||||
},
|
||||
override: [view.action.Open]
|
||||
})
|
||||
|
||||
builder.mixin(tracker.class.Issue, core.class.Class, view.mixin.ClassFilters, {
|
||||
filters: ['status', 'priority', 'assignee', 'project', 'sprint', 'estimation', 'dueDate', 'modifiedOn']
|
||||
})
|
||||
@ -1182,6 +1231,27 @@ export function createModel (builder: Builder): void {
|
||||
sort: { rank: SortingOrder.Ascending }
|
||||
}
|
||||
|
||||
createAction(builder, {
|
||||
action: view.actionImpl.ShowPopup,
|
||||
actionProps: {
|
||||
component: tracker.component.TimeSpendReportPopup,
|
||||
fillProps: {
|
||||
_object: 'issue'
|
||||
}
|
||||
},
|
||||
label: tracker.string.TimeSpendReportAdd,
|
||||
icon: tracker.icon.TimeReport,
|
||||
input: 'focus',
|
||||
keyBinding: ['keyT'],
|
||||
category: tracker.category.Tracker,
|
||||
target: tracker.class.Issue,
|
||||
context: {
|
||||
mode: ['context', 'browser'],
|
||||
application: tracker.app.Tracker,
|
||||
group: 'edit'
|
||||
}
|
||||
})
|
||||
|
||||
createAction(
|
||||
builder,
|
||||
{
|
||||
@ -1198,12 +1268,12 @@ export function createModel (builder: Builder): void {
|
||||
},
|
||||
label: tracker.string.Status,
|
||||
icon: tracker.icon.CategoryBacklog,
|
||||
keyBinding: [],
|
||||
input: 'none',
|
||||
keyBinding: ['keyS->keyS'],
|
||||
input: 'any',
|
||||
category: tracker.category.Tracker,
|
||||
target: tracker.class.Issue,
|
||||
context: {
|
||||
mode: ['context'],
|
||||
mode: ['context', 'browser'],
|
||||
application: tracker.app.Tracker,
|
||||
group: 'edit'
|
||||
}
|
||||
@ -1222,12 +1292,12 @@ export function createModel (builder: Builder): void {
|
||||
},
|
||||
label: tracker.string.Priority,
|
||||
icon: tracker.icon.PriorityHigh,
|
||||
keyBinding: [],
|
||||
input: 'none',
|
||||
keyBinding: ['keyP-keyR'],
|
||||
input: 'any',
|
||||
category: tracker.category.Tracker,
|
||||
target: tracker.class.Issue,
|
||||
context: {
|
||||
mode: ['context'],
|
||||
mode: ['context', 'browser'],
|
||||
application: tracker.app.Tracker,
|
||||
group: 'edit'
|
||||
}
|
||||
@ -1247,12 +1317,12 @@ export function createModel (builder: Builder): void {
|
||||
},
|
||||
label: tracker.string.Assignee,
|
||||
icon: contact.icon.Person,
|
||||
keyBinding: [],
|
||||
input: 'none',
|
||||
keyBinding: ['keyA'],
|
||||
input: 'any',
|
||||
category: tracker.category.Tracker,
|
||||
target: tracker.class.Issue,
|
||||
context: {
|
||||
mode: ['context'],
|
||||
mode: ['context', 'browser'],
|
||||
application: tracker.app.Tracker,
|
||||
group: 'edit'
|
||||
}
|
||||
@ -1274,12 +1344,12 @@ export function createModel (builder: Builder): void {
|
||||
},
|
||||
label: tracker.string.Project,
|
||||
icon: tracker.icon.Project,
|
||||
keyBinding: [],
|
||||
input: 'none',
|
||||
keyBinding: ['keyP->keyP'],
|
||||
input: 'any',
|
||||
category: tracker.category.Tracker,
|
||||
target: tracker.class.Issue,
|
||||
context: {
|
||||
mode: ['context'],
|
||||
mode: ['context', 'browser'],
|
||||
application: tracker.app.Tracker,
|
||||
group: 'edit'
|
||||
}
|
||||
@ -1307,12 +1377,12 @@ export function createModel (builder: Builder): void {
|
||||
},
|
||||
label: tracker.string.Sprint,
|
||||
icon: tracker.icon.Sprint,
|
||||
keyBinding: [],
|
||||
input: 'none',
|
||||
keyBinding: ['keyS->keyP'],
|
||||
input: 'any',
|
||||
category: tracker.category.Tracker,
|
||||
target: tracker.class.Issue,
|
||||
context: {
|
||||
mode: ['context'],
|
||||
mode: ['context', 'browser'],
|
||||
application: tracker.app.Tracker,
|
||||
group: 'edit'
|
||||
}
|
||||
@ -1334,8 +1404,8 @@ export function createModel (builder: Builder): void {
|
||||
},
|
||||
label: tracker.string.SetDueDate,
|
||||
icon: tracker.icon.DueDate,
|
||||
keyBinding: [],
|
||||
input: 'none',
|
||||
keyBinding: ['keyD'],
|
||||
input: 'any',
|
||||
category: tracker.category.Tracker,
|
||||
target: tracker.class.Issue,
|
||||
context: {
|
||||
@ -1356,7 +1426,7 @@ export function createModel (builder: Builder): void {
|
||||
label: tracker.string.CopyIssueId,
|
||||
icon: tracker.icon.CopyID,
|
||||
keyBinding: [],
|
||||
input: 'none',
|
||||
input: 'focus',
|
||||
category: tracker.category.Tracker,
|
||||
target: tracker.class.Issue,
|
||||
context: {
|
||||
@ -1377,7 +1447,7 @@ export function createModel (builder: Builder): void {
|
||||
label: tracker.string.CopyIssueTitle,
|
||||
icon: tracker.icon.CopyBranch,
|
||||
keyBinding: [],
|
||||
input: 'none',
|
||||
input: 'focus',
|
||||
category: tracker.category.Tracker,
|
||||
target: tracker.class.Issue,
|
||||
context: {
|
||||
@ -1398,7 +1468,7 @@ export function createModel (builder: Builder): void {
|
||||
label: tracker.string.CopyIssueUrl,
|
||||
icon: tracker.icon.CopyURL,
|
||||
keyBinding: [],
|
||||
input: 'none',
|
||||
input: 'focus',
|
||||
category: tracker.category.Tracker,
|
||||
target: tracker.class.Issue,
|
||||
context: {
|
||||
@ -1416,7 +1486,7 @@ export function createModel (builder: Builder): void {
|
||||
label: tracker.string.MoveToTeam,
|
||||
icon: view.icon.Move,
|
||||
keyBinding: [],
|
||||
input: 'none',
|
||||
input: 'any',
|
||||
category: tracker.category.Tracker,
|
||||
target: tracker.class.Issue,
|
||||
context: {
|
||||
@ -1465,7 +1535,7 @@ export function createModel (builder: Builder): void {
|
||||
label: tracker.string.Duplicate,
|
||||
icon: tracker.icon.Duplicate,
|
||||
keyBinding: [],
|
||||
input: 'none',
|
||||
input: 'focus',
|
||||
category: tracker.category.Tracker,
|
||||
target: tracker.class.Issue,
|
||||
context: {
|
||||
|
@ -41,7 +41,8 @@ export default mergeIds(trackerId, tracker, {
|
||||
// Required to pass build without errorsF
|
||||
Nope: '' as AnyComponent,
|
||||
SprintSelector: '' as AnyComponent,
|
||||
IssueStatistics: '' as AnyComponent
|
||||
IssueStatistics: '' as AnyComponent,
|
||||
TimeSpendReportPopup: '' as AnyComponent
|
||||
},
|
||||
app: {
|
||||
Tracker: '' as Ref<Application>
|
||||
|
@ -731,6 +731,17 @@ export function createModel (builder: Builder): void {
|
||||
target: core.class.Doc,
|
||||
context: { mode: ['context', 'browser', 'editor'] }
|
||||
})
|
||||
|
||||
createAction(
|
||||
builder,
|
||||
{
|
||||
...actionTemplates.open,
|
||||
target: core.class.Doc,
|
||||
category: view.category.Editor,
|
||||
context: { mode: ['browser', 'context'], group: 'edit' }
|
||||
},
|
||||
view.action.Open
|
||||
)
|
||||
}
|
||||
|
||||
export default view
|
||||
|
@ -137,11 +137,6 @@
|
||||
key.stopPropagation()
|
||||
handleSelection(key, selection)
|
||||
}
|
||||
if (key.code === 'Escape') {
|
||||
key.preventDefault()
|
||||
key.stopPropagation()
|
||||
dispatch('close')
|
||||
}
|
||||
}
|
||||
const manager = createFocusManager()
|
||||
|
||||
|
@ -137,11 +137,6 @@
|
||||
key.stopPropagation()
|
||||
handleSelection(key, objects, selection)
|
||||
}
|
||||
if (key.code === 'Escape') {
|
||||
key.preventDefault()
|
||||
key.stopPropagation()
|
||||
dispatch('close')
|
||||
}
|
||||
}
|
||||
const manager = createFocusManager()
|
||||
|
||||
|
@ -16,9 +16,9 @@
|
||||
import type { IntlString } from '@hcengineering/platform'
|
||||
import { translate } from '@hcengineering/platform'
|
||||
import { createEventDispatcher, onMount } from 'svelte'
|
||||
import { deviceOptionsStore, resizeObserver } from '..'
|
||||
import { getPlatformColor } from '../colors'
|
||||
import ListView from './ListView.svelte'
|
||||
import { resizeObserver, deviceOptionsStore } from '..'
|
||||
|
||||
export let placeholder: IntlString | undefined = undefined
|
||||
export let placeholderParam: any | undefined = undefined
|
||||
@ -62,11 +62,6 @@
|
||||
key.stopPropagation()
|
||||
handleSelection(key, selection)
|
||||
}
|
||||
if (key.code === 'Escape') {
|
||||
key.preventDefault()
|
||||
key.stopPropagation()
|
||||
dispatch('close')
|
||||
}
|
||||
}
|
||||
let input: HTMLElement
|
||||
onMount(() => {
|
||||
|
@ -16,11 +16,11 @@
|
||||
import type { IntlString } from '@hcengineering/platform'
|
||||
import { translate } from '@hcengineering/platform'
|
||||
import { createEventDispatcher, onMount } from 'svelte'
|
||||
import type { DropdownTextItem } from '../types'
|
||||
import { deviceOptionsStore, resizeObserver } from '..'
|
||||
import plugin from '../plugin'
|
||||
import type { DropdownTextItem } from '../types'
|
||||
import CheckBox from './CheckBox.svelte'
|
||||
import ListView from './ListView.svelte'
|
||||
import { resizeObserver, deviceOptionsStore } from '..'
|
||||
|
||||
export let placeholder: IntlString = plugin.string.SearchDots
|
||||
export let items: DropdownTextItem[]
|
||||
@ -76,11 +76,6 @@
|
||||
key.stopPropagation()
|
||||
handleSelection(key, selection)
|
||||
}
|
||||
if (key.code === 'Escape') {
|
||||
key.preventDefault()
|
||||
key.stopPropagation()
|
||||
dispatch('close')
|
||||
}
|
||||
}
|
||||
|
||||
function isSelected (
|
||||
|
@ -16,11 +16,11 @@
|
||||
import type { Asset, IntlString } from '@hcengineering/platform'
|
||||
import { translate } from '@hcengineering/platform'
|
||||
import { createEventDispatcher, onMount } from 'svelte'
|
||||
import type { AnySvelteComponent, ListItem } from '../types'
|
||||
import { deviceOptionsStore, resizeObserver } from '..'
|
||||
import plugin from '../plugin'
|
||||
import type { AnySvelteComponent, ListItem } from '../types'
|
||||
import Icon from './Icon.svelte'
|
||||
import ListView from './ListView.svelte'
|
||||
import { resizeObserver, deviceOptionsStore } from '..'
|
||||
|
||||
export let icon: Asset | AnySvelteComponent
|
||||
export let placeholder: IntlString = plugin.string.SearchDots
|
||||
@ -69,11 +69,6 @@
|
||||
key.stopPropagation()
|
||||
handleSelection(key, selection)
|
||||
}
|
||||
if (key.code === 'Escape') {
|
||||
key.preventDefault()
|
||||
key.stopPropagation()
|
||||
dispatch('close')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -15,10 +15,10 @@
|
||||
<script lang="ts">
|
||||
import { IntlString } from '@hcengineering/platform'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { resizeObserver } from '..'
|
||||
import CheckBox from './CheckBox.svelte'
|
||||
import Label from './Label.svelte'
|
||||
import ListView from './ListView.svelte'
|
||||
import { resizeObserver } from '..'
|
||||
|
||||
export let items: Record<any, IntlString>
|
||||
export let selected: any | undefined = undefined
|
||||
@ -51,11 +51,6 @@
|
||||
key.stopPropagation()
|
||||
handleSelection(key, selection)
|
||||
}
|
||||
if (key.code === 'Escape') {
|
||||
key.preventDefault()
|
||||
key.stopPropagation()
|
||||
dispatch('close')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -15,15 +15,15 @@
|
||||
<script lang="ts">
|
||||
import type { Asset, IntlString } from '@hcengineering/platform'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { deviceOptionsStore, resizeObserver } from '..'
|
||||
import { createFocusManager } from '../focus'
|
||||
import type { AnySvelteComponent } from '../types'
|
||||
import EditBox from './EditBox.svelte'
|
||||
import FocusHandler from './FocusHandler.svelte'
|
||||
import Icon from './Icon.svelte'
|
||||
import IconCheck from './icons/Check.svelte'
|
||||
import Label from './Label.svelte'
|
||||
import ListView from './ListView.svelte'
|
||||
import type { AnySvelteComponent } from '../types'
|
||||
import { resizeObserver, deviceOptionsStore } from '..'
|
||||
|
||||
interface ValueType {
|
||||
id: number | string | null
|
||||
@ -74,11 +74,6 @@
|
||||
key.stopPropagation()
|
||||
dispatch('close', value[selection].id)
|
||||
}
|
||||
if (key.code === 'Escape') {
|
||||
key.preventDefault()
|
||||
key.stopPropagation()
|
||||
dispatch('close')
|
||||
}
|
||||
}
|
||||
const manager = createFocusManager()
|
||||
|
||||
|
@ -23,10 +23,11 @@
|
||||
import { getTimeReportDate, getTimeReportDayType } from '../../../utils'
|
||||
import TimeReportDayDropdown from './TimeReportDayDropdown.svelte'
|
||||
|
||||
export let issueId: Ref<Issue>
|
||||
export let issueClass: Ref<Class<Issue>>
|
||||
export let space: Ref<Space>
|
||||
export let assignee: Ref<Employee> | undefined
|
||||
export let issue: Issue | undefined = undefined
|
||||
export let issueId: Ref<Issue> | undefined = issue?._id
|
||||
export let issueClass: Ref<Class<Issue>> = issue?._class ?? tracker.class.Issue
|
||||
export let space: Ref<Space> | undefined = issue?.space
|
||||
export let assignee: Ref<Employee> | null | undefined = issue?.assignee
|
||||
|
||||
export let value: TimeSpendReport | undefined
|
||||
export let placeholder: IntlString = tracker.string.TimeSpendReportValue
|
||||
@ -45,16 +46,20 @@
|
||||
return true
|
||||
}
|
||||
|
||||
const client = getClient()
|
||||
|
||||
async function create (): Promise<void> {
|
||||
if (value === undefined) {
|
||||
getClient().addCollection(
|
||||
tracker.class.TimeSpendReport,
|
||||
space,
|
||||
issueId,
|
||||
issueClass,
|
||||
'reports',
|
||||
data as AttachedData<TimeSpendReport>
|
||||
)
|
||||
if (space && issueId) {
|
||||
await client.addCollection(
|
||||
tracker.class.TimeSpendReport,
|
||||
space,
|
||||
issueId,
|
||||
issueClass,
|
||||
'reports',
|
||||
data as AttachedData<TimeSpendReport>
|
||||
)
|
||||
}
|
||||
} else {
|
||||
const ops: DocumentUpdate<TimeSpendReport> = {}
|
||||
if (value.value !== data.value) {
|
||||
@ -70,15 +75,17 @@
|
||||
ops.date = data.date
|
||||
}
|
||||
if (Object.keys(ops).length > 0) {
|
||||
getClient().update(value, ops)
|
||||
await client.update(value, ops)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$: canSave = Number.isFinite(data.value) && data.value !== 0 && space !== undefined && issueId !== undefined
|
||||
</script>
|
||||
|
||||
<Card
|
||||
label={tracker.string.TimeSpendReportAdd}
|
||||
canSave={Number.isFinite(data.value) && data.value !== 0}
|
||||
{canSave}
|
||||
okAction={create}
|
||||
on:close
|
||||
okLabel={value === undefined ? presentation.string.Create : presentation.string.Save}
|
||||
|
@ -116,6 +116,7 @@ import StatusRefPresenter from './components/issues/StatusRefPresenter.svelte'
|
||||
import SprintRefPresenter from './components/sprints/SprintRefPresenter.svelte'
|
||||
import { EmployeeAccount } from '@hcengineering/contact'
|
||||
import DeleteProjectPresenter from './components/projects/DeleteProjectPresenter.svelte'
|
||||
import TimeSpendReportPopup from './components/issues/timereport/TimeSpendReportPopup.svelte'
|
||||
|
||||
export { default as SubIssueList } from './components/issues/edit/SubIssueList.svelte'
|
||||
|
||||
@ -368,7 +369,8 @@ export default async (): Promise<Resources> => ({
|
||||
StatusRefPresenter,
|
||||
RelatedIssuesSection,
|
||||
RelatedIssueSelector,
|
||||
DeleteProjectPresenter
|
||||
DeleteProjectPresenter,
|
||||
TimeSpendReportPopup
|
||||
},
|
||||
completion: {
|
||||
IssueQuery: async (client: Client, query: string, filter?: { in?: RelatedDocument[], nin?: RelatedDocument[] }) =>
|
||||
|
@ -11,7 +11,7 @@ import {
|
||||
showPanel,
|
||||
showPopup
|
||||
} from '@hcengineering/ui'
|
||||
import { Action, ViewContext } from '@hcengineering/view'
|
||||
import { ViewContext } from '@hcengineering/view'
|
||||
import MoveView from './components/Move.svelte'
|
||||
import { contextStore } from './context'
|
||||
import view from './plugin'
|
||||
@ -96,12 +96,13 @@ export function select (evt: Event | undefined, offset: 1 | -1 | 0, of?: Doc, di
|
||||
}
|
||||
}
|
||||
|
||||
function SelectItem (doc: Doc | undefined, evt: Event): void {
|
||||
if (doc !== undefined) {
|
||||
function SelectItem (doc: Doc | Doc[] | undefined, evt: Event): void {
|
||||
const focus = $focusStore.focus
|
||||
if (focus !== undefined) {
|
||||
selectionStore.update((selection) => {
|
||||
const ind = selection.findIndex((it) => it._id === doc._id)
|
||||
const ind = selection.findIndex((it) => it._id === focus._id)
|
||||
if (ind === -1) {
|
||||
selection.push(doc)
|
||||
selection.push(focus)
|
||||
} else {
|
||||
selection.splice(ind, 1)
|
||||
}
|
||||
@ -122,10 +123,10 @@ function SelectItemAll (doc: Doc | undefined, evt: Event): void {
|
||||
evt.preventDefault()
|
||||
}
|
||||
|
||||
const MoveUp = (doc: Doc | undefined, evt: Event): void => select(evt, -1, doc, 'vertical')
|
||||
const MoveDown = (doc: Doc | undefined, evt: Event): void => select(evt, 1, doc, 'vertical')
|
||||
const MoveLeft = (doc: Doc | undefined, evt: Event): void => select(evt, -1, doc, 'horizontal')
|
||||
const MoveRight = (doc: Doc | undefined, evt: Event): void => select(evt, 1, doc, 'horizontal')
|
||||
const MoveUp = (doc: Doc | undefined, evt: Event): void => select(evt, -1, $focusStore.focus, 'vertical')
|
||||
const MoveDown = (doc: Doc | undefined, evt: Event): void => select(evt, 1, $focusStore.focus, 'vertical')
|
||||
const MoveLeft = (doc: Doc | undefined, evt: Event): void => select(evt, -1, $focusStore.focus, 'horizontal')
|
||||
const MoveRight = (doc: Doc | undefined, evt: Event): void => select(evt, 1, $focusStore.focus, 'horizontal')
|
||||
|
||||
function ShowActions (doc: Doc | Doc[] | undefined, evt: Event): void {
|
||||
evt.preventDefault()
|
||||
@ -143,9 +144,17 @@ function ShowPreview (doc: Doc | undefined, evt: Event): void {
|
||||
evt.preventDefault()
|
||||
}
|
||||
|
||||
function Open (doc: Doc, evt: Event): void {
|
||||
function Open (
|
||||
doc: Doc,
|
||||
evt: Event,
|
||||
props:
|
||||
| {
|
||||
component?: AnyComponent
|
||||
}
|
||||
| undefined
|
||||
): void {
|
||||
evt.preventDefault()
|
||||
showPanel(view.component.EditDoc, doc._id, Hierarchy.mixinOrClass(doc), 'content')
|
||||
showPanel(props?.component ?? view.component.EditDoc, doc._id, Hierarchy.mixinOrClass(doc), 'content')
|
||||
}
|
||||
|
||||
/**
|
||||
@ -319,7 +328,7 @@ function ValueSelector (
|
||||
doc: Doc | Doc[],
|
||||
evt: Event,
|
||||
props: {
|
||||
action: Action
|
||||
actionPopup: AnyComponent
|
||||
|
||||
attribute: string
|
||||
|
||||
@ -340,9 +349,7 @@ function ValueSelector (
|
||||
placeholder?: IntlString
|
||||
}
|
||||
): void {
|
||||
if (props.action.actionPopup !== undefined) {
|
||||
showPopup(props.action.actionPopup, { ...props, ...props.action.actionProps, value: doc, width: 'large' }, 'top')
|
||||
}
|
||||
showPopup(view.component.ValueSelector, { ...props, value: doc, width: 'large' }, 'top')
|
||||
}
|
||||
|
||||
async function getPopupAlignment (
|
||||
|
@ -148,9 +148,6 @@ export function filterActions (
|
||||
if (role < AccountRole.Maintainer && action.secured === true) {
|
||||
continue
|
||||
}
|
||||
if (action.override !== undefined) {
|
||||
overrideRemove.push(...action.override)
|
||||
}
|
||||
if (action.query !== undefined) {
|
||||
const r = matchQuery([doc], action.query, doc._class, hierarchy)
|
||||
if (r.length === 0) {
|
||||
@ -161,6 +158,9 @@ export function filterActions (
|
||||
(hierarchy.isDerived(doc._class, action.target) && client.getHierarchy().isDerived(action.target, derived)) ||
|
||||
(hierarchy.isMixin(action.target) && hierarchy.hasMixin(doc, action.target))
|
||||
) {
|
||||
if (action.override !== undefined) {
|
||||
overrideRemove.push(...action.override)
|
||||
}
|
||||
result.push(action)
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,9 @@
|
||||
})
|
||||
|
||||
let lastKey: KeyboardEvent | undefined
|
||||
let sequences: Action<Doc, Record<string, any>>[] = []
|
||||
let delayedAction: (() => Promise<void>) | undefined
|
||||
let timer: number | undefined
|
||||
|
||||
async function getCurrentActions (
|
||||
context: {
|
||||
@ -70,23 +73,39 @@
|
||||
)
|
||||
}
|
||||
function m (s1: string, s2: string): boolean {
|
||||
return s1 === s2.toLowerCase()
|
||||
return s1 === s2
|
||||
}
|
||||
function matchKey (key: KeyboardEvent, pattern: string, lastKey?: KeyboardEvent): boolean {
|
||||
|
||||
function findKeySequence (pattern: string, key: KeyboardEvent): boolean {
|
||||
const lc = pattern.toLowerCase()
|
||||
const pfp = (keyPrefix(key) + key.key).toLowerCase()
|
||||
const pfp2 = (keyPrefix(key) + key.code).toLowerCase()
|
||||
return lc.startsWith(`${pfp}->`) || lc.startsWith(`${pfp2}->`)
|
||||
}
|
||||
|
||||
function getSequences (
|
||||
key: KeyboardEvent,
|
||||
currentActions: Action<Doc, Record<string, any>>[]
|
||||
): Action<Doc, Record<string, any>>[] {
|
||||
const res = currentActions.filter((p) => p.keyBinding?.find((p) => findKeySequence(p, key)))
|
||||
return res
|
||||
}
|
||||
|
||||
function matchKeySequence (key: KeyboardEvent, pattern: string, lastKey: KeyboardEvent): boolean {
|
||||
const fp = (keyPrefix(key) + key.key).toLowerCase()
|
||||
const fp2 = (keyPrefix(key) + key.code).toLowerCase()
|
||||
const lc = pattern.toLowerCase()
|
||||
if (m(fp, lc) || m(fp2, lc)) {
|
||||
return true
|
||||
}
|
||||
if (lastKey !== undefined) {
|
||||
// Check with last key
|
||||
const pfp = (keyPrefix(key) + lastKey.key).toLowerCase()
|
||||
const pfp2 = (keyPrefix(key) + lastKey.code).toLowerCase()
|
||||
const pfp = (keyPrefix(lastKey) + lastKey.key).toLowerCase()
|
||||
const pfp2 = (keyPrefix(lastKey) + lastKey.code).toLowerCase()
|
||||
|
||||
return m(`${pfp}->${fp}`, lc) || m(`${pfp2}->${fp}`, lc) || m(`${pfp}->${fp2}`, lc) || m(`${pfp2}->${fp2}`, lc)
|
||||
}
|
||||
return false
|
||||
return m(`${pfp}->${fp}`, lc) || m(`${pfp2}->${fp}`, lc) || m(`${pfp}->${fp2}`, lc) || m(`${pfp2}->${fp2}`, lc)
|
||||
}
|
||||
|
||||
function matchKey (key: KeyboardEvent, pattern: string): boolean {
|
||||
const fp = (keyPrefix(key) + key.key).toLowerCase()
|
||||
const fp2 = (keyPrefix(key) + key.code).toLowerCase()
|
||||
const lc = pattern.toLowerCase()
|
||||
return m(fp, lc) || m(fp2, lc)
|
||||
}
|
||||
|
||||
async function handleKeys (evt: KeyboardEvent): Promise<void> {
|
||||
@ -114,6 +133,7 @@
|
||||
if (ctx.mode === 'none') {
|
||||
return
|
||||
}
|
||||
clearTimeout(timer)
|
||||
|
||||
const docs = getSelection($focusStore, $selectionStore)
|
||||
|
||||
@ -121,22 +141,56 @@
|
||||
// Retrieve actual list of actions for input context
|
||||
currentActions = await getContextActions(client, docs, { ...ctx, mode: 'input' })
|
||||
}
|
||||
for (const a of currentActions) {
|
||||
// TODO: Handle multiple keys here
|
||||
if (a.keyBinding?.find((it) => matchKey(evt, it, lastKey)) !== undefined) {
|
||||
lastKey = undefined
|
||||
const action = await getResource(a.action)
|
||||
if (action !== undefined) {
|
||||
await action($focusStore.focus, evt, a.actionProps)
|
||||
currentActions = currentActions.filter((p) => p.keyBinding !== undefined && p.keyBinding.length > 0)
|
||||
if (lastKey !== undefined) {
|
||||
for (const a of sequences) {
|
||||
// TODO: Handle multiple keys here
|
||||
if (a.keyBinding?.find((it) => (lastKey ? matchKeySequence(evt, it, lastKey) : false)) !== undefined) {
|
||||
const action = await getResource(a.action)
|
||||
if (action !== undefined) {
|
||||
sequences = []
|
||||
lastKey = undefined
|
||||
delayedAction = undefined
|
||||
return await action(docs, evt, a.actionProps)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sequences = getSequences(evt, currentActions)
|
||||
let found = false
|
||||
for (const a of currentActions) {
|
||||
// TODO: Handle multiple keys here
|
||||
if (a.keyBinding?.find((it) => matchKey(evt, it)) !== undefined) {
|
||||
const action = await getResource(a.action)
|
||||
if (action !== undefined) {
|
||||
if (sequences.length === 0) {
|
||||
lastKey = undefined
|
||||
sequences = []
|
||||
delayedAction = undefined
|
||||
return await action(docs, evt, a.actionProps)
|
||||
} else {
|
||||
delayedAction = async () => await action(docs, evt, a.actionProps)
|
||||
found = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found && delayedAction) {
|
||||
delayedAction()
|
||||
delayedAction = undefined
|
||||
}
|
||||
|
||||
lastKey = evt
|
||||
|
||||
setTimeout(() => {
|
||||
timer = setTimeout(() => {
|
||||
lastKey = undefined
|
||||
}, 500)
|
||||
sequences = []
|
||||
if (delayedAction !== undefined) {
|
||||
delayedAction()
|
||||
delayedAction = undefined
|
||||
}
|
||||
}, 300)
|
||||
}
|
||||
|
||||
let presenter: AnyComponent | undefined
|
||||
|
@ -147,11 +147,6 @@
|
||||
key.stopPropagation()
|
||||
handleSelection(key, selection)
|
||||
}
|
||||
if (key.code === 'Escape') {
|
||||
key.preventDefault()
|
||||
key.stopPropagation()
|
||||
closePopup()
|
||||
}
|
||||
}
|
||||
function formatKey (key: string): string[][] {
|
||||
const thens = key.split('->')
|
||||
|
@ -33,6 +33,7 @@
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
const changeStatus = async (newStatus: any) => {
|
||||
console.log('CHANGE VALUE', newStatus)
|
||||
if (newStatus === '#null') {
|
||||
newStatus = null
|
||||
return
|
||||
@ -118,7 +119,10 @@
|
||||
{#if values}
|
||||
<SelectPopup
|
||||
value={valuesToShow}
|
||||
on:close={(evt) => changeStatus(evt.detail)}
|
||||
on:close={(evt) => {
|
||||
console.log(evt)
|
||||
changeStatus(evt.detail)
|
||||
}}
|
||||
placeholder={placeholder ?? view.string.Filter}
|
||||
searchable
|
||||
{width}
|
||||
@ -133,7 +137,10 @@
|
||||
{searchField}
|
||||
allowDeselect={true}
|
||||
selected={current}
|
||||
on:close={(evt) => changeStatus(evt.detail === null ? null : evt.detail?._id)}
|
||||
on:close={(evt) => {
|
||||
console.log(evt)
|
||||
changeStatus(evt.detail === null ? null : evt.detail?._id)
|
||||
}}
|
||||
placeholder={placeholder ?? view.string.Filter}
|
||||
{width}
|
||||
{size}
|
||||
|
Loading…
Reference in New Issue
Block a user