mirror of
https://github.com/hcengineering/platform.git
synced 2024-11-22 11:42:30 +03:00
parent
6e44e556f6
commit
7cabfc746e
@ -59,7 +59,6 @@ export default mergeIds(boardId, board, {
|
||||
string: {
|
||||
CommonBoardPreference: '' as IntlString,
|
||||
ConvertToCard: '' as IntlString,
|
||||
ConfigLabel: '' as IntlString,
|
||||
ConfigDescription: '' as IntlString
|
||||
},
|
||||
action: {
|
||||
|
@ -27,7 +27,6 @@ export default mergeIds(calendarId, calendar, {
|
||||
component: {
|
||||
IntegrationConnect: '' as AnyComponent,
|
||||
CreateCalendar: '' as AnyComponent,
|
||||
CalendarView: '' as AnyComponent,
|
||||
EventPresenter: '' as AnyComponent,
|
||||
CalendarIntegrationIcon: '' as AnyComponent
|
||||
},
|
||||
|
@ -33,7 +33,6 @@ export default mergeIds(leadId, lead, {
|
||||
Title: '' as IntlString,
|
||||
ManageFunnelStatuses: '' as IntlString,
|
||||
GotoLeadApplication: '' as IntlString,
|
||||
ConfigLabel: '' as IntlString,
|
||||
ConfigDescription: '' as IntlString
|
||||
},
|
||||
component: {
|
||||
|
@ -64,7 +64,6 @@ export default mergeIds(recruitId, recruit, {
|
||||
GotoApplicants: '' as IntlString,
|
||||
GotoRecruitApplication: '' as IntlString,
|
||||
VacancyList: '' as IntlString,
|
||||
ConfigLabel: '' as IntlString,
|
||||
ConfigDescription: '' as IntlString,
|
||||
ShowApplications: '' as IntlString
|
||||
},
|
||||
|
@ -46,8 +46,8 @@ import {
|
||||
} from '@hcengineering/model'
|
||||
import attachment from '@hcengineering/model-attachment'
|
||||
import chunter from '@hcengineering/model-chunter'
|
||||
import { TTask } from '@hcengineering/model-task'
|
||||
import core, { DOMAIN_SPACE, TAttachedDoc, TDoc, TSpace, TStatus, TType } from '@hcengineering/model-core'
|
||||
import core, { TAttachedDoc, TDoc, TStatus, TType } from '@hcengineering/model-core'
|
||||
import { TSpaceWithStates, TTask } from '@hcengineering/model-task'
|
||||
import view, { actionTemplates, classPresenter, createAction, showColorsViewOption } from '@hcengineering/model-view'
|
||||
import workbench, { createNavigateAction } from '@hcengineering/model-workbench'
|
||||
import notification from '@hcengineering/notification'
|
||||
@ -121,9 +121,9 @@ export class TTypeMilestoneStatus extends TType {}
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
@Model(tracker.class.Project, core.class.Space, DOMAIN_SPACE)
|
||||
@Model(tracker.class.Project, task.class.SpaceWithStates)
|
||||
@UX(tracker.string.Project, tracker.icon.Issues, 'Project', 'name')
|
||||
export class TProject extends TSpace implements Project {
|
||||
export class TProject extends TSpaceWithStates implements Project {
|
||||
@Prop(TypeString(), tracker.string.ProjectIdentifier)
|
||||
@Index(IndexKind.FullText)
|
||||
identifier!: IntlString
|
||||
|
@ -39,7 +39,6 @@ export default mergeIds(trackerId, tracker, {
|
||||
Parent: '' as IntlString,
|
||||
CreatedDate: '' as IntlString,
|
||||
ChangeStatus: '' as IntlString,
|
||||
ConfigLabel: '' as IntlString,
|
||||
ConfigDescription: '' as IntlString,
|
||||
Unarchive: '' as IntlString,
|
||||
UnarchiveConfirm: '' as IntlString,
|
||||
|
@ -270,6 +270,7 @@ input.search {
|
||||
.items-center { align-items: center; }
|
||||
.self-end { align-self: end; }
|
||||
|
||||
.flex-gap-4 { gap: 1rem; }
|
||||
.flex-gap-3 { gap: .75rem; }
|
||||
.flex-gap-2 { gap: .5rem; }
|
||||
.flex-gap-1-5 { gap: .375rem; }
|
||||
|
@ -16,7 +16,7 @@
|
||||
import { DateRangeMode } from '@hcengineering/core'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import ui from '../plugin'
|
||||
import { DateOrShift } from '../types'
|
||||
import { DAY, DateOrShift, HOUR, MINUTE } from '../types'
|
||||
import DateRangePresenter from './calendar/DateRangePresenter.svelte'
|
||||
import TimeShiftPresenter from './TimeShiftPresenter.svelte'
|
||||
|
||||
@ -30,9 +30,7 @@
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
$: base = direction === 'before' ? -1 : 1
|
||||
const MINUTE = 60 * 1000
|
||||
const HOUR = 60 * MINUTE
|
||||
const DAY = 24 * HOUR
|
||||
|
||||
$: values = [...minutes.map((m) => m * MINUTE), ...hours.map((m) => m * HOUR), ...days.map((m) => m * DAY)]
|
||||
</script>
|
||||
|
||||
|
@ -16,14 +16,10 @@
|
||||
import { translate } from '@hcengineering/platform'
|
||||
import ui from '../plugin'
|
||||
import { themeStore } from '@hcengineering/theme'
|
||||
import { DAY, HOUR, MINUTE } from '../types'
|
||||
|
||||
export let value: number
|
||||
|
||||
const SECOND = 1000
|
||||
const MINUTE = SECOND * 60
|
||||
const HOUR = MINUTE * 60
|
||||
const DAY = HOUR * 24
|
||||
|
||||
let time: string = ''
|
||||
|
||||
async function formatTime (value: number) {
|
||||
|
@ -13,21 +13,13 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts" context="module">
|
||||
const SECOND = 1000
|
||||
const MINUTE = SECOND * 60
|
||||
const HOUR = MINUTE * 60
|
||||
const DAY = HOUR * 24
|
||||
const MONTH = DAY * 30
|
||||
const YEAR = MONTH * 12
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { translate } from '@hcengineering/platform'
|
||||
import { ticker } from '..'
|
||||
import { DAY, HOUR, MINUTE, MONTH, YEAR } from '../types'
|
||||
import ui from '../plugin'
|
||||
import { tooltip } from '../tooltips'
|
||||
import { themeStore } from '@hcengineering/theme'
|
||||
import { ticker } from '..'
|
||||
|
||||
export let value: number | undefined
|
||||
export let kind: 'no-border' | 'list' = 'no-border'
|
||||
|
@ -43,6 +43,7 @@
|
||||
export let startHour = 0
|
||||
export let startFromWeekStart = true
|
||||
export let weekFormat: 'narrow' | 'short' | 'long' | undefined = displayedDaysCount > 4 ? 'short' : 'long'
|
||||
export let showHeader = true
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
@ -120,7 +121,7 @@
|
||||
.forEach((event, i, arr) => {
|
||||
if (grid[event.day] === undefined) {
|
||||
grid[event.day] = {
|
||||
columns: [{ elements: [{ id: event.eventId, date: event.date, dueDate: event.dueDate, cols: 1 }] }]
|
||||
columns: [{ elements: [{ id: event._id, date: event.date, dueDate: event.dueDate, cols: 1 }] }]
|
||||
}
|
||||
} else {
|
||||
const index = grid[event.day].columns.findIndex(
|
||||
@ -137,7 +138,7 @@
|
||||
}
|
||||
})
|
||||
grid[event.day].columns.push({
|
||||
elements: [{ id: event.eventId, date: event.date, dueDate: event.dueDate, cols: size }]
|
||||
elements: [{ id: event._id, date: event.date, dueDate: event.dueDate, cols: size }]
|
||||
})
|
||||
} else {
|
||||
const intersects = grid[event.day].columns.filter((col) =>
|
||||
@ -156,7 +157,7 @@
|
||||
}
|
||||
})
|
||||
grid[event.day].columns[index].elements.push({
|
||||
id: event.eventId,
|
||||
id: event._id,
|
||||
date: event.date,
|
||||
dueDate: event.dueDate,
|
||||
cols: maxCols
|
||||
@ -192,7 +193,7 @@
|
||||
adMaxRow = 1
|
||||
alldays.forEach((event) => {
|
||||
const days = events
|
||||
.filter((ev) => ev.allDay && ev.day !== -1 && event.eventId === ev.eventId)
|
||||
.filter((ev) => ev.allDay && ev.day !== -1 && event._id === ev._id)
|
||||
.map((ev) => {
|
||||
return ev.day
|
||||
})
|
||||
@ -208,8 +209,8 @@
|
||||
break
|
||||
}
|
||||
}
|
||||
adRows.push({ id: event.eventId, row: emptyRow, startCol: days[0], endCol: days[days.length - 1] })
|
||||
days.forEach((day) => (alldaysGrid[day].alldays[emptyRow] = event.eventId))
|
||||
adRows.push({ id: event._id, row: emptyRow, startCol: days[0], endCol: days[days.length - 1] })
|
||||
days.forEach((day) => (alldaysGrid[day].alldays[emptyRow] = event._id))
|
||||
})
|
||||
const shown = minimizedAD ? minAD : maxAD
|
||||
let tempEventID: string = ''
|
||||
@ -280,8 +281,7 @@
|
||||
result.visibility = 0
|
||||
}
|
||||
result.top =
|
||||
rem(3.5) +
|
||||
styleAD +
|
||||
(showHeader ? rem(3.5) + styleAD : 0) +
|
||||
cellHeight * startTime.hours +
|
||||
(startTime.mins / 60) * cellHeight +
|
||||
getGridOffset(startTime.mins)
|
||||
@ -293,7 +293,7 @@
|
||||
let index: number = 0
|
||||
grid[event.day].columns.forEach((col, i) =>
|
||||
col.elements.forEach((el) => {
|
||||
if (el.id === event.eventId) {
|
||||
if (el.id === event._id) {
|
||||
cols = el.cols
|
||||
index = i
|
||||
}
|
||||
@ -399,7 +399,7 @@
|
||||
<div
|
||||
bind:this={container}
|
||||
class="calendar-container"
|
||||
style:grid={`[header] 3.5rem [all-day] ${styleAD}px repeat(${
|
||||
style:grid={`${showHeader ? '[header] 3.5rem [all-day] ' + styleAD + 'px' : ''} repeat(${
|
||||
(displayedHours - startHour) * 2
|
||||
}, [row-start] 2rem) / [time-col] 3.5rem repeat(${displayedDaysCount}, [col-start] 1fr)`}
|
||||
use:resizeObserver={(element) => checkSizes(element)}
|
||||
@ -431,7 +431,7 @@
|
||||
{#key styleAD}{#key calendarWidth}{#key displayedDaysCount}
|
||||
<div style:min-height={`${shownHeightAD - cellBorder * 2}px`} />
|
||||
{#each alldays as event, i}
|
||||
{@const rect = getADRect(event.eventId)}
|
||||
{@const rect = getADRect(event._id)}
|
||||
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
||||
<div
|
||||
class="calendar-element"
|
||||
@ -443,70 +443,70 @@
|
||||
style:--mask-image={getMask(rect.visibility)}
|
||||
tabindex={500 + i}
|
||||
>
|
||||
<slot name="event" id={event.eventId} size={{ width: rect.width, height: rect.height }} />
|
||||
<slot name="event" id={event._id} size={{ width: rect.width, height: rect.height }} />
|
||||
</div>
|
||||
{/each}
|
||||
{/key}{/key}{/key}
|
||||
</Scroller>
|
||||
{:else if shownAD}
|
||||
{#key styleAD}{#key calendarWidth}{#key displayedDaysCount}
|
||||
{#each alldays as event, i}
|
||||
{@const rect = getADRect(event.eventId)}
|
||||
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
||||
<div
|
||||
class="calendar-element"
|
||||
style:top={`${rect.top}px`}
|
||||
style:height={`${rect.height}px`}
|
||||
style:left={`${rect.left}px`}
|
||||
style:width={`${rect.width}px`}
|
||||
style:opacity={rect.visibility === 0 ? 0.4 : 1}
|
||||
style:--mask-image={getMask(rect.visibility)}
|
||||
tabindex={500 + i}
|
||||
>
|
||||
<slot name="event" id={event.eventId} size={{ width: rect.width, height: rect.height }} />
|
||||
</div>
|
||||
{/each}
|
||||
{/key}{/key}{/key}
|
||||
{#key [styleAD, calendarWidth, displayedDaysCount]}
|
||||
{#each alldays as event, i}
|
||||
{@const rect = getADRect(event._id)}
|
||||
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
||||
<div
|
||||
class="calendar-element"
|
||||
style:top={`${rect.top}px`}
|
||||
style:height={`${rect.height}px`}
|
||||
style:left={`${rect.left}px`}
|
||||
style:width={`${rect.width}px`}
|
||||
style:opacity={rect.visibility === 0 ? 0.4 : 1}
|
||||
style:--mask-image={getMask(rect.visibility)}
|
||||
tabindex={500 + i}
|
||||
>
|
||||
<slot name="event" id={event._id} size={{ width: rect.width, height: rect.height }} />
|
||||
</div>
|
||||
{/each}
|
||||
{/key}
|
||||
{:else}
|
||||
{#key styleAD}{#key calendarWidth}{#key displayedDaysCount}
|
||||
{#each shortAlldays as event, i}
|
||||
{@const rect = getADRect(event.id, event.day, event.fixRow)}
|
||||
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
||||
<div
|
||||
class="calendar-element"
|
||||
style:top={`${rect.top}px`}
|
||||
style:height={`${rect.height}px`}
|
||||
style:left={`${rect.left}px`}
|
||||
style:width={`${rect.width}px`}
|
||||
style:opacity={rect.visibility === 0 ? 0.4 : 1}
|
||||
style:--mask-image={getMask(rect.visibility)}
|
||||
tabindex={500 + i}
|
||||
>
|
||||
<slot name="event" id={event.id} size={{ width: rect.width, height: rect.height }} />
|
||||
</div>
|
||||
{/each}
|
||||
{#each moreCounts as more, day}
|
||||
{@const addon = shortAlldays.length}
|
||||
{#if more !== 0}
|
||||
{@const rect = getMore(day)}
|
||||
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div
|
||||
class="calendar-element antiButton ghost medium accent cursor-pointer"
|
||||
style:top={`${rect.top}px`}
|
||||
style:height={`${heightAD}rem`}
|
||||
style:left={`${rect.left}px`}
|
||||
style:width={`${rect.width}px`}
|
||||
style:padding-left={'1.25rem'}
|
||||
style:--mask-image={'none'}
|
||||
tabindex={500 + addon + day}
|
||||
on:click={() => (shownAD = true)}
|
||||
>
|
||||
<Label label={ui.string.MoreCount} params={{ count: more }} />
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
{/key}{/key}{/key}
|
||||
{#key [styleAD, calendarWidth, displayedDaysCount]}
|
||||
{#each shortAlldays as event, i}
|
||||
{@const rect = getADRect(event.id, event.day, event.fixRow)}
|
||||
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
||||
<div
|
||||
class="calendar-element"
|
||||
style:top={`${rect.top}px`}
|
||||
style:height={`${rect.height}px`}
|
||||
style:left={`${rect.left}px`}
|
||||
style:width={`${rect.width}px`}
|
||||
style:opacity={rect.visibility === 0 ? 0.4 : 1}
|
||||
style:--mask-image={getMask(rect.visibility)}
|
||||
tabindex={500 + i}
|
||||
>
|
||||
<slot name="event" id={event.id} size={{ width: rect.width, height: rect.height }} />
|
||||
</div>
|
||||
{/each}
|
||||
{#each moreCounts as more, day}
|
||||
{@const addon = shortAlldays.length}
|
||||
{#if more !== 0}
|
||||
{@const rect = getMore(day)}
|
||||
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div
|
||||
class="calendar-element antiButton ghost medium accent cursor-pointer"
|
||||
style:top={`${rect.top}px`}
|
||||
style:height={`${heightAD}rem`}
|
||||
style:left={`${rect.left}px`}
|
||||
style:width={`${rect.width}px`}
|
||||
style:padding-left={'1.25rem'}
|
||||
style:--mask-image={'none'}
|
||||
tabindex={500 + addon + day}
|
||||
on:click={() => (shownAD = true)}
|
||||
>
|
||||
<Label label={ui.string.MoreCount} params={{ count: more }} />
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
{/key}
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@ -530,6 +530,14 @@
|
||||
style:width={`${colWidth}px`}
|
||||
style:grid-column={`col-start ${dayOfWeek + 1} / ${dayOfWeek + 2}`}
|
||||
style:grid-row={`row-start ${hourOfDay * 2 + 1} / row-start ${hourOfDay * 2 + 3}`}
|
||||
on:dragover|preventDefault
|
||||
on:drop|preventDefault={(e) => {
|
||||
dispatch('drop', {
|
||||
day,
|
||||
hour: hourOfDay + startHour,
|
||||
date: new Date(day.setHours(hourOfDay + startHour, 0, 0, 0))
|
||||
})
|
||||
}}
|
||||
on:click|stopPropagation={() => {
|
||||
dispatch('create', {
|
||||
date: new Date(day.setHours(hourOfDay + startHour, 0, 0, 0)),
|
||||
@ -541,31 +549,31 @@
|
||||
{#if hourOfDay === displayedHours - startHour - 1}<div class="clear-cell" />{/if}
|
||||
{/each}
|
||||
|
||||
{#key styleAD}{#key calendarWidth}{#key displayedDaysCount}
|
||||
{#each newEvents.filter((ev) => !ev.allDay) as event, i}
|
||||
{@const rect = getRect(event)}
|
||||
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
||||
<div
|
||||
class="calendar-element"
|
||||
style:top={`${rect.top}px`}
|
||||
style:bottom={`${rect.bottom}px`}
|
||||
style:left={`${rect.left}px`}
|
||||
style:right={`${rect.right}px`}
|
||||
style:opacity={rect.visibility === 0 ? 0.4 : 1}
|
||||
style:--mask-image={'none'}
|
||||
tabindex={1000 + i}
|
||||
>
|
||||
<slot
|
||||
name="event"
|
||||
id={event.eventId}
|
||||
size={{
|
||||
width: rect.width,
|
||||
height: (calendarRect?.height ?? rect.top + rect.bottom) - rect.top - rect.bottom
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{/each}
|
||||
{/key}{/key}{/key}
|
||||
{#key [styleAD, calendarWidth, displayedDaysCount]}
|
||||
{#each newEvents.filter((ev) => !ev.allDay) as event, i}
|
||||
{@const rect = getRect(event)}
|
||||
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
||||
<div
|
||||
class="calendar-element"
|
||||
style:top={`${rect.top}px`}
|
||||
style:bottom={`${rect.bottom}px`}
|
||||
style:left={`${rect.left}px`}
|
||||
style:right={`${rect.right}px`}
|
||||
style:opacity={rect.visibility === 0 ? 0.4 : 1}
|
||||
style:--mask-image={'none'}
|
||||
tabindex={1000 + i}
|
||||
>
|
||||
<slot
|
||||
name="event"
|
||||
id={event._id}
|
||||
size={{
|
||||
width: rect.width,
|
||||
height: (calendarRect?.height ?? rect.top + rect.bottom) - rect.top - rect.bottom
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{/each}
|
||||
{/key}
|
||||
</div>
|
||||
</Scroller>
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import Scroller from '../Scroller.svelte'
|
||||
import TimeShiftPresenter from '../TimeShiftPresenter.svelte'
|
||||
import { DAY, HOUR, MINUTE } from '../../types'
|
||||
|
||||
export let currentDate: Date | null
|
||||
export let direction: 'before' | 'after' = 'after'
|
||||
@ -32,9 +33,6 @@
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
$: base = direction === 'before' ? -1 : 1
|
||||
const MINUTE = 60 * 1000
|
||||
const HOUR = 60 * MINUTE
|
||||
const DAY = 24 * HOUR
|
||||
|
||||
const shiftValues: (number | string)[] = []
|
||||
|
||||
|
@ -394,10 +394,17 @@ export interface DialogStep {
|
||||
* @public
|
||||
*/
|
||||
export interface CalendarItem {
|
||||
eventId: string
|
||||
_id: string
|
||||
allDay: boolean
|
||||
date: Timestamp
|
||||
dueDate: Timestamp
|
||||
day: number
|
||||
access: 'freeBusyReader' | 'reader' | 'writer' | 'owner'
|
||||
}
|
||||
|
||||
export const SECOND = 1000
|
||||
export const MINUTE = SECOND * 60
|
||||
export const HOUR = MINUTE * 60
|
||||
export const DAY = HOUR * 24
|
||||
export const MONTH = DAY * 30
|
||||
export const YEAR = MONTH * 12
|
||||
|
@ -117,6 +117,9 @@ const boards = plugin(boardId, {
|
||||
SendToBoard: '' as Ref<Action>,
|
||||
Delete: '' as Ref<Action>
|
||||
},
|
||||
string: {
|
||||
ConfigLabel: '' as IntlString
|
||||
},
|
||||
icon: {
|
||||
Board: '' as Asset,
|
||||
Card: '' as Asset
|
||||
|
@ -14,6 +14,7 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Calendar, Event, getAllEvents } from '@hcengineering/calendar'
|
||||
import { EmployeeAccount } from '@hcengineering/contact'
|
||||
import {
|
||||
Class,
|
||||
Doc,
|
||||
@ -21,50 +22,52 @@
|
||||
FindOptions,
|
||||
Ref,
|
||||
SortingOrder,
|
||||
Space,
|
||||
Timestamp,
|
||||
getCurrentAccount
|
||||
} from '@hcengineering/core'
|
||||
import { IntlString } from '@hcengineering/platform'
|
||||
import { createQuery } from '@hcengineering/presentation'
|
||||
import {
|
||||
AnyComponent,
|
||||
Button,
|
||||
IconBack,
|
||||
IconForward,
|
||||
MonthCalendar,
|
||||
CalendarItem,
|
||||
DayCalendar,
|
||||
WeekCalendar,
|
||||
DropdownLabelsIntl,
|
||||
IconBack,
|
||||
IconForward,
|
||||
MILLISECONDS_IN_DAY,
|
||||
MonthCalendar,
|
||||
YearCalendar,
|
||||
areDatesEqual,
|
||||
getMonday,
|
||||
DropdownLabelsIntl,
|
||||
showPopup,
|
||||
MILLISECONDS_IN_DAY
|
||||
showPopup
|
||||
} from '@hcengineering/ui'
|
||||
import { BuildModelKey } from '@hcengineering/view'
|
||||
import { CalendarMode } from '../index'
|
||||
import calendar from '../plugin'
|
||||
import Day from './Day.svelte'
|
||||
import Hour from './Hour.svelte'
|
||||
import EventElement from './EventElement.svelte'
|
||||
import { IntlString } from '@hcengineering/platform'
|
||||
|
||||
export let _class: Ref<Class<Doc>>
|
||||
export let space: Ref<Space> | undefined = undefined
|
||||
export let query: DocumentQuery<Event> = {}
|
||||
export let _class: Ref<Class<Doc>> = calendar.class.Event
|
||||
export let query: DocumentQuery<Event> | undefined = undefined
|
||||
export let options: FindOptions<Event> | undefined = undefined
|
||||
export let baseMenuClass: Ref<Class<Event>> | undefined = undefined
|
||||
export let config: (string | BuildModelKey)[]
|
||||
export let createComponent: AnyComponent | undefined = undefined
|
||||
export let createComponent: AnyComponent | undefined = calendar.component.CreateEvent
|
||||
export let allowedModes: CalendarMode[] = [
|
||||
CalendarMode.Days,
|
||||
CalendarMode.Week,
|
||||
CalendarMode.Month,
|
||||
CalendarMode.Year
|
||||
]
|
||||
|
||||
const me = getCurrentAccount() as EmployeeAccount
|
||||
|
||||
const mondayStart = true
|
||||
let mode: CalendarMode = CalendarMode.Days
|
||||
let mode: CalendarMode = allowedModes.includes(CalendarMode.Days) ? CalendarMode.Days : allowedModes[0]
|
||||
|
||||
// Current selected day
|
||||
let currentDate: Date = new Date()
|
||||
let selectedDate: Date = new Date()
|
||||
|
||||
let raw: Event[] = []
|
||||
let objects: Event[] = []
|
||||
|
||||
function getFrom (date: Date, mode: CalendarMode): Timestamp {
|
||||
@ -90,7 +93,7 @@
|
||||
function getTo (date: Date, mode: CalendarMode): Timestamp {
|
||||
switch (mode) {
|
||||
case CalendarMode.Days: {
|
||||
return new Date(date).setDate(date.getDate() + 1)
|
||||
return new Date(date).setDate(date.getDate() + 4)
|
||||
}
|
||||
case CalendarMode.Day: {
|
||||
return new Date(date).setDate(date.getDate() + 1)
|
||||
@ -116,7 +119,7 @@
|
||||
let calendars: Calendar[] = []
|
||||
const offsetTZ = new Date().getTimezoneOffset() * 60 * 1000
|
||||
|
||||
calendarsQuery.query(calendar.class.Calendar, { createdBy: getCurrentAccount()._id }, (res) => {
|
||||
calendarsQuery.query(calendar.class.Calendar, { createdBy: me._id }, (res) => {
|
||||
calendars = res
|
||||
})
|
||||
|
||||
@ -124,25 +127,21 @@
|
||||
|
||||
async function update (
|
||||
_class: Ref<Class<Event>>,
|
||||
query: DocumentQuery<Event>,
|
||||
from: Timestamp,
|
||||
to: Timestamp,
|
||||
query: DocumentQuery<Event> | undefined,
|
||||
calendars: Calendar[],
|
||||
options?: FindOptions<Event>
|
||||
) {
|
||||
q.query<Event>(
|
||||
_class,
|
||||
{
|
||||
space: { $in: calendars.map((p) => p._id) },
|
||||
...query
|
||||
},
|
||||
query ?? { space: { $in: calendars.map((p) => p._id) } },
|
||||
(result) => {
|
||||
objects = getAllEvents(result, from, to)
|
||||
raw = result
|
||||
},
|
||||
{ sort: { date: SortingOrder.Ascending }, ...options }
|
||||
)
|
||||
}
|
||||
$: update(_class, query, from, to, calendars, options)
|
||||
$: update(_class, query, calendars, options)
|
||||
$: objects = getAllEvents(raw, from, to)
|
||||
|
||||
function inRange (start: Date, end: Date, startPeriod: Date, period: 'day' | 'hour'): boolean {
|
||||
const endPeriod =
|
||||
@ -211,9 +210,32 @@
|
||||
showPopup(createComponent, { date, withTime }, 'top')
|
||||
}
|
||||
|
||||
let indexes = new Map<Ref<Event>, number>()
|
||||
function getDdItem (mode: CalendarMode) {
|
||||
switch (mode) {
|
||||
case CalendarMode.Day:
|
||||
return { id: 'day', label: calendar.string.ModeDay, mode: CalendarMode.Day }
|
||||
case CalendarMode.Days:
|
||||
return { id: 'days', label: calendar.string.DueDays, mode: CalendarMode.Days, params: { days: 3 } }
|
||||
case CalendarMode.Week:
|
||||
return { id: 'week', label: calendar.string.ModeWeek, mode: CalendarMode.Week }
|
||||
case CalendarMode.Month:
|
||||
return { id: 'month', label: calendar.string.ModeMonth, mode: CalendarMode.Month }
|
||||
case CalendarMode.Year:
|
||||
return { id: 'year', label: calendar.string.ModeYear, mode: CalendarMode.Year }
|
||||
}
|
||||
}
|
||||
|
||||
const ddItems: {
|
||||
function getDdItems (allowedModes: CalendarMode[]): void {
|
||||
ddItems = []
|
||||
for (const mode of allowedModes) {
|
||||
ddItems.push(getDdItem(mode))
|
||||
}
|
||||
ddItems = ddItems
|
||||
}
|
||||
|
||||
$: getDdItems(allowedModes)
|
||||
|
||||
let ddItems: {
|
||||
id: string | number
|
||||
label: IntlString
|
||||
mode: CalendarMode
|
||||
@ -243,7 +265,7 @@
|
||||
const eventEnd = event.allDay ? event.dueDate + offsetTZ : event.dueDate
|
||||
if ((eventStart < lastDate && eventEnd > startDate) || (eventStart === eventEnd && eventStart === startDay)) {
|
||||
result.push({
|
||||
eventId: event.eventId,
|
||||
_id: event._id,
|
||||
allDay: event.allDay,
|
||||
date: eventStart,
|
||||
dueDate: eventEnd,
|
||||
@ -263,7 +285,7 @@
|
||||
const eventEnd = event.dueDate + offsetTZ
|
||||
if ((eventStart < ld && eventEnd > sd) || (eventStart === eventEnd && eventStart === sd)) {
|
||||
result.push({
|
||||
eventId: event.eventId,
|
||||
_id: event._id,
|
||||
allDay: event.allDay,
|
||||
date: eventStart,
|
||||
dueDate: eventEnd,
|
||||
@ -282,14 +304,16 @@
|
||||
<span>{currentDate.getFullYear()}</span>
|
||||
</div>
|
||||
<div class="flex-row-center gap-2">
|
||||
<DropdownLabelsIntl
|
||||
items={ddItems.map((it) => {
|
||||
return { id: it.id, label: it.label, params: it.params }
|
||||
})}
|
||||
size={'medium'}
|
||||
selected={ddItems.find((it) => it.mode === mode)?.id}
|
||||
on:selected={(e) => (mode = ddItems.find((it) => it.id === e.detail)?.mode ?? ddItems[0].mode)}
|
||||
/>
|
||||
{#if ddItems.length > 1}
|
||||
<DropdownLabelsIntl
|
||||
items={ddItems.map((it) => {
|
||||
return { id: it.id, label: it.label, params: it.params }
|
||||
})}
|
||||
size={'medium'}
|
||||
selected={ddItems.find((it) => it.mode === mode)?.id}
|
||||
on:selected={(e) => (mode = ddItems.find((it) => it.id === e.detail)?.mode ?? ddItems[0].mode)}
|
||||
/>
|
||||
{/if}
|
||||
<Button
|
||||
label={calendar.string.Today}
|
||||
on:click={() => {
|
||||
@ -328,18 +352,7 @@
|
||||
}}
|
||||
>
|
||||
<svelte:fragment slot="cell" let:date let:today let:selected let:wrongMonth>
|
||||
<Day
|
||||
events={findEvents(objects, date)}
|
||||
{date}
|
||||
{_class}
|
||||
{baseMenuClass}
|
||||
{options}
|
||||
{config}
|
||||
{today}
|
||||
{selected}
|
||||
{wrongMonth}
|
||||
{query}
|
||||
/>
|
||||
<Day events={findEvents(objects, date)} {date} {_class} {options} {today} {selected} {wrongMonth} {query} />
|
||||
</svelte:fragment>
|
||||
</YearCalendar>
|
||||
{:else if mode === CalendarMode.Month}
|
||||
@ -350,9 +363,7 @@
|
||||
{date}
|
||||
size={'huge'}
|
||||
{_class}
|
||||
{baseMenuClass}
|
||||
{options}
|
||||
{config}
|
||||
{today}
|
||||
{selected}
|
||||
{wrongMonth}
|
||||
@ -379,9 +390,10 @@
|
||||
bind:selectedDate
|
||||
bind:currentDate
|
||||
on:create={(e) => showCreateDialog(e.detail.date, e.detail.withTime)}
|
||||
on:drop
|
||||
>
|
||||
<svelte:fragment slot="event" let:id let:size>
|
||||
{@const event = objects.find((event) => event.eventId === id)}
|
||||
{@const event = objects.find((event) => event._id === id)}
|
||||
{#if event}
|
||||
<EventElement {event} {size} />
|
||||
{/if}
|
||||
@ -397,36 +409,16 @@
|
||||
bind:selectedDate
|
||||
bind:currentDate
|
||||
on:create={(e) => showCreateDialog(e.detail.date, e.detail.withTime)}
|
||||
on:drop
|
||||
>
|
||||
<svelte:fragment slot="event" let:id let:size>
|
||||
{@const event = objects.find((event) => event.eventId === id)}
|
||||
{@const event = objects.find((event) => event._id === id)}
|
||||
{#if event}
|
||||
<EventElement {event} {size} />
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</DayCalendar>
|
||||
{/key}
|
||||
{:else if mode === CalendarMode.Day}
|
||||
<WeekCalendar
|
||||
{mondayStart}
|
||||
displayedDaysCount={1}
|
||||
startFromWeekStart={false}
|
||||
cellHeight={'4.5rem'}
|
||||
bind:selectedDate
|
||||
bind:currentDate
|
||||
>
|
||||
<svelte:fragment slot="cell" let:date>
|
||||
<Hour
|
||||
events={findEvents(objects, date, true)}
|
||||
{date}
|
||||
bind:indexes
|
||||
wide
|
||||
on:create={(e) => {
|
||||
showCreateDialog(e.detail, true)
|
||||
}}
|
||||
/>
|
||||
</svelte:fragment>
|
||||
</WeekCalendar>
|
||||
{/if}
|
||||
|
||||
<!-- <div class="min-h-4 max-h-4 h-4 flex-no-shrink" /> -->
|
||||
|
@ -16,7 +16,7 @@
|
||||
import { Event } from '@hcengineering/calendar'
|
||||
import { DateRangeMode } from '@hcengineering/core'
|
||||
import { translate } from '@hcengineering/platform'
|
||||
import { DateRangePresenter, themeStore } from '@hcengineering/ui'
|
||||
import { DAY, DateRangePresenter, HOUR, MINUTE, themeStore } from '@hcengineering/ui'
|
||||
import calendar from '../plugin'
|
||||
|
||||
export let value: Event
|
||||
@ -36,11 +36,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
const SECOND = 1000
|
||||
const MINUTE = SECOND * 60
|
||||
const HOUR = MINUTE * 60
|
||||
const DAY = HOUR * 24
|
||||
|
||||
async function formatDueDate (interval: number): Promise<string> {
|
||||
let passed = interval
|
||||
if (interval < 0) passed = 0
|
||||
|
@ -16,7 +16,6 @@
|
||||
import { Event } from '@hcengineering/calendar'
|
||||
import { Class, Doc, DocumentQuery, FindOptions, Ref } from '@hcengineering/core'
|
||||
import { Label, addZero, getPlatformColorForTextDef, showPopup, themeStore, tooltip } from '@hcengineering/ui'
|
||||
import { BuildModelKey } from '@hcengineering/view'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import calendar from '../plugin'
|
||||
import EventsPopup from './EventsPopup.svelte'
|
||||
@ -28,8 +27,6 @@
|
||||
export let _class: Ref<Class<Doc>>
|
||||
export let query: DocumentQuery<Event> = {}
|
||||
export let options: FindOptions<Event> | undefined = undefined
|
||||
export let baseMenuClass: Ref<Class<Event>> | undefined = undefined
|
||||
export let config: (string | BuildModelKey)[]
|
||||
|
||||
export let today: boolean = false
|
||||
export let selected: boolean = false
|
||||
|
@ -32,10 +32,13 @@ import SaveEventReminder from './components/SaveEventReminder.svelte'
|
||||
import UpdateRecInstancePopup from './components/UpdateRecInstancePopup.svelte'
|
||||
import ReminderViewlet from './components/activity/ReminderViewlet.svelte'
|
||||
import CalendarIntegrationIcon from './components/icons/Calendar.svelte'
|
||||
import EventElement from './components/EventElement.svelte'
|
||||
import calendar from './plugin'
|
||||
import contact from '@hcengineering/contact'
|
||||
import { deleteObjects } from '@hcengineering/view-resources'
|
||||
|
||||
export { EventElement, CalendarView }
|
||||
|
||||
async function saveEventReminder (object: Doc): Promise<void> {
|
||||
showPopup(SaveEventReminder, { objectId: object._id, objectClass: object._class })
|
||||
}
|
||||
|
@ -35,7 +35,6 @@ export default mergeIds(calendarId, calendar, {
|
||||
ModeWeek: '' as IntlString,
|
||||
ModeMonth: '' as IntlString,
|
||||
ModeYear: '' as IntlString,
|
||||
Today: '' as IntlString,
|
||||
TableView: '' as IntlString,
|
||||
DueMinutes: '' as IntlString,
|
||||
DueHours: '' as IntlString,
|
||||
|
@ -123,6 +123,7 @@ const calendarPlugin = plugin(calendarId, {
|
||||
Calendar: '' as Ref<Doc>
|
||||
},
|
||||
component: {
|
||||
CalendarView: '' as AnyComponent,
|
||||
PersonsPresenter: '' as AnyComponent,
|
||||
Events: '' as AnyComponent,
|
||||
DateTimePresenter: '' as AnyComponent,
|
||||
@ -141,7 +142,8 @@ const calendarPlugin = plugin(calendarId, {
|
||||
NoParticipants: '' as IntlString,
|
||||
PersonsLabel: '' as IntlString,
|
||||
EventNumber: '' as IntlString,
|
||||
Reminders: '' as IntlString
|
||||
Reminders: '' as IntlString,
|
||||
Today: '' as IntlString
|
||||
},
|
||||
handler: {
|
||||
DisconnectHandler: '' as Handler
|
||||
|
@ -262,6 +262,8 @@ export function getAllEvents (events: Event[], from: Timestamp, to: Timestamp):
|
||||
const instancesMap: Map<string, ReccuringInstance[]> = new Map()
|
||||
for (const event of events) {
|
||||
if (event._class === calendar.class.Event) {
|
||||
if (from > event.dueDate) continue
|
||||
if (event.date > to) continue
|
||||
base.push(event)
|
||||
} else if (event._class === calendar.class.ReccuringEvent) {
|
||||
recur.push(event as ReccuringEvent)
|
||||
@ -276,7 +278,13 @@ export function getAllEvents (events: Event[], from: Timestamp, to: Timestamp):
|
||||
for (const rec of recur) {
|
||||
recurData.push(...getReccuringEventInstances(rec, instancesMap.get(rec.eventId) ?? [], from, to))
|
||||
}
|
||||
const res = [...base, ...recurData, ...instances]
|
||||
const res = [
|
||||
...base,
|
||||
...recurData,
|
||||
...instances.filter((p) => {
|
||||
return from <= p.dueDate && p.date <= to
|
||||
})
|
||||
]
|
||||
res.sort((a, b) => a.date - b.date)
|
||||
return res
|
||||
}
|
||||
|
@ -334,7 +334,7 @@
|
||||
span {
|
||||
margin-left: 0.5rem;
|
||||
font-weight: 400;
|
||||
font-size: 0.875rem;
|
||||
|
||||
line-height: 1.125rem;
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
import type { Contact } from '@hcengineering/contact'
|
||||
import type { Class, Doc, Ref, Timestamp } from '@hcengineering/core'
|
||||
import { Mixin } from '@hcengineering/core'
|
||||
import type { Asset, Plugin } from '@hcengineering/platform'
|
||||
import type { Asset, IntlString, Plugin } from '@hcengineering/platform'
|
||||
import { plugin } from '@hcengineering/platform'
|
||||
import type { KanbanTemplateSpace, SpaceWithStates, State, Task } from '@hcengineering/task'
|
||||
|
||||
@ -68,6 +68,9 @@ const lead = plugin(leadId, {
|
||||
mixin: {
|
||||
Customer: '' as Ref<Mixin<Customer>>
|
||||
},
|
||||
string: {
|
||||
ConfigLabel: '' as IntlString
|
||||
},
|
||||
icon: {
|
||||
Funnel: '' as Asset,
|
||||
Lead: '' as Asset,
|
||||
|
@ -16,7 +16,7 @@
|
||||
import { Event } from '@hcengineering/calendar'
|
||||
import type { Channel, Organization, Person } from '@hcengineering/contact'
|
||||
import type { AttachedData, AttachedDoc, Class, Doc, Mixin, Ref, Space, Timestamp } from '@hcengineering/core'
|
||||
import type { Asset, Plugin, Resource } from '@hcengineering/platform'
|
||||
import type { Asset, IntlString, Plugin, Resource } from '@hcengineering/platform'
|
||||
import { plugin } from '@hcengineering/platform'
|
||||
import { TagReference } from '@hcengineering/tags'
|
||||
import type { KanbanTemplateSpace, SpaceWithStates, State, Task } from '@hcengineering/task'
|
||||
@ -158,6 +158,9 @@ const recruit = plugin(recruitId, {
|
||||
component: {
|
||||
EditVacancy: '' as AnyComponent
|
||||
},
|
||||
string: {
|
||||
ConfigLabel: '' as IntlString
|
||||
},
|
||||
icon: {
|
||||
RecruitApplication: '' as Asset,
|
||||
Vacancy: '' as Asset,
|
||||
|
@ -12,19 +12,10 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts" context="module">
|
||||
const SECOND = 1000
|
||||
const MINUTE = SECOND * 60
|
||||
const HOUR = MINUTE * 60
|
||||
const DAY = HOUR * 24
|
||||
const MONTH = DAY * 30
|
||||
const YEAR = MONTH * 12
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { translate } from '@hcengineering/platform'
|
||||
import tracker from '../../plugin'
|
||||
import { themeStore } from '@hcengineering/ui'
|
||||
import { DAY, HOUR, MINUTE, MONTH, YEAR, themeStore } from '@hcengineering/ui'
|
||||
|
||||
export let value: number
|
||||
|
||||
|
@ -139,6 +139,7 @@ import ProjectSpacePresenter from './components/projects/ProjectSpacePresenter.s
|
||||
import { get } from 'svelte/store'
|
||||
|
||||
export { default as SubIssueList } from './components/issues/edit/SubIssueList.svelte'
|
||||
export { default as IssueStatusIcon } from './components/issues/IssueStatusIcon.svelte'
|
||||
|
||||
export { IssuePresenter, TitlePresenter }
|
||||
|
||||
|
@ -24,7 +24,6 @@ import {
|
||||
Markup,
|
||||
Ref,
|
||||
RelatedDocument,
|
||||
Space,
|
||||
Status,
|
||||
StatusCategory,
|
||||
Timestamp,
|
||||
@ -33,7 +32,7 @@ import {
|
||||
} from '@hcengineering/core'
|
||||
import { Asset, IntlString, Plugin, Resource, plugin } from '@hcengineering/platform'
|
||||
import { TagCategory, TagElement, TagReference } from '@hcengineering/tags'
|
||||
import { Task } from '@hcengineering/task'
|
||||
import { SpaceWithStates, Task } from '@hcengineering/task'
|
||||
import { AnyComponent, Location, ResolvedLocation } from '@hcengineering/ui'
|
||||
import { Action, ActionCategory, IconProps } from '@hcengineering/view'
|
||||
|
||||
@ -45,7 +44,7 @@ export interface IssueStatus extends Status {}
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface Project extends Space, IconProps {
|
||||
export interface Project extends SpaceWithStates, IconProps {
|
||||
identifier: string // Project identifier
|
||||
sequence: number
|
||||
defaultIssueStatus: Ref<IssueStatus>
|
||||
@ -451,6 +450,7 @@ export default plugin(trackerId, {
|
||||
Location: '' as Resource<(loc: Location) => Promise<ResolvedLocation | undefined>>
|
||||
},
|
||||
string: {
|
||||
ConfigLabel: '' as IntlString,
|
||||
NewRelatedIssue: '' as IntlString
|
||||
}
|
||||
})
|
||||
|
@ -53,9 +53,16 @@
|
||||
}
|
||||
|
||||
$: if (doc !== undefined) {
|
||||
getObjectPresenter(client, doc._class, { key: '' }).then((p) => {
|
||||
presenter = p
|
||||
})
|
||||
getObjectPresenter(client, doc._class, { key: '' })
|
||||
.then((p) => {
|
||||
presenter = p
|
||||
})
|
||||
.catch((p) => {
|
||||
console.log(objectId)
|
||||
console.log(_class)
|
||||
console.log(value)
|
||||
throw p
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user