mirror of
https://github.com/hcengineering/platform.git
synced 2026-09-07 02:07:43 +02:00
UBERF-5603 (#4754)
Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
@@ -39,6 +39,7 @@
|
||||
export let shouldShowName = true
|
||||
export let shrink: number = 0
|
||||
export let isAction: boolean = false
|
||||
export let readonly: boolean = false
|
||||
|
||||
$: _object =
|
||||
(typeof object !== 'string' ? object : undefined) ?? (typeof value !== 'string' ? value : undefined) ?? []
|
||||
@@ -186,6 +187,7 @@
|
||||
{width}
|
||||
{short}
|
||||
{shrink}
|
||||
{readonly}
|
||||
{shouldShowName}
|
||||
showNavigate={false}
|
||||
justify={'left'}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
export let value: WithLookup<Issue>
|
||||
export let width: string | undefined = undefined
|
||||
export let editable: boolean = true
|
||||
|
||||
const client = getClient()
|
||||
$: shouldIgnoreOverdue =
|
||||
@@ -49,7 +50,7 @@
|
||||
kind={'link'}
|
||||
value={value.dueDate}
|
||||
{width}
|
||||
editable
|
||||
{editable}
|
||||
onChange={(e) => handleDueDateChanged(e)}
|
||||
{shouldIgnoreOverdue}
|
||||
/>
|
||||
|
||||
@@ -52,7 +52,15 @@
|
||||
{/if}
|
||||
{:else if value}
|
||||
<div class="flex-row-center">
|
||||
<DocNavLink object={value} {onClick} {disabled} {noUnderline} component={tracker.component.EditIssue} shrink={0}>
|
||||
<DocNavLink
|
||||
object={value}
|
||||
{onClick}
|
||||
{disabled}
|
||||
{noUnderline}
|
||||
{inline}
|
||||
component={tracker.component.EditIssue}
|
||||
shrink={0}
|
||||
>
|
||||
<span class="issuePresenterRoot" class:list={kind === 'list'} class:cursor-pointer={!disabled}>
|
||||
{#if shouldShowAvatar}
|
||||
<div class="icon" use:tooltip={{ label: tracker.string.Issue }}>
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
openDoc,
|
||||
SelectDirection,
|
||||
setGroupByValues,
|
||||
showMenu,
|
||||
statusStore
|
||||
} from '@hcengineering/view-resources'
|
||||
import { ChatMessagesPresenter } from '@hcengineering/chunter-resources'
|
||||
@@ -138,10 +139,6 @@
|
||||
;(document.activeElement as HTMLElement)?.blur()
|
||||
})
|
||||
|
||||
const showMenu = async (ev: MouseEvent, items: Doc[]): Promise<void> => {
|
||||
ev.preventDefault()
|
||||
showPopup(Menu, { object: items, baseMenuClass }, getEventPositionElement(ev))
|
||||
}
|
||||
// Category information only
|
||||
let tasks: DocWithRank[] = []
|
||||
|
||||
@@ -337,7 +334,9 @@
|
||||
on:check={(evt) => {
|
||||
listProvider.updateSelection(evt.detail.docs, evt.detail.value)
|
||||
}}
|
||||
on:contextmenu={(evt) => showMenu(evt.detail.evt, evt.detail.objects)}
|
||||
on:contextmenu={(evt) => {
|
||||
showMenu(evt.detail.evt, { object: evt.detail.objects, baseMenuClass })
|
||||
}}
|
||||
>
|
||||
<svelte:fragment slot="header" let:state let:count let:index>
|
||||
{@const color = accentColors.get(`${index}${$themeStore.dark}${groupByKey}`)}
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
export let value: Issue
|
||||
export let type: 'isBlocking' | 'blockedBy' | 'relations'
|
||||
export let blockedBy: Doc[] | undefined = undefined
|
||||
export let disabled: boolean = false
|
||||
export let readonly: boolean = false
|
||||
|
||||
$: valueGroup = (type === 'isBlocking' ? blockedBy ?? [] : value[type] ?? []).reduce<
|
||||
Map<Ref<Class<Doc>>, Ref<Doc>[]>
|
||||
@@ -25,7 +27,7 @@
|
||||
{#each classes as classCategory}
|
||||
{@const vals = valueGroup.get(classCategory)}
|
||||
{#if vals}
|
||||
<RelationEditorPart {value} _class={classCategory} documentIds={vals} {type} />
|
||||
<RelationEditorPart {value} _class={classCategory} documentIds={vals} {type} {disabled} {readonly} />
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
export let _class: Ref<Class<Doc>>
|
||||
export let documentIds: Ref<Doc>[]
|
||||
export let type: 'isBlocking' | 'blockedBy' | 'relations'
|
||||
export let disabled: boolean = false
|
||||
export let readonly: boolean = false
|
||||
|
||||
const client = getClient()
|
||||
const issuesQuery = createQuery()
|
||||
@@ -29,6 +31,7 @@
|
||||
})
|
||||
|
||||
async function handleClick (issue: RelatedDocument) {
|
||||
if (readonly || disabled) return
|
||||
const prop = type === 'isBlocking' ? 'blockedBy' : type
|
||||
const isBlockingValue = await client.findAll(value._class, { 'blockedBy._id': value._id })
|
||||
|
||||
@@ -67,6 +70,7 @@
|
||||
}
|
||||
|
||||
async function handleRedirect (issue: Issue) {
|
||||
if (disabled) return
|
||||
const loc = await issueLinkFragmentProvider(issue)
|
||||
navigate(loc)
|
||||
}
|
||||
@@ -80,13 +84,15 @@
|
||||
<div class="tag-container">
|
||||
<Icon {icon} size={'small'} />
|
||||
<div class="flex-grow">
|
||||
<button on:click|stopPropagation={() => handleRedirect(issue)}>
|
||||
<button {disabled} on:click|stopPropagation={() => handleRedirect(issue)}>
|
||||
<span class="overflow-label ml-1-5 content-color">{issue.identifier}</span>
|
||||
</button>
|
||||
</div>
|
||||
<button class="btn-close" on:click|stopPropagation={() => handleClick(issue)}>
|
||||
<Icon icon={IconClose} size={'x-small'} />
|
||||
</button>
|
||||
{#if !readonly}
|
||||
<button class="btn-close" on:click|stopPropagation={() => handleClick(issue)}>
|
||||
<Icon icon={IconClose} size={'x-small'} />
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
<div class="tag-container between">
|
||||
@@ -94,9 +100,11 @@
|
||||
is={view.component.ObjectPresenter}
|
||||
props={{ objectId: doc._id, _class: doc._class, value: doc, noUnderline: true, props: { avatarSize: 'card' } }}
|
||||
/>
|
||||
<button class="btn-close" on:click|stopPropagation={() => handleClick(doc)}>
|
||||
<Icon icon={IconClose} size={'x-small'} />
|
||||
</button>
|
||||
{#if !readonly}
|
||||
<button class="btn-close" on:click|stopPropagation={() => handleClick(doc)}>
|
||||
<Icon icon={IconClose} size={'x-small'} />
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
|
||||
@@ -53,16 +53,6 @@
|
||||
align-items: center;
|
||||
flex-shrink: 1;
|
||||
min-width: 1rem;
|
||||
|
||||
&.list {
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
&:active {
|
||||
color: var(--theme-content-color);
|
||||
}
|
||||
}
|
||||
|
||||
.with-margin {
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
import tags from '@hcengineering/tags'
|
||||
import type { Issue } from '@hcengineering/tracker'
|
||||
import { Component, Label } from '@hcengineering/ui'
|
||||
import { getFiltredKeys, isCollectionAttr, ObjectBox } from '@hcengineering/view-resources'
|
||||
import { getFiltredKeys, isCollectionAttr, ObjectBox, restrictionStore } from '@hcengineering/view-resources'
|
||||
import tracker from '../../../plugin'
|
||||
import ComponentEditor from '../../components/ComponentEditor.svelte'
|
||||
import MilestoneEditor from '../../milestones/MilestoneEditor.svelte'
|
||||
@@ -33,6 +33,7 @@
|
||||
|
||||
export let issue: Issue
|
||||
export let showAllMixins: boolean = false
|
||||
export let readonly = false
|
||||
|
||||
const query = createQuery()
|
||||
let showIsBlocking = false
|
||||
@@ -125,31 +126,37 @@
|
||||
<Label label={tracker.string.Status} />
|
||||
</span>
|
||||
|
||||
<StatusEditor value={issue} size={'medium'} iconSize={'small'} shouldShowLabel />
|
||||
<StatusEditor value={issue} size={'medium'} iconSize={'small'} shouldShowLabel isEditable={!readonly} />
|
||||
|
||||
{#if issue.blockedBy?.length}
|
||||
<span class="labelTop">
|
||||
<Label label={tracker.string.BlockedBy} />
|
||||
</span>
|
||||
<RelationEditor value={issue} type="blockedBy" />
|
||||
<RelationEditor value={issue} type="blockedBy" {readonly} disabled={$restrictionStore.disableNavigation} />
|
||||
{/if}
|
||||
{#if showIsBlocking}
|
||||
<span class="labelTop">
|
||||
<Label label={tracker.string.Blocks} />
|
||||
</span>
|
||||
<RelationEditor value={issue} type="isBlocking" {blockedBy} />
|
||||
<RelationEditor
|
||||
value={issue}
|
||||
type="isBlocking"
|
||||
{blockedBy}
|
||||
{readonly}
|
||||
disabled={$restrictionStore.disableNavigation}
|
||||
/>
|
||||
{/if}
|
||||
{#if issue.relations?.length}
|
||||
<span class="labelTop">
|
||||
<Label label={tracker.string.Related} />
|
||||
</span>
|
||||
<RelationEditor value={issue} type="relations" />
|
||||
<RelationEditor value={issue} type="relations" {readonly} disabled={$restrictionStore.disableNavigation} />
|
||||
{/if}
|
||||
|
||||
<span class="labelOnPanel">
|
||||
<Label label={tracker.string.Priority} />
|
||||
</span>
|
||||
<PriorityEditor value={issue} size={'medium'} shouldShowLabel />
|
||||
<PriorityEditor value={issue} size={'medium'} shouldShowLabel isEditable={!readonly} />
|
||||
|
||||
<span class="labelOnPanel">
|
||||
<Label label={core.string.CreatedBy} />
|
||||
@@ -168,24 +175,27 @@
|
||||
<span class="labelOnPanel">
|
||||
<Label label={tracker.string.Assignee} />
|
||||
</span>
|
||||
<AssigneeEditor object={issue} size={'medium'} avatarSize={'card'} width="100%" />
|
||||
<AssigneeEditor object={issue} size={'medium'} avatarSize={'card'} width="100%" {readonly} />
|
||||
|
||||
<span class="labelTop">
|
||||
<Label label={tracker.string.Labels} />
|
||||
</span>
|
||||
<Component is={tags.component.TagsAttributeEditor} props={{ object: issue, label: tracker.string.AddLabel }} />
|
||||
<Component
|
||||
is={tags.component.TagsAttributeEditor}
|
||||
props={{ object: issue, label: tracker.string.AddLabel, readonly }}
|
||||
/>
|
||||
|
||||
<div class="divider" />
|
||||
|
||||
<span class="labelOnPanel">
|
||||
<Label label={tracker.string.Component} />
|
||||
</span>
|
||||
<ComponentEditor value={issue} space={issue.space} size={'medium'} />
|
||||
<ComponentEditor value={issue} space={issue.space} size={'medium'} isEditable={!readonly} />
|
||||
|
||||
<span class="labelOnPanel">
|
||||
<Label label={tracker.string.Milestone} />
|
||||
</span>
|
||||
<MilestoneEditor value={issue} space={issue.space} size={'medium'} />
|
||||
<MilestoneEditor value={issue} space={issue.space} size={'medium'} isEditable={!readonly} />
|
||||
|
||||
{#if issue.dueDate !== null}
|
||||
<div class="divider" />
|
||||
@@ -193,13 +203,13 @@
|
||||
<span class="labelOnPanel">
|
||||
<Label label={tracker.string.DueDate} />
|
||||
</span>
|
||||
<DueDateEditor value={issue} width={'100%'} />
|
||||
<DueDateEditor value={issue} width={'100%'} editable={!readonly} />
|
||||
{/if}
|
||||
|
||||
{#if keys.length > 0}
|
||||
<div class="divider" />
|
||||
{#each keys as key (typeof key === 'string' ? key : key.key)}
|
||||
<AttributeBarEditor {key} _class={issue._class} object={issue} showHeader={true} size={'medium'} />
|
||||
<AttributeBarEditor {readonly} {key} _class={issue._class} object={issue} showHeader={true} size={'medium'} />
|
||||
{/each}
|
||||
{/if}
|
||||
|
||||
@@ -211,6 +221,7 @@
|
||||
<AttributeBarEditor
|
||||
{key}
|
||||
_class={mixin._id}
|
||||
{readonly}
|
||||
object={hierarchy.as(issue, mixin._id)}
|
||||
showHeader={true}
|
||||
size={'medium'}
|
||||
|
||||
@@ -40,11 +40,10 @@
|
||||
Spinner,
|
||||
createFocusManager,
|
||||
getCurrentResolvedLocation,
|
||||
navigate,
|
||||
showPopup
|
||||
navigate
|
||||
} from '@hcengineering/ui'
|
||||
import view from '@hcengineering/view'
|
||||
import { ContextMenu, DocNavLink, ParentsNavigator } from '@hcengineering/view-resources'
|
||||
import { DocNavLink, ParentsNavigator, showMenu } from '@hcengineering/view-resources'
|
||||
import { createEventDispatcher, onDestroy } from 'svelte'
|
||||
import { generateIssueShortLink } from '../../../issues'
|
||||
import tracker from '../../../plugin'
|
||||
@@ -58,6 +57,7 @@
|
||||
export let _class: Ref<Class<Issue>>
|
||||
export let embedded: boolean = false
|
||||
export let kind: 'default' | 'modern' = 'default'
|
||||
export let readonly: boolean = false
|
||||
|
||||
let lastId: Ref<Doc> = _id
|
||||
const queryClient = createQuery()
|
||||
@@ -121,13 +121,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
function showMenu (ev?: Event): void {
|
||||
function showContextMenu (ev: MouseEvent): void {
|
||||
if (issue !== undefined) {
|
||||
showPopup(
|
||||
ContextMenu,
|
||||
{ object: issue, excludedActions: [view.action.Open] },
|
||||
(ev as MouseEvent).target as HTMLElement
|
||||
)
|
||||
showMenu(ev, { object: issue, excludedActions: [view.action.Open] })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,6 +177,8 @@
|
||||
<Panel
|
||||
object={issue}
|
||||
isHeader={false}
|
||||
withoutInput={readonly}
|
||||
allowClose={!embedded}
|
||||
isAside={true}
|
||||
isSub={false}
|
||||
{embedded}
|
||||
@@ -223,25 +221,27 @@
|
||||
</svelte:fragment>
|
||||
|
||||
<svelte:fragment slot="utils">
|
||||
<Button icon={IconMoreH} iconProps={{ size: 'medium' }} kind={'icon'} on:click={showMenu} />
|
||||
<CopyToClipboard issueUrl={generateIssueShortLink(issue.identifier)} />
|
||||
<Button
|
||||
icon={setting.icon.Setting}
|
||||
kind={'icon'}
|
||||
iconProps={{ size: 'medium' }}
|
||||
showTooltip={{ label: setting.string.ClassSetting }}
|
||||
on:click={(ev) => {
|
||||
ev.stopPropagation()
|
||||
const loc = getCurrentResolvedLocation()
|
||||
loc.path[2] = settingId
|
||||
loc.path[3] = 'setting'
|
||||
loc.path[4] = 'classes'
|
||||
loc.path.length = 5
|
||||
loc.query = { _class }
|
||||
loc.fragment = undefined
|
||||
navigate(loc)
|
||||
}}
|
||||
/>
|
||||
{#if !readonly}
|
||||
<Button icon={IconMoreH} iconProps={{ size: 'medium' }} kind={'icon'} on:click={showContextMenu} />
|
||||
<CopyToClipboard issueUrl={generateIssueShortLink(issue.identifier)} />
|
||||
<Button
|
||||
icon={setting.icon.Setting}
|
||||
kind={'icon'}
|
||||
iconProps={{ size: 'medium' }}
|
||||
showTooltip={{ label: setting.string.ClassSetting }}
|
||||
on:click={(ev) => {
|
||||
ev.stopPropagation()
|
||||
const loc = getCurrentResolvedLocation()
|
||||
loc.path[2] = settingId
|
||||
loc.path[3] = 'setting'
|
||||
loc.path[4] = 'classes'
|
||||
loc.path.length = 5
|
||||
loc.query = { _class }
|
||||
loc.fragment = undefined
|
||||
navigate(loc)
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
<Button
|
||||
icon={IconMixin}
|
||||
iconProps={{ size: 'medium' }}
|
||||
@@ -265,6 +265,7 @@
|
||||
<EditBox
|
||||
focusIndex={1}
|
||||
bind:value={title}
|
||||
disabled={readonly}
|
||||
placeholder={tracker.string.IssueTitlePlaceholder}
|
||||
kind="large-style"
|
||||
on:blur={save}
|
||||
@@ -273,6 +274,7 @@
|
||||
<AttachmentStyleBoxCollabEditor
|
||||
focusIndex={30}
|
||||
object={issue}
|
||||
{readonly}
|
||||
key={{ key: 'description', attr: descriptionKey }}
|
||||
bind:this={descriptionBox}
|
||||
placeholder={tracker.string.IssueDescriptionPlaceholder}
|
||||
@@ -292,7 +294,7 @@
|
||||
|
||||
{#if editorFooter}
|
||||
<div class="step-tb-6">
|
||||
<Component is={editorFooter.footer} props={{ object: issue, _class, ...editorFooter.props }} />
|
||||
<Component is={editorFooter.footer} props={{ object: issue, _class, ...editorFooter.props, readonly }} />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -303,7 +305,7 @@
|
||||
<svelte:fragment slot="custom-attributes">
|
||||
{#if issue !== undefined && currentProject}
|
||||
<div class="space-divider" />
|
||||
<ControlPanel {issue} {showAllMixins} />
|
||||
<ControlPanel {issue} {showAllMixins} {readonly} />
|
||||
{/if}
|
||||
|
||||
<div class="popupPanel-body__aside-grid">
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
import { Issue } from '@hcengineering/tracker'
|
||||
import { Button, Chevron, ExpandCollapse, IconAdd, closeTooltip, resizeObserver, showPopup } from '@hcengineering/ui'
|
||||
import view, { ViewOptions, Viewlet, ViewletPreference } from '@hcengineering/view'
|
||||
import { ViewletsSettingButton } from '@hcengineering/view-resources'
|
||||
import { ViewletsSettingButton, restrictionStore } from '@hcengineering/view-resources'
|
||||
import { afterUpdate } from 'svelte'
|
||||
import tracker from '../../../plugin'
|
||||
import CreateIssue from '../../CreateIssue.svelte'
|
||||
@@ -139,19 +139,21 @@
|
||||
{#if hasSubIssues}
|
||||
<slot name="buttons" />
|
||||
{/if}
|
||||
<Button
|
||||
id="add-sub-issue"
|
||||
icon={IconAdd}
|
||||
label={hasSubIssues ? undefined : createLabel}
|
||||
labelParams={{ subIssues: 0 }}
|
||||
kind={'ghost'}
|
||||
showTooltip={{ label: createLabel, direction: 'bottom' }}
|
||||
on:click={() => {
|
||||
isCollapsed = false
|
||||
closeTooltip()
|
||||
openNewIssueDialog()
|
||||
}}
|
||||
/>
|
||||
{#if !$restrictionStore.readonly}
|
||||
<Button
|
||||
id="add-sub-issue"
|
||||
icon={IconAdd}
|
||||
label={hasSubIssues ? undefined : createLabel}
|
||||
labelParams={{ subIssues: 0 }}
|
||||
kind={'ghost'}
|
||||
showTooltip={{ label: createLabel, direction: 'bottom' }}
|
||||
on:click={() => {
|
||||
isCollapsed = false
|
||||
closeTooltip()
|
||||
openNewIssueDialog()
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{#if hasSubIssues && viewOptions && viewlet}
|
||||
@@ -165,7 +167,7 @@
|
||||
}}
|
||||
>
|
||||
<SubIssueList
|
||||
createItemDialog={CreateIssue}
|
||||
createItemDialog={!$restrictionStore.readonly ? CreateIssue : undefined}
|
||||
createItemLabel={tracker.string.AddIssueTooltip}
|
||||
createItemDialogProps={{ space: object.space, ...createParams, shouldSaveDraft }}
|
||||
focusIndex={focusIndex === -1 ? -1 : focusIndex + 1}
|
||||
|
||||
@@ -30,6 +30,9 @@
|
||||
export let compactMode: boolean = false
|
||||
export let configurations: Record<Ref<Class<Doc>>, Viewlet['config']> = {}
|
||||
export let preference: ViewletPreference[] = []
|
||||
export let createItemDialog: AnySvelteComponent | AnyComponent | undefined = undefined
|
||||
export let createItemLabel: IntlString | undefined = undefined
|
||||
export let createItemDialogProps: Record<string, any> | undefined = undefined
|
||||
|
||||
let list: List
|
||||
|
||||
@@ -62,10 +65,6 @@
|
||||
isFocus: () => focused
|
||||
})
|
||||
|
||||
export let createItemDialog: AnySvelteComponent | AnyComponent | undefined = undefined
|
||||
export let createItemLabel: IntlString | undefined = undefined
|
||||
export let createItemDialogProps: Record<string, any> | undefined = undefined
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
</script>
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<script lang="ts">
|
||||
import { Issue, trackerId } from '@hcengineering/tracker'
|
||||
import { Button, IconScaleFull, Label, closeTooltip, getCurrentResolvedLocation, navigate } from '@hcengineering/ui'
|
||||
import { createFilter, setFilters } from '@hcengineering/view-resources'
|
||||
import { createFilter, restrictionStore, setFilters } from '@hcengineering/view-resources'
|
||||
import tracker from '../../../plugin'
|
||||
import QueryIssuesList from './QueryIssuesList.svelte'
|
||||
|
||||
@@ -44,24 +44,26 @@
|
||||
<Label label={tracker.string.SubIssuesList} params={{ subIssues: size }} />
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="buttons">
|
||||
<Button
|
||||
icon={IconScaleFull}
|
||||
kind={'ghost'}
|
||||
showTooltip={{ label: tracker.string.OpenSubIssues, direction: 'bottom' }}
|
||||
on:click={() => {
|
||||
const filter = createFilter(tracker.class.Issue, 'attachedTo', [issue._id])
|
||||
if (filter !== undefined) {
|
||||
closeTooltip()
|
||||
const loc = getCurrentResolvedLocation()
|
||||
loc.fragment = undefined
|
||||
loc.query = undefined
|
||||
loc.path[2] = trackerId
|
||||
loc.path[3] = issue.space
|
||||
loc.path[4] = 'issues'
|
||||
navigate(loc)
|
||||
setFilters([filter])
|
||||
}
|
||||
}}
|
||||
/>
|
||||
{#if !$restrictionStore.disableNavigation}
|
||||
<Button
|
||||
icon={IconScaleFull}
|
||||
kind={'ghost'}
|
||||
showTooltip={{ label: tracker.string.OpenSubIssues, direction: 'bottom' }}
|
||||
on:click={() => {
|
||||
const filter = createFilter(tracker.class.Issue, 'attachedTo', [issue._id])
|
||||
if (filter !== undefined) {
|
||||
closeTooltip()
|
||||
const loc = getCurrentResolvedLocation()
|
||||
loc.fragment = undefined
|
||||
loc.query = undefined
|
||||
loc.path[2] = trackerId
|
||||
loc.path[3] = issue.space
|
||||
loc.path[4] = 'issues'
|
||||
navigate(loc)
|
||||
setFilters([filter])
|
||||
}
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</QueryIssuesList>
|
||||
|
||||
+4
-10
@@ -16,18 +16,13 @@
|
||||
import contact from '@hcengineering/contact'
|
||||
import { AssigneeBox } from '@hcengineering/contact-resources'
|
||||
import { Issue } from '@hcengineering/tracker'
|
||||
import { ListView, deviceOptionsStore as deviceInfo, getEventPositionElement, showPopup } from '@hcengineering/ui'
|
||||
import { ContextMenu, FixedColumn, ListSelectionProvider } from '@hcengineering/view-resources'
|
||||
import { ListView, deviceOptionsStore as deviceInfo } from '@hcengineering/ui'
|
||||
import { FixedColumn, ListSelectionProvider, showMenu } from '@hcengineering/view-resources'
|
||||
import tracker from '../../../plugin'
|
||||
import { activeProjects } from '../../../utils'
|
||||
import EstimationEditor from './EstimationEditor.svelte'
|
||||
|
||||
export let issues: Issue[]
|
||||
|
||||
function showContextMenu (ev: MouseEvent, object: Issue) {
|
||||
showPopup(ContextMenu, { object }, $deviceInfo.isMobile ? 'top' : getEventPositionElement(ev))
|
||||
}
|
||||
|
||||
const listProvider = new ListSelectionProvider(() => {})
|
||||
$: twoRows = $deviceInfo.twoRows
|
||||
</script>
|
||||
@@ -36,11 +31,10 @@
|
||||
<ListView count={issues.length} addClass={'step-tb-2-accent'}>
|
||||
<svelte:fragment slot="item" let:item>
|
||||
{@const issue = issues[item]}
|
||||
{@const currentProject = $activeProjects.get(issue.space)}
|
||||
<div
|
||||
class="{twoRows ? 'flex-col' : 'flex-between'} p-text-2 clear-mins"
|
||||
on:contextmenu|preventDefault={(ev) => {
|
||||
showContextMenu(ev, issue)
|
||||
on:contextmenu={(ev) => {
|
||||
showMenu(ev, { object: issue })
|
||||
}}
|
||||
on:mouseover={() => {
|
||||
listProvider.updateFocus(issue)
|
||||
|
||||
+1
@@ -48,6 +48,7 @@
|
||||
{size}
|
||||
{justify}
|
||||
{width}
|
||||
disabled={readonly}
|
||||
on:click={(ev) => {
|
||||
if (!shown && !readonly) {
|
||||
showPopup(EditBoxPopup, { value, format: 'number' }, eventToHTMLElement(ev), (res) => {
|
||||
|
||||
+9
-6
@@ -29,6 +29,7 @@
|
||||
export let kind: 'no-border' | 'link' = 'no-border'
|
||||
export let size: 'small' | 'medium' | 'large' = 'large'
|
||||
export let currentProject: Project | undefined
|
||||
export let readonly: boolean = false
|
||||
|
||||
$: if (currentProject === undefined) {
|
||||
currentProject = $activeProjects.get(object.space)
|
||||
@@ -37,6 +38,7 @@
|
||||
$: defaultTimeReportDay = currentProject?.defaultTimeReportDay
|
||||
|
||||
function addTimeReport (event: MouseEvent): void {
|
||||
if (readonly) return
|
||||
showPopup(
|
||||
TimeSpendReportPopup,
|
||||
{
|
||||
@@ -52,6 +54,7 @@
|
||||
)
|
||||
}
|
||||
function showReports (event: MouseEvent): void {
|
||||
if (readonly) return
|
||||
showPopup(ReportsPopup, { issue: object }, eventToHTMLElement(event))
|
||||
}
|
||||
$: childTime = floorFractionDigits(
|
||||
@@ -66,6 +69,7 @@
|
||||
<div
|
||||
id="ReportedTimeEditor"
|
||||
class="link-container antiButton link {size} flex-grow flex-between"
|
||||
class:readonly
|
||||
on:click={showReports}
|
||||
>
|
||||
{#if value !== undefined}
|
||||
@@ -78,9 +82,11 @@
|
||||
{:else}
|
||||
<span class="content-dark-color"><Label label={placeholder} /></span>
|
||||
{/if}
|
||||
<div class="add-action">
|
||||
<ActionIcon icon={IconAdd} size={'small'} action={addTimeReport} />
|
||||
</div>
|
||||
{#if !readonly}
|
||||
<div class="add-action">
|
||||
<ActionIcon icon={IconAdd} size={'small'} action={addTimeReport} />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{:else if value !== undefined}
|
||||
<span class="flex-row-center">
|
||||
@@ -101,9 +107,6 @@
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: var(--theme-bg-color);
|
||||
border-color: var(--theme-divider-color);
|
||||
|
||||
.add-action {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
+3
-8
@@ -22,10 +22,9 @@
|
||||
ListView,
|
||||
deviceOptionsStore as deviceInfo,
|
||||
eventToHTMLElement,
|
||||
getEventPositionElement,
|
||||
showPopup
|
||||
} from '@hcengineering/ui'
|
||||
import { ContextMenu, FixedColumn, ListSelectionProvider } from '@hcengineering/view-resources'
|
||||
import { FixedColumn, ListSelectionProvider, showMenu } from '@hcengineering/view-resources'
|
||||
import tracker from '../../../plugin'
|
||||
import { activeProjects } from '../../../utils'
|
||||
import TimePresenter from './TimePresenter.svelte'
|
||||
@@ -33,10 +32,6 @@
|
||||
|
||||
export let reports: WithLookup<TimeSpendReport>[]
|
||||
|
||||
function showContextMenu (ev: MouseEvent, object: TimeSpendReport) {
|
||||
showPopup(ContextMenu, { object }, getEventPositionElement(ev))
|
||||
}
|
||||
|
||||
const listProvider = new ListSelectionProvider(() => {})
|
||||
|
||||
const toProjectId = (ref: Ref<Space>) => ref as Ref<Project>
|
||||
@@ -70,8 +65,8 @@
|
||||
{@const currentProject = $activeProjects.get(toProjectId(report.space))}
|
||||
<div
|
||||
class="{twoRows ? 'flex-col' : 'flex-between'} p-text-2 clear-mins"
|
||||
on:contextmenu|preventDefault={(ev) => {
|
||||
showContextMenu(ev, report)
|
||||
on:contextmenu={(ev) => {
|
||||
showMenu(ev, { object: report })
|
||||
}}
|
||||
on:mouseenter={() => {
|
||||
listProvider.updateFocus(report)
|
||||
|
||||
@@ -22,9 +22,9 @@
|
||||
import setting, { settingId } from '@hcengineering/setting'
|
||||
import tags from '@hcengineering/tags'
|
||||
import { IssueTemplate, IssueTemplateChild, Project } from '@hcengineering/tracker'
|
||||
import { Button, EditBox, IconMoreH, Label, getCurrentResolvedLocation, navigate, showPopup } from '@hcengineering/ui'
|
||||
import { ContextMenu } from '@hcengineering/view-resources'
|
||||
import { Button, EditBox, IconMoreH, Label, getCurrentResolvedLocation, navigate } from '@hcengineering/ui'
|
||||
import view from '@hcengineering/view'
|
||||
import { showMenu } from '@hcengineering/view-resources'
|
||||
import { createEventDispatcher, onDestroy, onMount } from 'svelte'
|
||||
import tracker from '../../plugin'
|
||||
|
||||
@@ -91,13 +91,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
function showMenu (ev?: Event): void {
|
||||
function showContextMenu (ev: MouseEvent): void {
|
||||
if (template !== undefined) {
|
||||
showPopup(
|
||||
ContextMenu,
|
||||
{ object: template, excludedActions: [view.action.Open] },
|
||||
(ev as MouseEvent).target as HTMLElement
|
||||
)
|
||||
showMenu(ev, { object: template, excludedActions: [view.action.Open] })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,7 +179,7 @@
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="utils">
|
||||
<Button icon={IconMoreH} iconProps={{ size: 'medium' }} kind={'icon'} on:click={showMenu} />
|
||||
<Button icon={IconMoreH} iconProps={{ size: 'medium' }} kind={'icon'} on:click={showContextMenu} />
|
||||
<Button
|
||||
icon={setting.icon.Setting}
|
||||
iconProps={{ size: 'medium' }}
|
||||
|
||||
Reference in New Issue
Block a user