Fixed work slots layout in Planner (#5262)

Signed-off-by: Alexander Platov <alexander.platov@hardcoreeng.com>
This commit is contained in:
Alexander Platov 2024-04-10 14:36:56 +03:00 committed by GitHub
parent babbc490f2
commit 50d5c3bad9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 111 additions and 75 deletions

View File

@ -678,6 +678,7 @@ input.search {
.h-50 { height: 12.5rem; }
.h-60 { height: 15.0rem; }
.w-min { width: min-content; }
.w-max { width: max-content; }
.w-full { width: 100%; }
.w-2 { width: .5rem; }
.w-4 { width: 1rem; }
@ -708,6 +709,7 @@ input.search {
.min-w-144 { min-width: 25rem; }
.min-w-168 { min-width: 42rem; }
.min-w-min { min-width: min-content; }
.min-w-full { min-width: 100%; }
.min-h-0 { min-height: 0; }
.min-h-2 { min-height: .5rem; }
.min-h-4 { min-height: 1rem; }
@ -1001,6 +1003,7 @@ a.no-line {
.content-primary-color { color: var(--primary-button-color); }
.red-color { color: var(--highlight-red); }
.error-color { color: var(--theme-error-color); }
.sunshine-text-color { color: var(--tag-accent-SunshineText) !important; }
.border-radius-4 { border-radius: 1rem; }
.border-radius-3 { border-radius: 0.75rem; }

View File

@ -37,6 +37,7 @@
export let selected: DropdownIntlItem['id'] | undefined = undefined
export let element: HTMLButtonElement | undefined = undefined
export let focusIndex = -1
export let id: string | undefined = undefined
let opened: boolean = false
@ -83,5 +84,6 @@
{inheritColor}
pressed={opened}
{focusIndex}
{id}
on:click={openPopup}
/>

View File

@ -25,6 +25,7 @@
getUserTimezone,
showPopup
} from '@hcengineering/ui'
import { FixedColumn } from '@hcengineering/view-resources'
import { createEventDispatcher } from 'svelte'
import DateLocalePresenter from './DateLocalePresenter.svelte'
@ -38,6 +39,7 @@
export let disabled: boolean = false
export let focusIndex = -1
export let timeZone: string = getUserTimezone()
export let fixed: string | undefined = undefined
const dispatch = createEventDispatcher()
@ -80,11 +82,19 @@
class:flex-gap-2={direction === 'horizontal'}
>
{#if showDate || withoutTime}
{#if fixed === undefined}
<div class="min-w-28">
<ButtonBase type="type-button" {kind} {size} {disabled} {focusIndex} on:click={dateClick}>
<DateLocalePresenter date={currentDate.getTime()} {timeZone} />
<span class="overflow-label"><DateLocalePresenter date={currentDate.getTime()} {timeZone} /></span>
</ButtonBase>
</div>
{:else}
<FixedColumn key={fixed + '-date'} addClass={'min-w-28'}>
<ButtonBase type="type-button" {kind} {size} {disabled} {focusIndex} on:click={dateClick}>
<span class="overflow-label"><DateLocalePresenter date={currentDate.getTime()} {timeZone} /></span>
</ButtonBase>
</FixedColumn>
{/if}
{/if}
{#if showDate && !withoutTime && direction === 'horizontal'}
@ -92,6 +102,7 @@
{/if}
{#if !withoutTime}
{#if fixed === undefined}
<ButtonBase
type="type-button"
{kind}
@ -110,14 +121,42 @@
}}
/>
</ButtonBase>
{:else}
<FixedColumn key={fixed + '-time'} addClass={'min-w-28'}>
<ButtonBase
type="type-button"
{kind}
{size}
{disabled}
focusIndex={focusIndex !== -1 ? focusIndex + 1 : focusIndex}
on:click={timeClick}
>
<TimeInputBox
bind:currentDate
{timeZone}
noBorder
size={'small'}
on:update={(date) => {
updateTime(date.detail)
}}
/>
</ButtonBase>
</FixedColumn>
{/if}
{/if}
</div>
{#if !withoutTime && difference > 0}
<div class="divider" />
<div class="duration font-regular-14">
{#if fixed === undefined}
<div class="p-2 font-regular-14 sunshine-text-color">
<TimeShiftPresenter value={date - difference} exact />
</div>
{:else}
<FixedColumn key={fixed + '-duration'} addClass={'p-2 font-regular-14 sunshine-text-color'}>
<TimeShiftPresenter value={date - difference} exact />
</FixedColumn>
{/if}
{/if}
<style lang="scss">
@ -140,11 +179,6 @@
}
}
.duration {
padding: var(--spacing-1);
color: var(--tag-accent-SunshineText);
}
.divider {
width: 0;
height: 1.25rem;

View File

@ -25,14 +25,11 @@
weekday: 'short',
month: 'short'
}
if (current.getFullYear() !== new Date(date).getFullYear()) {
options = {
$: options = {
...options,
year: '2-digit'
timeZone,
year: current.getFullYear() !== new Date(date).getFullYear() ? '2-digit' : undefined
}
}
$: options.timeZone = timeZone
</script>
{new Date(date).toLocaleDateString('default', options)}

View File

@ -24,6 +24,8 @@
export let disabled: boolean = false
export let timeZone: string = getUserTimezone()
export let focusIndex = -1
export let grow: boolean = false
export let fixed: string | undefined = undefined
$: sameDate = areDatesEqual(utcToZonedTime(startDate, timeZone), utcToZonedTime(dueDate, timeZone))
@ -49,7 +51,7 @@
}
</script>
<div class="flex-row-center flex-gap-2">
<div class="flex-row-center flex-gap-2 flex-no-shrink" class:flex-grow={grow}>
<DateEditor
bind:date={startDate}
direction={sameDate ? 'horizontal' : 'vertical'}
@ -58,6 +60,7 @@
on:update={dateChange}
{disabled}
{focusIndex}
fixed={fixed === undefined ? undefined : fixed + '-startDate'}
/>
<div class="flex-no-shrink content-darker-color"></div>
<DateEditor
@ -69,6 +72,7 @@
{disabled}
{timeZone}
focusIndex={focusIndex !== -1 ? focusIndex + 1 : focusIndex}
fixed={fixed === undefined ? undefined : fixed + '-dueDate'}
on:update={dueChange}
/>
</div>

View File

@ -64,6 +64,7 @@
{size}
{disabled}
{focusIndex}
id={'visibleButton'}
on:selected={(event) => {
if (event.detail) change(event.detail)
}}

View File

@ -249,6 +249,7 @@
<Workslots
bind:slots
shortcuts={false}
fixed={'createToDo'}
on:remove={removeSlot}
on:create={createSlot}
on:change={changeSlot}

View File

@ -236,6 +236,7 @@
.slots-content {
gap: var(--spacing-2);
padding: var(--spacing-2) var(--spacing-4);
min-width: 0;
border-top: 1px solid var(--theme-divider-color);
}
.eventPopup-container {

View File

@ -92,4 +92,4 @@
}
</script>
<Workslots {slots} on:change={change} on:dueChange={dueChange} on:create={create} on:remove={remove} />
<Workslots {slots} fixed={'toDo'} on:change={change} on:dueChange={dueChange} on:create={create} on:remove={remove} />

View File

@ -13,7 +13,7 @@
// limitations under the License.
-->
<script lang="ts">
import { ButtonBase, ButtonIcon, IconDelete, themeStore, Hotkey, HotkeyGroup } from '@hcengineering/ui'
import { ButtonBase, ButtonIcon, IconDelete, themeStore, Hotkey, HotkeyGroup, Scroller } from '@hcengineering/ui'
import { EventTimeEditor } from '@hcengineering/calendar-resources'
import { WorkSlot } from '@hcengineering/time'
import { createEventDispatcher } from 'svelte'
@ -23,6 +23,7 @@
export let slots: WorkSlot[] = []
export let shortcuts: boolean = true
export let fixed: string | undefined = undefined
const dispatch = createEventDispatcher()
@ -51,18 +52,20 @@
<svelte:window on:keydown={handleKeyDown} />
<div class="flex-col w-full flex-gap-1">
<Scroller gap={'flex-gap-1'} horizontal>
{#each slots as slot, i}
<div class="flex justify-start items-center flex-gap-2 w-full pr-4 slot">
<div class="flex-between flex-no-shrink flex-gap-2 min-w-full w-max slot">
<Hotkey key={(i + 1).toString()} />
<EventTimeEditor
allDay={false}
startDate={slot.date}
dueDate={slot.dueDate}
grow
{fixed}
on:change={(e) => change(e, slot)}
on:dueChange={(e) => dueChange(e, slot)}
/>
<div class="tool">
<div class="tool flex-no-shrink">
<ButtonIcon
kind="tertiary"
size="small"
@ -74,7 +77,7 @@
</div>
</div>
{/each}
</div>
</Scroller>
<div class="flex-row-center flex-gap-4">
<ButtonBase
kind="secondary"
@ -98,25 +101,11 @@
<style lang="scss">
.slot {
position: relative;
padding: var(--spacing-1) var(--spacing-1) var(--spacing-1) var(--spacing-2_5);
border-radius: var(--small-BorderRadius);
padding: var(--spacing-1) var(--spacing-1) var(--spacing-1) var(--spacing-2);
background-color: var(--tag-nuance-SunshineBackground);
&:before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 0.25rem;
height: 100%;
background-color: var(--tag-accent-SunshineBackground);
border-radius: var(--small-BorderRadius) 0 0 var(--small-BorderRadius);
}
.tool {
margin-left: auto;
}
border-left: var(--extra-small-BorderRadius) solid var(--tag-accent-SunshineBackground);
border-radius: var(--extra-small-BorderRadius) var(--small-BorderRadius) var(--small-BorderRadius)
var(--extra-small-BorderRadius);
}
.duration {

View File

@ -48,10 +48,8 @@ export class PlanningPage extends CalendarPage {
)
this.buttonPopupCreatePriority = page.locator('div.popup button#priorityButton')
this.buttonPanelCreatePriority = page.locator('div.hulyModal-container button#priorityButton')
this.buttonPopupCreateVisible = page.locator('div.popup button.type-button.menu', { hasText: 'visible' })
this.buttonPanelCreateVisible = page.locator('div.hulyModal-container button.type-button.menu', {
hasText: 'visible'
})
this.buttonPopupCreateVisible = page.locator('div.popup button#visibleButton')
this.buttonPanelCreateVisible = page.locator('div.hulyModal-container button#visibleButton')
this.buttonPopupCreateAddLabel = page.locator('div.popup button.antiButton', { hasText: 'Add label' })
this.buttonPanelCreateAddLabel = page.locator('.hulyHeader-titleGroup > button:nth-child(2)')
this.buttonPopupCreateAddSlot = page.locator('div.popup button', { hasText: 'Add Slot' })
@ -137,12 +135,12 @@ export class PlanningPage extends CalendarPage {
public async setTimeSlot (rowNumber: number, slot: Slot, popup: boolean = false): Promise<void> {
const p = popup
? 'div.popup div.horizontalBox div.end div.flex-col div.flex'
: 'div.hulyModal-container div.slots-content div.flex-col div.flex'
? 'div.popup div.horizontalBox div.end div.scroller-container div.box div.flex-between.min-w-full'
: 'div.hulyModal-container div.slots-content div.scroller-container div.box div.flex-between.min-w-full'
const row = this.page.locator(p).nth(rowNumber)
// dateStart
await row.locator('div.dateEditor-container:nth-child(1) button:first-child').click()
await row.locator('div.dateEditor-container:first-child > div.min-w-28:first-child button').click()
if (slot.dateStart === 'today') {
await this.buttonCalendarToday.click()
} else {
@ -177,8 +175,8 @@ export class PlanningPage extends CalendarPage {
private async checkTimeSlot (rowNumber: number, slot: Slot, popup: boolean = false): Promise<void> {
const p = popup
? 'div.popup div.horizontalBox div.end div.flex-col div.flex'
: 'div.hulyModal-container div.slots-content div.flex-col div.flex'
? 'div.popup div.horizontalBox div.end div.scroller-container div.box div.flex-between.min-w-full'
: 'div.hulyModal-container div.slots-content div.scroller-container div.box div.flex-between.min-w-full'
const row = this.page.locator(p).nth(rowNumber)
// timeStart
await expect(row.locator('div.dateEditor-container:nth-child(1) button:last-child div.datetime-input')).toHaveText(
@ -260,7 +258,9 @@ export class PlanningPage extends CalendarPage {
public async deleteTimeSlot (rowNumber: number): Promise<void> {
const row = this.page
.locator('div.hulyModal-container div.slots-content div.flex-col div.flex div.tool')
.locator(
'div.hulyModal-container div.slots-content div.scroller-container div.box div.flex-between.min-w-full div.tool'
)
.nth(rowNumber)
await row.locator('xpath=..').hover()
await row.locator('button').click()
@ -268,8 +268,12 @@ export class PlanningPage extends CalendarPage {
}
public async checkTimeSlotEndDate (rowNumber: number, dateEnd: string): Promise<void> {
const row = this.page.locator('div.hulyModal-container div.slots-content div.flex-col div.flex').nth(rowNumber)
const row = this.page
.locator('div.hulyModal-container div.slots-content div.scroller-container div.box div.flex-between.min-w-full')
.nth(rowNumber)
// dateEnd
await expect(row.locator('div.dateEditor-container:nth-child(1) button:first-child')).toContainText(dateEnd)
await expect(row.locator('div.dateEditor-container:first-child > div.min-w-28:first-child button')).toContainText(
dateEnd
)
}
}