Skip to content

Commit

Permalink
EZQMS-1109: Add signature details for reviews/approvals (#6111)
Browse files Browse the repository at this point in the history
* ezqms-1109: add signature details for reviews/approvals
Signed-off-by: Alexey Zinoviev <alexey.zinoviev@xored.com>
  • Loading branch information
lexiv0re authored Jul 23, 2024
1 parent 93b798c commit 8163a30
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
-->
<script lang="ts">
import { Ref, SortingOrder } from '@hcengineering/core'
import { Label, Scroller, getUserTimezone } from '@hcengineering/ui'
import { Label, Scroller } from '@hcengineering/ui'
import { createQuery } from '@hcengineering/presentation'
import documents, { DocumentApprovalRequest, DocumentReviewRequest } from '@hcengineering/controlled-documents'
import { employeeByIdStore, personAccountByIdStore } from '@hcengineering/contact-resources'
Expand All @@ -23,6 +23,7 @@
import documentsRes from '../../plugin'
import { $controlledDocument as controlledDocument } from '../../stores/editors/document/editor'
import { formatSignatureDate } from '../../utils'
interface Signer {
id?: Ref<Person>
Expand All @@ -38,7 +39,6 @@
const reviewQuery = createQuery()
const approvalQuery = createQuery()
const timeZone: string = getUserTimezone()
$: if ($controlledDocument !== undefined) {
reviewQuery.query(
Expand Down Expand Up @@ -92,7 +92,7 @@
id: $controlledDocument.author,
role: 'author',
name: getNameByEmployeeId($controlledDocument.author),
date: $controlledDocument.createdOn !== undefined ? formatDate($controlledDocument.createdOn) : ''
date: $controlledDocument.createdOn !== undefined ? formatSignatureDate($controlledDocument.createdOn) : ''
}
]
Expand All @@ -105,7 +105,7 @@
id: rAcc?.person,
role: 'reviewer',
name: getNameByEmployeeId(rAcc?.person),
date: formatDate(date ?? reviewRequest.modifiedOn)
date: formatSignatureDate(date ?? reviewRequest.modifiedOn)
})
})
}
Expand All @@ -119,25 +119,12 @@
id: aAcc?.person,
role: 'approver',
name: getNameByEmployeeId(aAcc?.person),
date: formatDate(date ?? approvalRequest.modifiedOn)
date: formatSignatureDate(date ?? approvalRequest.modifiedOn)
})
})
}
}
function formatDate (date: number): string {
return new Date(date).toLocaleDateString('default', {
year: 'numeric',
month: 'short',
day: 'numeric',
timeZone,
timeZoneName: 'short',
hour: 'numeric',
minute: 'numeric',
second: 'numeric'
})
}
function getSignerLabel (role: 'author' | 'reviewer' | 'approver'): IntlString {
switch (role) {
case 'author':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,28 @@
import { slide } from 'svelte/transition'
import documents, { DocumentRequest } from '@hcengineering/controlled-documents'
import chunter from '@hcengineering/chunter'
import { PersonAccount } from '@hcengineering/contact'
import { PersonAccountRefPresenter } from '@hcengineering/contact-resources'
import { type Person, type PersonAccount } from '@hcengineering/contact'
import { PersonAccountRefPresenter, personAccountByIdStore } from '@hcengineering/contact-resources'
import { Ref } from '@hcengineering/core'
import { getClient } from '@hcengineering/presentation'
import { Chevron, Label } from '@hcengineering/ui'
import { Chevron, Label, tooltip } from '@hcengineering/ui'
import { $documentSnapshots as documentSnapshots } from '../../../stores/editors/document'
import documentsRes from '../../../plugin'
import ApprovedIcon from '../../icons/Approved.svelte'
import RejectedIcon from '../../icons/Rejected.svelte'
import CancelledIcon from '../../icons/Cancelled.svelte'
import WaitingIcon from '../../icons/Waiting.svelte'
import SignatureInfo from './SignatureInfo.svelte'
export let request: DocumentRequest
export let initiallyExpanded: boolean = false
interface PersonalApproval {
account: Ref<PersonAccount>
person?: Ref<Person>
approved: 'approved' | 'rejected' | 'cancelled' | 'waiting'
timestamp?: number
}
const client = getClient()
Expand All @@ -31,45 +34,53 @@
let rejectingMessage: string | undefined
let approvals: PersonalApproval[] = []
$: if (request != null) {
void getRequestData()
}
$: void getRequestData(request)
$: type = hierarchy.isDerived(request._class, documents.class.DocumentApprovalRequest)
? documents.string.Approval
: documents.string.Review
async function getRequestData (): Promise<void> {
if (request !== undefined) {
approvals = await getApprovals(request)
const rejectingComment = await client.findOne(chunter.class.ChatMessage, {
attachedTo: request?._id,
attachedToClass: request?._class
})
rejectingMessage = rejectingComment?.message
async function getRequestData (req: DocumentRequest): Promise<void> {
if (req == null) {
return
}
approvals = await getApprovals(req, $personAccountByIdStore)
const rejectingComment = await client.findOne(chunter.class.ChatMessage, {
attachedTo: req?._id,
attachedToClass: req?._class
})
rejectingMessage = rejectingComment?.message
}
async function getApprovals (req: DocumentRequest): Promise<PersonalApproval[]> {
async function getApprovals (
req: DocumentRequest,
accountById: typeof $personAccountByIdStore
): Promise<PersonalApproval[]> {
const rejectedBy: PersonalApproval[] =
req.rejected !== undefined
? [
{
account: req.rejected,
approved: 'rejected'
person: accountById.get(req.rejected)?.person,
approved: 'rejected',
timestamp: req.modifiedOn
}
]
: []
const approvedBy: PersonalApproval[] = req.approved.map((id) => ({
const approvedBy: PersonalApproval[] = req.approved.map((id, idx) => ({
account: id,
approved: 'approved'
person: accountById.get(id)?.person,
approved: 'approved',
timestamp: req.approvedDates?.[idx] ?? req.modifiedOn
}))
const ignoredBy = req.requested
.filter((p) => p !== req?.rejected)
.filter((p) => !(req?.approved as string[]).includes(p))
.map(
(id): PersonalApproval => ({
account: id,
person: accountById.get(id)?.person,
approved: req?.rejected !== undefined ? 'cancelled' : 'waiting'
})
)
Expand Down Expand Up @@ -115,15 +126,30 @@
{#each approvals as approver}
<div class="approver">
<PersonAccountRefPresenter value={approver.account} avatarSize="x-small" />
{#if approver.approved === 'approved'}
<ApprovedIcon size="medium" fill={'var(--theme-docs-accepted-color)'} />
{:else if approver.approved === 'rejected'}
<RejectedIcon size="medium" fill={'var(--negative-button-default)'} />
{:else if approver.approved === 'cancelled'}
<CancelledIcon size="medium" />
{:else if approver.approved === 'waiting'}
<WaitingIcon size="medium" />
{/if}
{#key approver.timestamp}
<!-- For some reason tooltip is not interactive w/o remount -->
<span
use:tooltip={approver.timestamp !== undefined
? {
component: SignatureInfo,
props: {
id: approver.person,
timestamp: approver.timestamp
}
}
: undefined}
>
{#if approver.approved === 'approved'}
<ApprovedIcon size="medium" fill={'var(--theme-docs-accepted-color)'} />
{:else if approver.approved === 'rejected'}
<RejectedIcon size="medium" fill={'var(--negative-button-default)'} />
{:else if approver.approved === 'cancelled'}
<CancelledIcon size="medium" />
{:else if approver.approved === 'waiting'}
<WaitingIcon size="medium" />
{/if}
</span>
{/key}
</div>
{#if rejectingMessage !== undefined && approver.approved === 'rejected'}
<div class="reject-message">{@html rejectingMessage}</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<!--
// Copyright © 2020, 2021 Anticrm Platform Contributors.
// Copyright © 2022, 2023, 2024 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
-->
<script lang="ts">
import { formatSignatureDate } from '../../../utils'
export let id: string
export let timestamp: number
</script>

<div>ID: {id}</div>
<div>{formatSignatureDate(timestamp)}</div>
17 changes: 16 additions & 1 deletion plugins/controlled-documents-resources/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import contact, { type Employee, type PersonAccount } from '@hcengineering/conta
import request, { RequestStatus } from '@hcengineering/request'
import textEditor from '@hcengineering/text-editor'
import { isEmptyMarkup } from '@hcengineering/text'
import { getEventPositionElement, showPopup, type Location } from '@hcengineering/ui'
import { getEventPositionElement, showPopup, getUserTimezone, type Location } from '@hcengineering/ui'
import { type KeyFilter } from '@hcengineering/view'
import chunter from '@hcengineering/chunter'
import documents, {
Expand Down Expand Up @@ -835,3 +835,18 @@ export async function createTemplate (space: OrgSpace): Promise<void> {
wizardOpened({ $$currentStep: 'info', location: { space: space._id, project: project ?? documents.ids.NoProject } })
showPopup(documents.component.QmsTemplateWizard, {})
}

export function formatSignatureDate (date: number): string {
const timeZone: string = getUserTimezone()

return new Date(date).toLocaleDateString('default', {
year: 'numeric',
month: 'short',
day: 'numeric',
timeZone,
timeZoneName: 'short',
hour: 'numeric',
minute: 'numeric',
second: 'numeric'
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export class DocumentApprovalsPage extends DocumentCommonPage {
}

async checkSuccessApproval (approvalName: string): Promise<void> {
await expect(this.page.locator('svg[fill*="accepted"]').locator('xpath=..').locator('span.ap-label')).toHaveText(
await expect(this.page.locator('svg[fill*="accepted"]').locator('xpath=../..').locator('span.ap-label')).toHaveText(
approvalName
)
}
Expand Down

0 comments on commit 8163a30

Please sign in to comment.