mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-23 16:56:07 +00:00
UBER-1083: Use hours and minutes to present less than a day durations (#4111)
Signed-off-by: Petr Vyazovetskiy <develop.pit@gmail.com>
This commit is contained in:
parent
32e39a3723
commit
e361325a73
@ -11,7 +11,7 @@ export interface KeyedAttribute {
|
||||
export { updateAttribute } from '@hcengineering/core'
|
||||
|
||||
export function getAttribute (client: Client, object: any, key: KeyedAttribute): any {
|
||||
// Check if attr is mixin and return it's value
|
||||
// Check if attr is mixin and return its value
|
||||
if (client.getHierarchy().isMixin(key.attr.attributeOf)) {
|
||||
return (client.getHierarchy().as(object, key.attr.attributeOf) as any)[key.key]
|
||||
} else {
|
||||
|
@ -73,6 +73,7 @@ export function checkAdaptiveMatching (size: WidthType | null, limit: WidthType)
|
||||
return size !== null ? range.has(size) : false
|
||||
}
|
||||
|
||||
// TODO: Fix naming, since it doesn't floor (floorFractionDigits(2.5) === 3.0)
|
||||
export function floorFractionDigits (n: number | string, amount: number): number {
|
||||
return Number(Number(n).toFixed(amount))
|
||||
}
|
||||
|
@ -237,7 +237,9 @@
|
||||
"TimeSpendReportValueTooltip": "Spent time in hours",
|
||||
"TimeSpendReportDescription": "Description",
|
||||
"TimeSpendValue": "{value}d",
|
||||
"TimeSpendDays": "{value}d",
|
||||
"TimeSpendHours": "{value}h",
|
||||
"TimeSpendMinutes": "{value}m",
|
||||
"ChildEstimation": "Subissues Estimation",
|
||||
"ChildReportedTime": "Subissues Time",
|
||||
"CapacityValue": "of {value}d",
|
||||
|
@ -237,7 +237,9 @@
|
||||
"TimeSpendReportValueTooltip": "Затраченное время в человеко днях",
|
||||
"TimeSpendReportDescription": "Описание",
|
||||
"TimeSpendValue": "{value}d",
|
||||
"TimeSpendDays": "{value}d",
|
||||
"TimeSpendHours": "{value}h",
|
||||
"TimeSpendMinutes": "{value}m",
|
||||
"ChildEstimation": "Оценка подзадач",
|
||||
"ChildReportedTime": "Время подзадач",
|
||||
"CapacityValue": "из {value}d",
|
||||
|
@ -13,13 +13,46 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { floorFractionDigits, Label, tooltip } from '@hcengineering/ui'
|
||||
import { Label, tooltip, themeStore } from '@hcengineering/ui'
|
||||
import tracker from '../../../plugin'
|
||||
import { translate } from '@hcengineering/platform'
|
||||
|
||||
export let id: string | undefined = undefined
|
||||
export let kind: 'link' | undefined = undefined
|
||||
export let value: number
|
||||
export let noSymbol: boolean = false
|
||||
|
||||
// TODO: Make configurable?
|
||||
const hoursInWorkingDay = 8
|
||||
|
||||
let label = ''
|
||||
|
||||
$: days = Math.floor(value / hoursInWorkingDay)
|
||||
$: hours = Math.floor(value % hoursInWorkingDay)
|
||||
$: minutes = Math.floor((value % 1) * 60)
|
||||
|
||||
$: Promise.all([
|
||||
days > 0 ? translate(tracker.string.TimeSpendDays, { value: days }, $themeStore.language) : Promise.resolve(false),
|
||||
hours > 0
|
||||
? translate(tracker.string.TimeSpendHours, { value: hours }, $themeStore.language)
|
||||
: Promise.resolve(false),
|
||||
minutes > 0
|
||||
? translate(tracker.string.TimeSpendMinutes, { value: minutes }, $themeStore.language)
|
||||
: Promise.resolve(false)
|
||||
])
|
||||
.then(([days, hours, minutes]) =>
|
||||
[
|
||||
...(days === false ? [] : [days]),
|
||||
...(hours === false ? [] : [hours]),
|
||||
...(minutes === false ? [] : [minutes])
|
||||
].join(' ')
|
||||
)
|
||||
.then((l) => (l === '' ? translate(tracker.string.TimeSpendHours, { value: 0 }, $themeStore.language) : l))
|
||||
.then((l) => {
|
||||
label = l
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err)
|
||||
})
|
||||
</script>
|
||||
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
@ -30,16 +63,13 @@
|
||||
on:click
|
||||
use:tooltip={{
|
||||
component: Label,
|
||||
props: { label: tracker.string.TimeSpendHours, params: { value: floorFractionDigits(value, 2) } }
|
||||
props: {
|
||||
label: tracker.string.TimeSpendValue,
|
||||
params: { value }
|
||||
}
|
||||
}}
|
||||
>
|
||||
{#if noSymbol}
|
||||
{floorFractionDigits(value, 2)}
|
||||
{:else if value > 0 && value < 8}
|
||||
<Label label={tracker.string.TimeSpendHours} params={{ value: floorFractionDigits(value, 2) }} />
|
||||
{:else}
|
||||
<Label label={tracker.string.TimeSpendValue} params={{ value: floorFractionDigits(value / 8, 3) }} />
|
||||
{/if}
|
||||
{label}
|
||||
</span>
|
||||
|
||||
<style lang="scss">
|
||||
|
@ -269,7 +269,9 @@ export default mergeIds(trackerId, tracker, {
|
||||
TimeSpendReportValue: '' as IntlString,
|
||||
TimeSpendReportDescription: '' as IntlString,
|
||||
TimeSpendValue: '' as IntlString,
|
||||
TimeSpendDays: '' as IntlString,
|
||||
TimeSpendHours: '' as IntlString,
|
||||
TimeSpendMinutes: '' as IntlString,
|
||||
|
||||
ChildEstimation: '' as IntlString,
|
||||
ChildReportedTime: '' as IntlString,
|
||||
|
@ -4,7 +4,7 @@
|
||||
./tool-local.sh create-account user1 -f John -l Appleseed -p 1234
|
||||
./tool-local.sh confirm-email user1
|
||||
# Create second user record in accounts
|
||||
./tool-local.sh create-account user2 -f Kainin -l Numoin -p 1234
|
||||
./tool-local.sh create-account user2 -f Kainin -l Dirak -p 1234
|
||||
./tool-local.sh confirm-email user2
|
||||
|
||||
|
||||
@ -18,4 +18,4 @@
|
||||
./tool-local.sh assign-workspace user2 sanity-ws
|
||||
|
||||
./tool-local.sh configure sanity-ws --enable=*
|
||||
./tool-local.sh configure sanity-ws --list
|
||||
./tool-local.sh configure sanity-ws --list
|
||||
|
@ -44,6 +44,7 @@ export class TemplateDetailsPage extends CommonTrackerPage {
|
||||
if (data.labels != null) {
|
||||
await this.buttonAddLabel.click()
|
||||
await expect(this.page.locator('div.menu-group span', { hasText: data.labels })).toBeVisible()
|
||||
await this.inputTitle.click({ force: true })
|
||||
}
|
||||
if (data.component != null) {
|
||||
await expect(this.buttonComponent).toHaveText(data.component)
|
||||
|
@ -83,5 +83,32 @@ test.describe('Tracker issue tests', () => {
|
||||
...editIssue,
|
||||
estimation: '1d'
|
||||
})
|
||||
|
||||
const estimations = new Map([
|
||||
['0', '0h'],
|
||||
['1', '1h'],
|
||||
['1.25', '1h 15m'],
|
||||
['1.259', '1h 15m'],
|
||||
['1.26', '1h 15m'],
|
||||
['1.27', '1h 16m'],
|
||||
['1.5', '1h 30m'],
|
||||
['1.75', '1h 45m'],
|
||||
['2', '2h'],
|
||||
['7', '7h'],
|
||||
['8', '1d'],
|
||||
['9', '1d 1h'],
|
||||
['9.5', '1d 1h 30m']
|
||||
])
|
||||
|
||||
for (const [input, expected] of estimations.entries()) {
|
||||
await issuesDetailsPage.editIssue({
|
||||
estimation: input
|
||||
})
|
||||
await issuesDetailsPage.checkIssue({
|
||||
...newIssue,
|
||||
...editIssue,
|
||||
estimation: expected
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
@ -49,7 +49,7 @@ test.describe('Tracker template tests', () => {
|
||||
|
||||
test('Edit a Template', async ({ page }) => {
|
||||
const newTemplate: NewIssue = {
|
||||
title: 'Template for edit',
|
||||
title: `Template for edit-${generateId()}`,
|
||||
description: 'Created template for edit'
|
||||
}
|
||||
|
||||
@ -70,6 +70,7 @@ test.describe('Tracker template tests', () => {
|
||||
await trackerNavigationMenuPage.buttonTemplates.click()
|
||||
|
||||
const templatePage = new TemplatePage(page)
|
||||
await templatePage.createNewTemplate(newTemplate)
|
||||
await templatePage.openTemplate(newTemplate.title)
|
||||
|
||||
const templateDetailsPage = new TemplateDetailsPage(page)
|
||||
@ -82,9 +83,32 @@ test.describe('Tracker template tests', () => {
|
||||
})
|
||||
|
||||
await templateDetailsPage.checkCommentExist('Appleseed John created template')
|
||||
await templateDetailsPage.checkCommentExist('Appleseed John changed priority to High')
|
||||
await templateDetailsPage.checkCommentExist('Appleseed John changed assignee to Dirak Kainin')
|
||||
await templateDetailsPage.checkCommentExist('Appleseed John changed estimation to 1d')
|
||||
await templateDetailsPage.checkCommentExist('Appleseed John changed due date')
|
||||
|
||||
const estimations = new Map([
|
||||
['0', '0h'],
|
||||
['1', '1h'],
|
||||
['1.25', '1h 15m'],
|
||||
['1.259', '1h 15m'],
|
||||
['1.26', '1h 15m'],
|
||||
['1.27', '1h 16m'],
|
||||
['1.5', '1h 30m'],
|
||||
['1.75', '1h 45m'],
|
||||
['2', '2h'],
|
||||
['7', '7h'],
|
||||
['8', '1d'],
|
||||
['9', '1d 1h'],
|
||||
['9.5', '1d 1h 30m']
|
||||
])
|
||||
|
||||
for (const [input, expected] of estimations.entries()) {
|
||||
await templateDetailsPage.editTemplate({
|
||||
estimation: input
|
||||
})
|
||||
await templateDetailsPage.checkTemplate({
|
||||
...newTemplate,
|
||||
...editTemplate,
|
||||
estimation: expected
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
@ -213,9 +213,20 @@ export async function floorFractionDigits (n: number | string, amount: number):
|
||||
}
|
||||
|
||||
export async function toTime (value: number): Promise<string> {
|
||||
if (value > 0 && value < 8) {
|
||||
return `${await floorFractionDigits(value, 2)}h`
|
||||
} else {
|
||||
return `${await floorFractionDigits(value / 8, 3)}d`
|
||||
if (value <= 0) {
|
||||
return '0h'
|
||||
}
|
||||
|
||||
// TODO: Make configurable?
|
||||
const hoursInWorkingDay = 8
|
||||
|
||||
const days = Math.floor(value / hoursInWorkingDay)
|
||||
const hours = Math.floor(value % hoursInWorkingDay)
|
||||
const minutes = Math.floor((value % 1) * 60)
|
||||
|
||||
return [
|
||||
...(days > 0 ? [`${days}d`] : []),
|
||||
...(hours > 0 ? [`${hours}h`] : []),
|
||||
...(minutes > 0 ? [`${minutes}m`] : [])
|
||||
].join(' ')
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user