Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@

import { createEventDispatcher, onDestroy } from 'svelte'
import { generateIssueShortLink, getIssueIdByIdentifier } from '../../../issues'
import { canEditIssue } from '../../../utils'
import tracker from '../../../plugin'
import IssueStatusActivity from '../IssueStatusActivity.svelte'
import ControlPanel from './ControlPanel.svelte'
Expand All @@ -72,6 +73,18 @@
let descriptionBox: AttachmentStyleBoxCollabEditor
let showAllMixins: boolean

let effectiveReadonly = true
$: if (issue !== undefined) {
const currentIssue = issue
void canEditIssue(currentIssue).then((canEdit) => {
if (issue === currentIssue) {
effectiveReadonly = readonly || !canEdit
}
})
} else {
effectiveReadonly = readonly
}

const inboxClient = InboxNotificationsClientImpl.getClient()

let issueId: Ref<Issue> | undefined
Expand Down Expand Up @@ -198,7 +211,7 @@
<Panel
object={issue}
isHeader={false}
withoutInput={readonly}
withoutInput={effectiveReadonly}
allowClose={!embedded}
isAside={true}
isSub={false}
Expand Down Expand Up @@ -233,25 +246,25 @@
{/if}
<ComponentExtensions
extension={tracker.extensions.EditIssueTitle}
props={{ size: 'medium', kind: 'ghost', space: issue.space, value: issue, readonly }}
props={{ size: 'medium', kind: 'ghost', space: issue.space, value: issue, readonly: effectiveReadonly }}
/>
</svelte:fragment>
<svelte:fragment slot="pre-utils">
<ComponentExtensions
extension={view.extensions.EditDocTitleExtension}
props={{ size: 'medium', kind: 'ghost', _id, _class, value: issue, readonly }}
props={{ size: 'medium', kind: 'ghost', _id, _class, value: issue, readonly: effectiveReadonly }}
/>
<ComponentExtensions
extension={tracker.extensions.EditIssueHeader}
props={{ size: 'medium', kind: 'ghost', space: issue.space, readonly, value: issue }}
props={{ size: 'medium', kind: 'ghost', space: issue.space, readonly: effectiveReadonly, value: issue }}
/>
{#if saved}
<Label label={presentation.string.Saved} />
{/if}
</svelte:fragment>

<svelte:fragment slot="utils">
{#if !readonly}
{#if !effectiveReadonly}
<Button
icon={IconMoreH}
iconProps={{ size: 'medium' }}
Expand Down Expand Up @@ -294,7 +307,7 @@
{#if hasParentIssue}
<div class="mb-6 flex-row-center">
<SubIssueSelector {issue} />
{#if !readonly}
{#if !effectiveReadonly}
<div class="ml-2">
<Button
icon={tracker.icon.UnsetParent}
Expand All @@ -313,7 +326,7 @@
<EditBox
focusIndex={1}
bind:value={title}
disabled={readonly}
disabled={effectiveReadonly}
placeholder={tracker.string.IssueTitlePlaceholder}
kind="large-style"
on:blur={save}
Expand All @@ -322,7 +335,7 @@
<AttachmentStyleBoxCollabEditor
focusIndex={30}
object={issue}
{readonly}
readonly={effectiveReadonly}
key={{ key: 'description', attr: descriptionKey }}
bind:this={descriptionBox}
identifier={issue?.identifier}
Expand All @@ -339,11 +352,14 @@
{/key}
</div>

<RelationsEditor object={issue} {readonly} />
<RelationsEditor object={issue} readonly={effectiveReadonly} />

{#if editorFooter}
<div class="step-tb-6">
<Component is={editorFooter.footer} props={{ object: issue, _class, ...editorFooter.props, readonly }} />
<Component
is={editorFooter.footer}
props={{ object: issue, _class, ...editorFooter.props, readonly: effectiveReadonly }}
/>
</div>
{/if}

Expand All @@ -354,7 +370,7 @@
<svelte:fragment slot="custom-attributes">
{#if issue !== undefined}
<div class="space-divider" />
<ControlPanel {issue} {showAllMixins} {readonly} />
<ControlPanel {issue} {showAllMixins} readonly={effectiveReadonly} />
{/if}

<div class="popupPanel-body__aside-grid">
Expand Down
29 changes: 28 additions & 1 deletion plugins/tracker-resources/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import { Analytics } from '@hcengineering/analytics'
import { type Person } from '@hcengineering/contact'
import core, {
AccountRole,
SortingOrder,
toIdMap,
type ApplyOperations,
Expand All @@ -33,7 +34,9 @@ import core, {
type TxCreateDoc,
type TxOperations,
type TxResult,
type TxUpdateDoc
type TxUpdateDoc,
getCurrentAccount,
type WithLookup
} from '@hcengineering/core'
import { type IntlString } from '@hcengineering/platform'
import { createQuery, getClient, onClient } from '@hcengineering/presentation'
Expand Down Expand Up @@ -274,6 +277,30 @@ export async function moveIssuesToAnotherMilestone (
}
}

export async function canEditIssue (issue?: Issue | WithLookup<Issue>): Promise<boolean> {
const client = getClient()
if (issue === undefined) return false

const account = getCurrentAccount()
const isGuest =
account.role === AccountRole.Guest ||
account.role === AccountRole.DocGuest ||
account.role === AccountRole.ReadOnlyGuest

if (!isGuest) return true

const isCreator =
issue.createdBy !== undefined && Array.isArray(account.socialIds) && account.socialIds.includes(issue.createdBy)

if (isCreator) return true

const collaborator = await client.findOne(core.class.Collaborator, {
attachedTo: issue._id,
collaborator: account.uuid
})
return collaborator !== undefined
}

export function getTimeReportDate (type: TimeReportDayType): number {
const date = new Date(Date.now())

Expand Down
Loading