Add date difference calculation functionality (#10673)

* Add date difference calculation functionality

Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>

* Fix

Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>

* Fix formatting

Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>

---------

Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
Denis Bykhov
2026-03-24 00:49:55 +05:00
committed by GitHub
parent 6f14b3d73a
commit 31246a11a0
23 changed files with 258 additions and 44 deletions
@@ -165,8 +165,12 @@
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
<button
bind:this={elements[0]}
on:keydown={(event) => keyDown(event, 0)}
on:mouseover={() => elements[0]?.focus()}
on:keydown={(event) => {
keyDown(event, 0)
}}
on:mouseover={() => {
elements[0]?.focus()
}}
on:click={() => {
onUserRequest()
}}
@@ -183,8 +187,12 @@
{#if func.editor !== undefined}
<Submenu
bind:element={elements[functionsOffset + i]}
on:keydown={(event) => keyDown(event, functionsOffset + i)}
on:mouseover={() => elements[functionsOffset + i]?.focus()}
on:keydown={(event) => {
keyDown(event, functionsOffset + i)
}}
on:mouseover={() => {
elements[functionsOffset + i]?.focus()
}}
label={func.label}
props={{
masterTag,
@@ -199,8 +207,12 @@
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
<button
bind:this={elements[functionsOffset + i]}
on:keydown={(event) => keyDown(event, functionsOffset + i)}
on:mouseover={() => elements[functionsOffset + i]?.focus()}
on:keydown={(event) => {
keyDown(event, functionsOffset + i)
}}
on:mouseover={() => {
elements[functionsOffset + i]?.focus()
}}
on:click={() => {
onFunc(func._id)
}}
@@ -219,8 +231,12 @@
{#if pc.attributes.length > 0}
<Submenu
bind:element={elements[processContextOffset + i]}
on:keydown={(event) => keyDown(event, processContextOffset + i)}
on:mouseover={() => elements[processContextOffset + i]?.focus()}
on:keydown={(event) => {
keyDown(event, processContextOffset + i)
}}
on:mouseover={() => {
elements[processContextOffset + i]?.focus()
}}
component={ExecutionContextPresenter}
props={{
context: pc,
@@ -236,8 +252,12 @@
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
<button
bind:this={elements[processContextOffset + i]}
on:keydown={(event) => keyDown(event, processContextOffset + i)}
on:mouseover={() => elements[processContextOffset + i]?.focus()}
on:keydown={(event) => {
keyDown(event, processContextOffset + i)
}}
on:mouseover={() => {
elements[processContextOffset + i]?.focus()
}}
on:click={() => {
onProcessContext(pc)
}}
@@ -254,8 +274,12 @@
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
<button
bind:this={elements[attributesOffset + i]}
on:keydown={(event) => keyDown(event, attributesOffset + i)}
on:mouseover={() => elements[attributesOffset + i]?.focus()}
on:keydown={(event) => {
keyDown(event, attributesOffset + i)
}}
on:mouseover={() => {
elements[attributesOffset + i]?.focus()
}}
on:click={() => {
onAttribute(attr)
}}
@@ -272,8 +296,12 @@
{#each nested as object, i}
<Submenu
bind:element={elements[nestedOffset + i]}
on:keydown={(event) => keyDown(event, nestedOffset + i)}
on:mouseover={() => elements[nestedOffset + i]?.focus()}
on:keydown={(event) => {
keyDown(event, nestedOffset + i)
}}
on:mouseover={() => {
elements[nestedOffset + i]?.focus()
}}
label={object.attribute.label}
props={{
context: object,
@@ -292,8 +320,12 @@
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
<button
bind:this={elements[relationsOffset + i]}
on:keydown={(event) => keyDown(event, relationsOffset + i)}
on:mouseover={() => elements[relationsOffset + i]?.focus()}
on:keydown={(event) => {
keyDown(event, relationsOffset + i)
}}
on:mouseover={() => {
elements[relationsOffset + i]?.focus()
}}
on:click={() => {
onRelation(object[1])
}}
@@ -306,8 +338,12 @@
{:else}
<Submenu
bind:element={elements[relationsOffset + i]}
on:keydown={(event) => keyDown(event, relationsOffset + i)}
on:mouseover={() => elements[relationsOffset + i]?.focus()}
on:keydown={(event) => {
keyDown(event, relationsOffset + i)
}}
on:mouseover={() => {
elements[relationsOffset + i]?.focus()
}}
text={object[1].name}
props={{
context: object[1],
@@ -324,8 +360,12 @@
{#each convertible as conv, i}
<Submenu
bind:element={elements[convertibleOffset + i]}
on:keydown={(event) => keyDown(event, convertibleOffset + i)}
on:mouseover={() => elements[convertibleOffset + i]?.focus()}
on:keydown={(event) => {
keyDown(event, convertibleOffset + i)
}}
on:mouseover={() => {
elements[convertibleOffset + i]?.focus()
}}
label={getFunc(conv.func).label}
props={{
process,
@@ -344,8 +384,12 @@
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
<button
bind:this={elements[customValueIndex]}
on:keydown={(event) => keyDown(event, customValueIndex)}
on:mouseover={() => elements[customValueIndex]?.focus()}
on:keydown={(event) => {
keyDown(event, customValueIndex)
}}
on:mouseover={() => {
elements[customValueIndex]?.focus()
}}
on:click={onConst}
class="menu-item"
>
@@ -0,0 +1,107 @@
<!--
// Copyright © 2025 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 { MasterTag, Tag } from '@hcengineering/card'
import core, { AnyAttribute, Ref } from '@hcengineering/core'
import { getResource } from '@hcengineering/platform'
import presentation, { Card, getClient } from '@hcengineering/presentation'
import { Context, Process, ProcessFunction } from '@hcengineering/process'
import ui, { AnySvelteComponent, DropdownIntlItem, DropdownLabelsIntl } from '@hcengineering/ui'
import view from '@hcengineering/view'
import { createEventDispatcher } from 'svelte'
import ProcessAttribute from '../ProcessAttribute.svelte'
import { Analytics } from '@hcengineering/analytics'
export let func: ProcessFunction
export let process: Process
export let masterTag: Ref<MasterTag | Tag>
export let context: Context
export let attribute: AnyAttribute
export let props: Record<string, any> = {}
let otherDate = props?.otherDate
let unit = props?.unit ?? 'days'
const items: DropdownIntlItem[] = [
{ id: 'hours', label: ui.string.Hours },
{ id: 'days', label: ui.string.Days },
{ id: 'weeks', label: ui.string.Weeks },
{ id: 'months', label: ui.string.Months },
{ id: 'years', label: ui.string.Years }
]
const dispatch = createEventDispatcher()
const client = getClient()
const h = client.getHierarchy()
function save (): void {
dispatch('close', { otherDate, unit })
}
let editor: AnySvelteComponent | undefined
function getEditor (): void {
try {
const inlineEditor = h.as(h.getClass(core.class.TypeDate), view.mixin.AttributeEditor).inlineEditor
void getResource(inlineEditor)
.then((p) => {
editor = p
})
.catch((e: any) => {
Analytics.handleError(e)
})
} catch (e: any) {
Analytics.handleError(e)
}
}
getEditor()
</script>
<Card on:close width={'small'} label={func.label} canSave okAction={save} okLabel={presentation.string.Save}>
<div class="grid">
<ProcessAttribute
{process}
{masterTag}
{context}
attribute={{ ...attribute, label: ui.string.TargetDate }}
presenterClass={{
attrClass: core.class.TypeDate,
category: 'attribute'
}}
value={otherDate}
{editor}
on:change={(e) => {
otherDate = e.detail
}}
/>
<div class="flex-row-center flex-gap-2">
<DropdownLabelsIntl {items} bind:selected={unit} />
</div>
</div>
</Card>
<style lang="scss">
.grid {
display: grid;
width: 100%;
grid-template-columns: 1fr;
grid-auto-rows: minmax(1rem, max-content);
justify-content: start;
align-items: center;
row-gap: 0.75rem;
height: min-content;
}
</style>