mirror of
https://github.com/hcengineering/platform.git
synced 2024-11-25 19:58:30 +03:00
parent
5f0ba95cee
commit
0aafafb93e
@ -20,7 +20,8 @@ import {
|
||||
Event,
|
||||
ReccuringEvent,
|
||||
ReccuringInstance,
|
||||
RecurringRule
|
||||
RecurringRule,
|
||||
Visibility
|
||||
} from '@hcengineering/calendar'
|
||||
import { Contact } from '@hcengineering/contact'
|
||||
import { DateRangeMode, Domain, IndexKind, Markup, Ref, Timestamp } from '@hcengineering/core'
|
||||
@ -60,7 +61,7 @@ export const DOMAIN_CALENDAR = 'calendar' as Domain
|
||||
@Model(calendar.class.Calendar, core.class.Space)
|
||||
@UX(calendar.string.Calendar, calendar.icon.Calendar)
|
||||
export class TCalendar extends TSpaceWithStates implements Calendar {
|
||||
visibility!: 'public' | 'freeBusy' | 'private'
|
||||
visibility!: Visibility
|
||||
|
||||
sync?: boolean
|
||||
}
|
||||
@ -108,7 +109,7 @@ export class TEvent extends TAttachedDoc implements Event {
|
||||
|
||||
access!: 'freeBusyReader' | 'reader' | 'writer' | 'owner'
|
||||
|
||||
visibility?: 'public' | 'freeBusy' | 'private'
|
||||
visibility?: Visibility
|
||||
}
|
||||
|
||||
@Model(calendar.class.ReccuringEvent, calendar.class.Event)
|
||||
@ -117,6 +118,7 @@ export class TReccuringEvent extends TEvent implements ReccuringEvent {
|
||||
rules!: RecurringRule[]
|
||||
exdate!: Timestamp[]
|
||||
rdate!: Timestamp[]
|
||||
originalStartTime!: Timestamp
|
||||
}
|
||||
|
||||
@Model(calendar.class.ReccuringInstance, calendar.class.Event)
|
||||
|
@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { Calendar, Event } from '@hcengineering/calendar'
|
||||
import { Calendar, Event, ReccuringEvent } from '@hcengineering/calendar'
|
||||
import core, { Ref, TxOperations } from '@hcengineering/core'
|
||||
import { MigrateOperation, MigrationClient, MigrationUpgradeClient } from '@hcengineering/model'
|
||||
import calendar from './plugin'
|
||||
@ -76,10 +76,21 @@ async function migrateReminders (client: MigrationClient): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
async function fillOriginalStartTime (client: MigrationClient): Promise<void> {
|
||||
const events = await client.find<ReccuringEvent>(DOMAIN_CALENDAR, {
|
||||
_class: calendar.class.ReccuringEvent,
|
||||
originalStartTime: { $exists: false }
|
||||
})
|
||||
for (const event of events) {
|
||||
await client.update(DOMAIN_CALENDAR, { _id: event._id }, { originalStartTime: event.date })
|
||||
}
|
||||
}
|
||||
|
||||
export const calendarOperation: MigrateOperation = {
|
||||
async migrate (client: MigrationClient): Promise<void> {
|
||||
await fixEventDueDate(client)
|
||||
await migrateReminders(client)
|
||||
await fillOriginalStartTime(client)
|
||||
},
|
||||
async upgrade (client: MigrationUpgradeClient): Promise<void> {
|
||||
const tx = new TxOperations(client, core.account.System)
|
||||
|
@ -37,7 +37,6 @@ export default mergeIds(tagsId, tags, {
|
||||
ColorLabel: '' as IntlString,
|
||||
WeightLabel: '' as IntlString,
|
||||
TagReferenceLabel: '' as IntlString,
|
||||
TagLabel: '' as IntlString,
|
||||
TargetClassLabel: '' as IntlString,
|
||||
TargetCategoryLabel: '' as IntlString,
|
||||
TagReference: '' as IntlString,
|
||||
|
@ -38,6 +38,7 @@
|
||||
export let autoSelect = true
|
||||
export let iconWithEmoji: AnySvelteComponent | Asset | ComponentType | undefined = undefined
|
||||
export let defaultIcon: AnySvelteComponent | Asset | ComponentType | undefined = undefined
|
||||
export let readonly: boolean = false
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
@ -61,6 +62,7 @@
|
||||
{component}
|
||||
{componentProps}
|
||||
{autoSelect}
|
||||
{readonly}
|
||||
{iconWithEmoji}
|
||||
{defaultIcon}
|
||||
bind:value={space}
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
export let checked: boolean = false
|
||||
export let symbol: 'check' | 'minus' = 'check'
|
||||
export let size: 'small' | 'medium' = 'small'
|
||||
export let size: 'small' | 'medium' | 'large' = 'small'
|
||||
export let circle: boolean = false
|
||||
export let accented: boolean = false
|
||||
export let readonly = false
|
||||
@ -66,6 +66,10 @@
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
}
|
||||
&.large {
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
}
|
||||
&.circle {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
|
@ -27,6 +27,7 @@
|
||||
export let placeholder: IntlString
|
||||
export let items: ListItem[] = []
|
||||
export let selected: ListItem | undefined = undefined
|
||||
export let disabled: boolean = false
|
||||
|
||||
export let kind: ButtonKind = 'no-border'
|
||||
export let size: ButtonSize = 'small'
|
||||
@ -35,6 +36,8 @@
|
||||
export let labelDirection: TooltipAlignment | undefined = undefined
|
||||
export let focusIndex = -1
|
||||
|
||||
export let withSearch: boolean = true
|
||||
|
||||
let container: HTMLElement
|
||||
let opened: boolean = false
|
||||
|
||||
@ -45,16 +48,18 @@
|
||||
<div bind:this={container} class="min-w-0">
|
||||
<Button
|
||||
{focusIndex}
|
||||
{icon}
|
||||
icon={selected?.icon ?? icon}
|
||||
iconProps={selected?.iconProps}
|
||||
width={width ?? 'min-content'}
|
||||
{size}
|
||||
{kind}
|
||||
{justify}
|
||||
{disabled}
|
||||
showTooltip={{ label, direction: labelDirection }}
|
||||
on:click={() => {
|
||||
if (!opened) {
|
||||
opened = true
|
||||
showPopup(DropdownPopup, { title: label, items, icon }, container, (result) => {
|
||||
showPopup(DropdownPopup, { title: label, items, icon, withSearch }, container, (result) => {
|
||||
if (result) {
|
||||
selected = result
|
||||
dispatch('selected', result)
|
||||
|
@ -26,6 +26,7 @@
|
||||
export let icon: Asset | AnySvelteComponent
|
||||
export let placeholder: IntlString = plugin.string.SearchDots
|
||||
export let items: ListItem[]
|
||||
export let withSearch: boolean = true
|
||||
|
||||
let search: string = ''
|
||||
let phTraslate: string = ''
|
||||
@ -74,16 +75,18 @@
|
||||
</script>
|
||||
|
||||
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')} on:keydown={onKeydown}>
|
||||
<div class="header">
|
||||
<input
|
||||
bind:this={searchInput}
|
||||
type="text"
|
||||
bind:value={search}
|
||||
placeholder={phTraslate}
|
||||
on:input={(ev) => {}}
|
||||
on:change
|
||||
/>
|
||||
</div>
|
||||
{#if withSearch}
|
||||
<div class="header">
|
||||
<input
|
||||
bind:this={searchInput}
|
||||
type="text"
|
||||
bind:value={search}
|
||||
placeholder={phTraslate}
|
||||
on:input={(ev) => {}}
|
||||
on:change
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="scroll">
|
||||
<div class="box">
|
||||
<ListView bind:this={list} count={objects.length} bind:selection>
|
||||
@ -97,10 +100,12 @@
|
||||
handleSelection(evt, idx)
|
||||
}}
|
||||
>
|
||||
{#if item.image || icon}
|
||||
{#if item.image || item.icon || icon}
|
||||
<div class="flex-center img" class:image={item.image}>
|
||||
{#if item.image}
|
||||
<img src={item.image} alt={item.label} />
|
||||
{:else if item.icon}
|
||||
<Icon icon={item.icon} size={'medium'} iconProps={item.iconProps} />
|
||||
{:else if typeof icon === 'string'}
|
||||
<Icon {icon} size={'small'} />
|
||||
{:else}
|
||||
@ -119,17 +124,17 @@
|
||||
<style lang="scss">
|
||||
.img {
|
||||
margin-right: 0.75rem;
|
||||
flex-shrink: 0;
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.image {
|
||||
border-color: transparent;
|
||||
color: var(--caption-color);
|
||||
background-color: var(--popup-bg-hover);
|
||||
border-radius: 50%;
|
||||
outline: none;
|
||||
overflow: hidden;
|
||||
}
|
||||
.image {
|
||||
border-color: transparent;
|
||||
img {
|
||||
max-width: fit-content;
|
||||
}
|
||||
|
13
packages/ui/src/components/icons/CircleAdd.svelte
Normal file
13
packages/ui/src/components/icons/CircleAdd.svelte
Normal file
@ -0,0 +1,13 @@
|
||||
<script lang="ts">
|
||||
export let size: 'x-small' | 'small' | 'medium' | 'large'
|
||||
export let fill: string = 'currentColor'
|
||||
</script>
|
||||
|
||||
<svg class="svg-{size}" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" {fill}>
|
||||
<path
|
||||
d="M8 2C11.3 2 14 4.7 14 8C14 11.3 11.3 14 8 14C4.7 14 2 11.3 2 8C2 4.7 4.7 2 8 2ZM8 1C4.15 1 1 4.15 1 8C1 11.85 4.15 15 8 15C11.85 15 15 11.85 15 8C15 4.15 11.85 1 8 1Z"
|
||||
/>
|
||||
<path
|
||||
d="M12 8C12 7.72386 11.7761 7.5 11.5 7.5L8.5 7.5V4.5C8.5 4.22386 8.27614 4 8 4C7.72386 4 7.5 4.22386 7.5 4.5V7.5H4.5C4.22386 7.5 4 7.72386 4 8C4 8.27614 4.22386 8.5 4.5 8.5H7.5L7.5 11.5C7.5 11.7761 7.72386 12 8 12C8.27614 12 8.5 11.7761 8.5 11.5V8.5H11.5C11.7761 8.5 12 8.27614 12 8Z"
|
||||
/>
|
||||
</svg>
|
@ -101,6 +101,7 @@ export { default as DropdownPopup } from './components/DropdownPopup.svelte'
|
||||
export { default as DropdownLabels } from './components/DropdownLabels.svelte'
|
||||
export { default as DropdownLabelsPopup } from './components/DropdownLabelsPopup.svelte'
|
||||
export { default as DropdownLabelsIntl } from './components/DropdownLabelsIntl.svelte'
|
||||
export { default as DropdownLabelsPopupIntl } from './components/DropdownLabelsPopupIntl.svelte'
|
||||
export { default as DropdownRecord } from './components/DropdownRecord.svelte'
|
||||
export { default as ShowMore } from './components/ShowMore.svelte'
|
||||
export { default as Menu } from './components/Menu.svelte'
|
||||
@ -115,6 +116,7 @@ export { default as Timeline } from './components/Timeline.svelte'
|
||||
export { default as TimeShiftPresenter } from './components/TimeShiftPresenter.svelte'
|
||||
|
||||
export { default as IconAdd } from './components/icons/Add.svelte'
|
||||
export { default as IconCircleAdd } from './components/icons/CircleAdd.svelte'
|
||||
export { default as IconCopy } from './components/icons/Copy.svelte'
|
||||
export { default as IconStart } from './components/icons/Start.svelte'
|
||||
export { default as IconStop } from './components/icons/Stop.svelte'
|
||||
|
@ -280,6 +280,8 @@ export interface LabelAndProps {
|
||||
export interface ListItem {
|
||||
_id: string
|
||||
label: string
|
||||
icon?: Asset
|
||||
iconProps?: any
|
||||
image?: string
|
||||
isSelectable?: boolean
|
||||
fontWeight?: 'normal' | 'medium' | 'semi-bold'
|
||||
|
@ -37,4 +37,11 @@
|
||||
<symbol id="globe" viewBox="0 0 32 32">
|
||||
<path d="M16 2.00024C13.2311 2.00024 10.5243 2.82133 8.22202 4.35967C5.91973 5.89801 4.12532 8.08451 3.06569 10.6427C2.00607 13.2008 1.72882 16.0158 2.26901 18.7315C2.80921 21.4472 4.14258 23.9418 6.10051 25.8997C8.05845 27.8577 10.553 29.191 13.2687 29.7312C15.9845 30.2714 18.7994 29.9942 21.3576 28.9346C23.9157 27.8749 26.1022 26.0805 27.6406 23.7782C29.1789 21.4759 30 18.7692 30 16.0002C30 12.2872 28.525 8.72626 25.8995 6.10075C23.274 3.47524 19.713 2.00024 16 2.00024ZM28 15.0002H22C21.8833 11.3173 20.9291 7.70939 19.21 4.45024C21.5786 5.09814 23.6914 6.45709 25.2632 8.34367C26.8351 10.2302 27.7903 12.5536 28 15.0002ZM16 28.0002C15.7769 28.0152 15.5531 28.0152 15.33 28.0002C13.2583 24.6964 12.1085 20.8984 12 17.0002H20C19.9005 20.8956 18.7612 24.6934 16.7 28.0002C16.467 28.0166 16.2331 28.0166 16 28.0002ZM12 15.0002C12.0995 11.1049 13.2388 7.30707 15.3 4.00024C15.7453 3.95021 16.1947 3.95021 16.64 4.00024C18.7223 7.30104 19.8825 11.0993 20 15.0002H12ZM12.76 4.45024C11.0513 7.71189 10.1075 11.3197 10 15.0002H4.00001C4.20971 12.5536 5.16495 10.2302 6.7368 8.34367C8.30865 6.45709 10.4214 5.09814 12.79 4.45024H12.76ZM4.05001 17.0002H10.05C10.1544 20.68 11.0948 24.2878 12.8 27.5502C10.4389 26.8954 8.33478 25.5334 6.77056 23.6474C5.20634 21.7614 4.25695 19.4418 4.05001 17.0002ZM19.21 27.5502C20.9291 24.2911 21.8833 20.6832 22 17.0002H28C27.7903 19.4469 26.8351 21.7702 25.2632 23.6568C23.6914 25.5434 21.5786 26.9023 19.21 27.5502Z" />
|
||||
</symbol>
|
||||
<symbol id="private" viewBox="0 0 16 16" fill="none">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 1.99999C6.89543 1.99999 6 2.89542 6 3.99998V6.99995H10V3.99998C10 2.89542 9.10457 1.99999 8 1.99999ZM11 6.99995V3.99998C11 2.34314 9.65685 1 8 1C6.34315 1 5 2.34314 5 3.99998V6.99995C3.89543 6.99995 3 7.89538 3 8.99994V12.9999C3 14.1045 3.89543 14.9999 5 14.9999H11C12.1046 14.9999 13 14.1045 13 12.9999V8.99994C13 7.89538 12.1046 6.99995 11 6.99995ZM5 7.99995C4.44772 7.99995 4 8.44766 4 8.99994V12.9999C4 13.5522 4.44772 13.9999 5 13.9999H11C11.5523 13.9999 12 13.5522 12 12.9999V8.99994C12 8.44766 11.5523 7.99995 11 7.99995H5Z" fill="currentColor"/>
|
||||
</symbol>
|
||||
<symbol id="public" viewBox="0 0 16 16" fill="none">
|
||||
<path d="M15.4698 7.83C14.8817 6.30882 13.8608 4.99331 12.5332 4.04604C11.2056 3.09878 9.62953 2.56129 7.99979 2.5C6.37005 2.56129 4.79398 3.09878 3.46639 4.04604C2.1388 4.99331 1.11787 6.30882 0.529787 7.83C0.490071 7.93985 0.490071 8.06015 0.529787 8.17C1.11787 9.69118 2.1388 11.0067 3.46639 11.954C4.79398 12.9012 6.37005 13.4387 7.99979 13.5C9.62953 13.4387 11.2056 12.9012 12.5332 11.954C13.8608 11.0067 14.8817 9.69118 15.4698 8.17C15.5095 8.06015 15.5095 7.93985 15.4698 7.83ZM7.99979 12.5C5.34979 12.5 2.54979 10.535 1.53479 8C2.54979 5.465 5.34979 3.5 7.99979 3.5C10.6498 3.5 13.4498 5.465 14.4648 8C13.4498 10.535 10.6498 12.5 7.99979 12.5Z" fill="currentColor"/>
|
||||
<path d="M7.99979 5C7.40644 5 6.82642 5.17595 6.33308 5.50559C5.83973 5.83524 5.45521 6.30377 5.22815 6.85195C5.00109 7.40013 4.94168 8.00333 5.05743 8.58527C5.17319 9.16721 5.45891 9.70176 5.87847 10.1213C6.29802 10.5409 6.83257 10.8266 7.41452 10.9424C7.99646 11.0581 8.59966 10.9987 9.14784 10.7716C9.69602 10.5446 10.1646 10.1601 10.4942 9.66671C10.8238 9.17336 10.9998 8.59334 10.9998 8C10.9998 7.20435 10.6837 6.44129 10.1211 5.87868C9.5585 5.31607 8.79544 5 7.99979 5ZM7.99979 10C7.60422 10 7.21755 9.8827 6.88865 9.66294C6.55975 9.44318 6.3034 9.13082 6.15203 8.76537C6.00065 8.39991 5.96105 7.99778 6.03822 7.60982C6.11539 7.22186 6.30587 6.86549 6.58557 6.58579C6.86528 6.30608 7.22164 6.1156 7.60961 6.03843C7.99757 5.96126 8.3997 6.00087 8.76515 6.15224C9.13061 6.30362 9.44296 6.55996 9.66273 6.88886C9.88249 7.21776 9.99979 7.60444 9.99979 8C9.99979 8.53043 9.78907 9.03914 9.414 9.41421C9.03893 9.78929 8.53022 10 7.99979 10Z" fill="currentColor"/>
|
||||
</symbol>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 13 KiB |
@ -78,6 +78,10 @@
|
||||
"Busy": "Busy",
|
||||
"AddReminder": "Add reminder",
|
||||
"SeeAllNumberParticipants": "{value, plural, other {See all # participants}}",
|
||||
"SeeAllNumberReminders": "{value, plural, other {See all # reminders}}"
|
||||
"SeeAllNumberReminders": "{value, plural, other {See all # reminders}}",
|
||||
"Visibility": "Visibility",
|
||||
"Private": "Only visible to you",
|
||||
"Public": "Visible to everyone",
|
||||
"FreeBusy": "FreeBusy"
|
||||
}
|
||||
}
|
@ -78,6 +78,10 @@
|
||||
"Busy": "Занято",
|
||||
"AddReminder": "Добавить напоминание",
|
||||
"SeeAllNumberParticipants": "{value, plural, other {Увидеть всех # участников}}",
|
||||
"SeeAllNumberReminders": "{value, plural, other {Просмотреть все # напоминаний}}"
|
||||
"SeeAllNumberReminders": "{value, plural, other {Просмотреть все # напоминаний}}",
|
||||
"Visibility": "Видимость",
|
||||
"Private": "Видно только Вам",
|
||||
"Public": "Видно всем",
|
||||
"FreeBusy": "Скрыть детали"
|
||||
}
|
||||
}
|
@ -26,7 +26,9 @@ loadMetadata(calendar.icon, {
|
||||
Description: `${icons}#description`,
|
||||
Participants: `${icons}#participants`,
|
||||
Repeat: `${icons}#repeat`,
|
||||
Globe: `${icons}#globe`
|
||||
Globe: `${icons}#globe`,
|
||||
Private: `${icons}#private`,
|
||||
Public: `${icons}#public`
|
||||
})
|
||||
|
||||
addStringsLoader(calendarId, async (lang: string) => await import(`../lang/${lang}.json`))
|
||||
|
@ -82,7 +82,8 @@
|
||||
participants,
|
||||
title,
|
||||
allDay,
|
||||
access: 'owner'
|
||||
access: 'owner',
|
||||
originalStartTime: allDay ? saveUTC(date) : date
|
||||
})
|
||||
} else {
|
||||
await client.addCollection(calendar.class.Event, space, attachedTo, attachedToClass, 'events', {
|
||||
|
@ -14,7 +14,7 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Event, ReccuringInstance } from '@hcengineering/calendar'
|
||||
import { Timestamp, Ref, DocumentUpdate } from '@hcengineering/core'
|
||||
import { DocumentUpdate, Ref, Timestamp } from '@hcengineering/core'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import ui, {
|
||||
ActionIcon,
|
||||
@ -29,16 +29,16 @@
|
||||
closeTooltip,
|
||||
deviceOptionsStore as deviceInfo,
|
||||
day as getDay,
|
||||
getEventPositionElement,
|
||||
getMonday,
|
||||
getWeekDayName,
|
||||
resizeObserver,
|
||||
showPopup,
|
||||
getEventPositionElement
|
||||
showPopup
|
||||
} from '@hcengineering/ui'
|
||||
import { Menu } from '@hcengineering/view-resources'
|
||||
import { createEventDispatcher, onDestroy, onMount } from 'svelte'
|
||||
import calendar from '../plugin'
|
||||
import { updateReccuringInstance, isReadOnly } from '../utils'
|
||||
import { isReadOnly, updateReccuringInstance } from '../utils'
|
||||
import EventElement from './EventElement.svelte'
|
||||
|
||||
export let events: Event[]
|
||||
@ -563,7 +563,11 @@
|
||||
if (originDueDate !== event.dueDate) update.dueDate = event.dueDate
|
||||
if (Object.keys(update).length > 0) {
|
||||
if (event._class === calendar.class.ReccuringInstance) {
|
||||
await updateReccuringInstance(update, event as ReccuringInstance)
|
||||
await updateReccuringInstance(update, {
|
||||
...event,
|
||||
date: originDate,
|
||||
dueDate: originDueDate
|
||||
} as ReccuringInstance)
|
||||
} else {
|
||||
await client.update(event, update)
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
import { Icon, areDatesEqual, IconArrowRight } from '@hcengineering/ui'
|
||||
import calendar from '../plugin'
|
||||
import DateEditor from './DateEditor.svelte'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
|
||||
export let startDate: number
|
||||
export let dueDate: number
|
||||
@ -26,10 +27,12 @@
|
||||
|
||||
let diff = dueDate - startDate
|
||||
const allDayDuration = 24 * 60 * 60 * 1000 - 1
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
function dateChange () {
|
||||
startDate = allDay ? new Date(startDate).setHours(0, 0, 0, 0) : startDate
|
||||
dueDate = startDate + (allDay ? allDayDuration : diff)
|
||||
dispatch('change', { startDate, dueDate })
|
||||
}
|
||||
|
||||
function dueChange () {
|
||||
@ -40,6 +43,7 @@
|
||||
dueDate = startDate + (allDay ? allDayDuration : diff)
|
||||
}
|
||||
diff = dueDate - startDate
|
||||
dispatch('dueChange', { dueDate })
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -111,7 +111,6 @@
|
||||
<div class="repeatPopup-container">
|
||||
<div class="header">
|
||||
<Label label={calendar.string.Repeat} />
|
||||
{selected}
|
||||
</div>
|
||||
<div class="content flex-col">
|
||||
<div class="flex-row-center gap-1-5">
|
||||
|
@ -159,6 +159,14 @@ export async function updateReccuringInstance (
|
||||
eventId: object.recurringEventId
|
||||
})
|
||||
if (base !== undefined) {
|
||||
if (ops.date !== undefined) {
|
||||
const diff = object.date - ops.date
|
||||
ops.date = base.date - diff
|
||||
}
|
||||
if (ops.dueDate !== undefined) {
|
||||
const diff = object.dueDate - ops.dueDate
|
||||
ops.dueDate = base.dueDate - diff
|
||||
}
|
||||
await client.update(base, ops)
|
||||
}
|
||||
} else if (res.mode === 'next') {
|
||||
|
@ -19,12 +19,19 @@ import { plugin } from '@hcengineering/platform'
|
||||
import type { Handler, IntegrationType } from '@hcengineering/setting'
|
||||
import { AnyComponent } from '@hcengineering/ui'
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type Visibility = 'public' | 'freeBusy' | 'private'
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface Calendar extends Space {
|
||||
visibility: 'public' | 'freeBusy' | 'private'
|
||||
visibility: Visibility
|
||||
sync?: boolean
|
||||
externalId?: string
|
||||
externalUser?: string
|
||||
}
|
||||
|
||||
/**
|
||||
@ -55,6 +62,7 @@ export interface ReccuringEvent extends Event {
|
||||
rules: RecurringRule[]
|
||||
exdate: Timestamp[]
|
||||
rdate: Timestamp[]
|
||||
originalStartTime: Timestamp
|
||||
}
|
||||
|
||||
/**
|
||||
@ -84,7 +92,7 @@ export interface Event extends AttachedDoc {
|
||||
|
||||
reminders?: Timestamp[]
|
||||
|
||||
visibility?: 'public' | 'freeBusy' | 'private'
|
||||
visibility?: Visibility
|
||||
|
||||
access: 'freeBusyReader' | 'reader' | 'writer' | 'owner'
|
||||
}
|
||||
@ -134,7 +142,9 @@ const calendarPlugin = plugin(calendarId, {
|
||||
Description: '' as Asset,
|
||||
Participants: '' as Asset,
|
||||
Repeat: '' as Asset,
|
||||
Globe: '' as Asset
|
||||
Globe: '' as Asset,
|
||||
Public: '' as Asset,
|
||||
Private: '' as Asset
|
||||
},
|
||||
space: {
|
||||
// deprecated
|
||||
@ -166,7 +176,11 @@ const calendarPlugin = plugin(calendarId, {
|
||||
PersonsLabel: '' as IntlString,
|
||||
EventNumber: '' as IntlString,
|
||||
Reminders: '' as IntlString,
|
||||
Today: '' as IntlString
|
||||
Today: '' as IntlString,
|
||||
Visibility: '' as IntlString,
|
||||
Public: '' as IntlString,
|
||||
FreeBusy: '' as IntlString,
|
||||
Private: '' as IntlString
|
||||
},
|
||||
handler: {
|
||||
DisconnectHandler: '' as Handler
|
||||
|
@ -285,7 +285,7 @@ function getReccuringEventInstances (
|
||||
const excludes = new Set(event.exdate ?? [])
|
||||
res = res.filter((p) => !excludes.has(p.date))
|
||||
res = res.filter((i) => {
|
||||
const override = instances.find((p) => p.originalStartTime === i.date)
|
||||
const override = instances.find((p) => p.originalStartTime === i.originalStartTime)
|
||||
return override === undefined
|
||||
})
|
||||
return res
|
||||
|
@ -11,6 +11,7 @@
|
||||
"AddTagTooltip": "Add/Create {word}",
|
||||
"AddNowTooltip": "Create {word}",
|
||||
"AddTag": "Create {word}",
|
||||
"AddLabel": "Add label",
|
||||
"EditTag": "Edit {word}",
|
||||
"TagCreateLabel": "Tag",
|
||||
"CancelLabel": "Cancel",
|
||||
|
@ -11,6 +11,7 @@
|
||||
"AddTagTooltip": "Добавить/создать {word}",
|
||||
"AddNowTooltip": "Создать {word}",
|
||||
"AddTag": "Создать {word}",
|
||||
"AddLabel": "Добавить метку",
|
||||
"EditTag": "Редактировать {word}",
|
||||
"TagCreateLabel": "Тег",
|
||||
"CancelLabel": "Отмена",
|
||||
|
74
plugins/tags-resources/src/components/DocTagsEditor.svelte
Normal file
74
plugins/tags-resources/src/components/DocTagsEditor.svelte
Normal file
@ -0,0 +1,74 @@
|
||||
<!--
|
||||
// Copyright © 2023 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 { Class, Doc, Ref } from '@hcengineering/core'
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import tags, { TagReference } from '@hcengineering/tags'
|
||||
import { Button, ButtonKind, Icon, Label, getEventPopupPositionElement, showPopup } from '@hcengineering/ui'
|
||||
import tagsPlugin from '../plugin'
|
||||
import TagReferencePresenter from './TagReferencePresenter.svelte'
|
||||
import TagsEditorPopup from './TagsEditorPopup.svelte'
|
||||
import TagIcon from './icons/TagIcon.svelte'
|
||||
|
||||
export let object: Doc
|
||||
export let targetClass: Ref<Class<Doc>>
|
||||
export let kind: ButtonKind = 'ghost'
|
||||
|
||||
let items: TagReference[] = []
|
||||
const query = createQuery()
|
||||
const client = getClient()
|
||||
|
||||
$: query.query(tags.class.TagReference, { attachedTo: object._id }, (result) => {
|
||||
items = result
|
||||
})
|
||||
|
||||
async function click (evt: MouseEvent): Promise<void> {
|
||||
showPopup(TagsEditorPopup, { object, targetClass }, getEventPopupPositionElement(evt))
|
||||
}
|
||||
|
||||
async function removeTag (tag: TagReference): Promise<void> {
|
||||
if (tag !== undefined) await client.remove(tag)
|
||||
}
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<Button {kind} padding={'0rem;'} on:click={click}>
|
||||
<div slot="content" class="flex-row-center flex-gap-1">
|
||||
<Icon icon={TagIcon} size={'medium'} />
|
||||
<span class="overflow-label label"><Label label={tagsPlugin.string.AddLabel} /></span>
|
||||
</div>
|
||||
</Button>
|
||||
{#if items.length}
|
||||
<div class="flex-row-center flex-wrap">
|
||||
{#each items as value}
|
||||
<div class="step-container clear-mins">
|
||||
<TagReferencePresenter
|
||||
attr={undefined}
|
||||
isEditable
|
||||
{value}
|
||||
kind={'list'}
|
||||
on:remove={(res) => removeTag(res.detail)}
|
||||
/>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.step-container {
|
||||
margin: 0.375rem 0.375rem 0 0;
|
||||
}
|
||||
</style>
|
72
plugins/tags-resources/src/components/DraftTagsEditor.svelte
Normal file
72
plugins/tags-resources/src/components/DraftTagsEditor.svelte
Normal file
@ -0,0 +1,72 @@
|
||||
<!--
|
||||
// Copyright © 2023 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 { Class, Doc, Ref } from '@hcengineering/core'
|
||||
import { TagReference } from '@hcengineering/tags'
|
||||
import { Button, ButtonKind, Icon, Label, getEventPopupPositionElement, showPopup } from '@hcengineering/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import tagsPlugin from '../plugin'
|
||||
import DraftTagsPopup from './DraftTagsPopup.svelte'
|
||||
import TagReferencePresenter from './TagReferencePresenter.svelte'
|
||||
import TagIcon from './icons/TagIcon.svelte'
|
||||
|
||||
export let tags: TagReference[] = []
|
||||
export let targetClass: Ref<Class<Doc>>
|
||||
export let kind: ButtonKind = 'ghost'
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
function removeTag (tag: TagReference) {
|
||||
tags = tags.filter((t) => t !== tag)
|
||||
dispatch('change', tags)
|
||||
}
|
||||
|
||||
function click (evt: MouseEvent) {
|
||||
showPopup(DraftTagsPopup, { targetClass, tags }, getEventPopupPositionElement(evt), undefined, (res) => {
|
||||
tags = res
|
||||
dispatch('change', tags)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<Button {kind} padding={'0rem;'} on:click={click}>
|
||||
<div slot="content" class="flex-row-center flex-gap-1">
|
||||
<Icon icon={TagIcon} size={'medium'} />
|
||||
<span class="overflow-label label"><Label label={tagsPlugin.string.AddLabel} /></span>
|
||||
</div>
|
||||
</Button>
|
||||
{#if tags.length}
|
||||
<div class="flex-row-center flex-wrap">
|
||||
{#each tags as value}
|
||||
<div class="step-container clear-mins">
|
||||
<TagReferencePresenter
|
||||
attr={undefined}
|
||||
isEditable
|
||||
{value}
|
||||
kind={'list'}
|
||||
on:remove={(res) => removeTag(res.detail)}
|
||||
/>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.step-container {
|
||||
margin: 0.375rem 0.375rem 0 0;
|
||||
}
|
||||
</style>
|
51
plugins/tags-resources/src/components/DraftTagsPopup.svelte
Normal file
51
plugins/tags-resources/src/components/DraftTagsPopup.svelte
Normal file
@ -0,0 +1,51 @@
|
||||
<!--
|
||||
// Copyright © 2023 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 { AttachedData, Class, Doc, Ref } from '@hcengineering/core'
|
||||
import { TagElement, TagReference } from '@hcengineering/tags'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import TagsPopup from './TagsPopup.svelte'
|
||||
|
||||
export let targetClass: Ref<Class<Doc>>
|
||||
export let tags: AttachedData<TagReference>[] = []
|
||||
|
||||
$: selected = tags.map((p) => p.tag)
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
async function addRef ({ title, color, _id: tag }: TagElement): Promise<void> {
|
||||
tags.push({
|
||||
tag,
|
||||
title,
|
||||
color
|
||||
})
|
||||
tags = tags
|
||||
dispatch('update', tags)
|
||||
}
|
||||
|
||||
async function removeTag (tag: TagElement): Promise<void> {
|
||||
tags = tags.filter((t) => t.tag !== tag._id)
|
||||
tags = tags
|
||||
dispatch('update', tags)
|
||||
}
|
||||
|
||||
async function onUpdate (event: CustomEvent<{ action: string; tag: TagElement }>) {
|
||||
const result = event.detail
|
||||
if (result === undefined) return
|
||||
if (result.action === 'add') addRef(result.tag)
|
||||
else if (result.action === 'remove') removeTag(result.tag)
|
||||
}
|
||||
</script>
|
||||
|
||||
<TagsPopup {targetClass} {selected} on:update={onUpdate} />
|
36
plugins/tags-resources/src/components/TagElement.svelte
Normal file
36
plugins/tags-resources/src/components/TagElement.svelte
Normal file
@ -0,0 +1,36 @@
|
||||
<!--
|
||||
// Copyright © 2023 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 { TagElement } from '@hcengineering/tags'
|
||||
import { getPlatformColorDef, themeStore } from '@hcengineering/ui'
|
||||
|
||||
export let element: TagElement
|
||||
|
||||
$: color = getPlatformColorDef(element.color ?? 0, $themeStore.dark)
|
||||
</script>
|
||||
|
||||
<div class="color" style:background-color={color.color} />
|
||||
<span class="label overflow-label ml-1-5 max-w-40">
|
||||
{element.title}
|
||||
</span>
|
||||
|
||||
<style lang="scss">
|
||||
.color {
|
||||
flex-shrink: 0;
|
||||
width: 0.5rem;
|
||||
height: 0.5rem;
|
||||
border-radius: 50%;
|
||||
}
|
||||
</style>
|
@ -1,17 +1,19 @@
|
||||
<script lang="ts">
|
||||
import { AnyAttribute, Doc } from '@hcengineering/core'
|
||||
import { AnyAttribute, Class, Doc, Ref } from '@hcengineering/core'
|
||||
import { IntlString } from '@hcengineering/platform'
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import type { TagReference } from '@hcengineering/tags'
|
||||
import tags from '@hcengineering/tags'
|
||||
import { Icon, IconAdd, Label, getEventPopupPositionElement, showPopup } from '@hcengineering/ui'
|
||||
import { Icon, Label, getEventPopupPositionElement, showPopup } from '@hcengineering/ui'
|
||||
import TagReferencePresenter from './TagReferencePresenter.svelte'
|
||||
import TagsEditorPopup from './TagsEditorPopup.svelte'
|
||||
import TagIcon from './icons/TagIcon.svelte'
|
||||
|
||||
export let object: Doc
|
||||
export let label: IntlString
|
||||
export let label: IntlString = tags.string.AddLabel
|
||||
export let readonly: boolean = false
|
||||
export let attr: AnyAttribute | undefined = undefined
|
||||
export let targetClass: Ref<Class<Doc>> = object._class
|
||||
|
||||
let items: TagReference[] = []
|
||||
const query = createQuery()
|
||||
@ -22,7 +24,7 @@
|
||||
})
|
||||
async function tagsHandler (evt: MouseEvent): Promise<void> {
|
||||
if (readonly) return
|
||||
showPopup(TagsEditorPopup, { object }, getEventPopupPositionElement(evt))
|
||||
showPopup(TagsEditorPopup, { object, targetClass }, getEventPopupPositionElement(evt))
|
||||
}
|
||||
async function removeTag (tag: TagReference): Promise<void> {
|
||||
if (tag !== undefined) await client.remove(tag)
|
||||
@ -45,7 +47,7 @@
|
||||
{#if !readonly}
|
||||
<div class="step-container clear-mins">
|
||||
<button class="tag-button" on:click|stopPropagation={tagsHandler}>
|
||||
<div class="icon"><Icon icon={IconAdd} size={'full'} /></div>
|
||||
<div class="icon"><Icon icon={TagIcon} size={'full'} /></div>
|
||||
<span class="overflow-label label"><Label {label} /></span>
|
||||
</button>
|
||||
</div>
|
||||
@ -53,7 +55,7 @@
|
||||
</div>
|
||||
{:else if !readonly}
|
||||
<button class="tag-button" style="width: min-content" on:click|stopPropagation={tagsHandler}>
|
||||
<div class="icon"><Icon icon={IconAdd} size={'full'} /></div>
|
||||
<div class="icon"><Icon icon={TagIcon} size={'full'} /></div>
|
||||
<span class="overflow-label label"><Label {label} /></span>
|
||||
</button>
|
||||
{/if}
|
||||
|
@ -13,12 +13,13 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Doc, Ref } from '@hcengineering/core'
|
||||
import { Class, Doc, Ref } from '@hcengineering/core'
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import tags, { TagElement } from '@hcengineering/tags'
|
||||
import TagsPopup from './TagsPopup.svelte'
|
||||
|
||||
export let object: Doc
|
||||
export let targetClass: Ref<Class<Doc>> = object._class
|
||||
|
||||
let selected: Ref<TagElement>[] = []
|
||||
const query = createQuery()
|
||||
@ -45,4 +46,4 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<TagsPopup targetClass={object._class} {selected} on:update={onUpdate} />
|
||||
<TagsPopup {targetClass} {selected} on:update={onUpdate} />
|
||||
|
22
plugins/tags-resources/src/components/icons/TagIcon.svelte
Normal file
22
plugins/tags-resources/src/components/icons/TagIcon.svelte
Normal file
@ -0,0 +1,22 @@
|
||||
<script lang="ts">
|
||||
export let size: 'x-small' | 'small' | 'medium' | 'large'
|
||||
export let fill: string = 'currentColor'
|
||||
</script>
|
||||
|
||||
<svg class="svg-{size}" fill="none" viewBox="0 0 16 16">
|
||||
<path
|
||||
opacity="0.01"
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M0 16L16 16L16 2.54292e-07L-6.99382e-07 9.53674e-07L0 16Z"
|
||||
/>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M6.28273 14.1415L1.86168 9.72159C1.63012 9.49034 1.5 9.17654 1.5 8.84932C1.5 8.5221 1.63012 8.20831 1.86168 7.97706L8.04102 1.79315C8.22858 1.60546 8.48305 1.5 8.74839 1.5L13.5 1.5C14.0523 1.5 14.5 1.94772 14.5 2.5L14.5 7.25015C14.5 7.5154 14.3946 7.76979 14.207 7.95733L8.02156 14.1415C7.54056 14.6195 6.76373 14.6195 6.28273 14.1415Z"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<circle cx="11.4996" cy="4.49961" r="0.9" />
|
||||
</svg>
|
@ -12,7 +12,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
import { Resources } from '@hcengineering/platform'
|
||||
import { TagElement } from '@hcengineering/tags'
|
||||
import { TagElement as TagElementType } from '@hcengineering/tags'
|
||||
import { eventToHTMLElement, showPopup } from '@hcengineering/ui'
|
||||
import TagsCategoryBar from './components/CategoryBar.svelte'
|
||||
import CategoryPresenter from './components/CategoryPresenter.svelte'
|
||||
@ -32,13 +32,16 @@ import TagsEditorPopup from './components/TagsEditorPopup.svelte'
|
||||
import LabelsPresenter from './components/LabelsPresenter.svelte'
|
||||
import CreateTagElement from './components/CreateTagElement.svelte'
|
||||
import ObjectsTagsEditorPopup from './components/ObjectsTagsEditorPopup.svelte'
|
||||
import TagElement from './components/TagElement.svelte'
|
||||
import { ObjQueryType } from '@hcengineering/core'
|
||||
import { getRefs } from './utils'
|
||||
import { Filter } from '@hcengineering/view'
|
||||
import WeightPopup from './components/WeightPopup.svelte'
|
||||
import DraftTagsEditor from './components/DraftTagsEditor.svelte'
|
||||
import TagsFilterPresenter from './components/TagsFilterPresenter.svelte'
|
||||
import DocTagsEditor from './components/DocTagsEditor.svelte'
|
||||
|
||||
export { WeightPopup }
|
||||
export { WeightPopup, TagElement }
|
||||
export async function tagsInResult (filter: Filter, onUpdate: () => void): Promise<ObjQueryType<any>> {
|
||||
const result = await getRefs(filter, onUpdate)
|
||||
return { $in: result }
|
||||
@ -71,10 +74,12 @@ export default async (): Promise<Resources> => ({
|
||||
TagsEditorPopup,
|
||||
LabelsPresenter,
|
||||
ObjectsTagsEditorPopup,
|
||||
TagsFilterPresenter
|
||||
TagsFilterPresenter,
|
||||
DraftTagsEditor,
|
||||
DocTagsEditor
|
||||
},
|
||||
actionImpl: {
|
||||
Open: (value: TagElement, evt: MouseEvent) => {
|
||||
Open: (value: TagElementType, evt: MouseEvent) => {
|
||||
showPopup(EditTagElement, { value, keyTitle: '' }, eventToHTMLElement(evt))
|
||||
}
|
||||
},
|
||||
|
@ -35,7 +35,6 @@ export default mergeIds(tagsId, tags, {
|
||||
WeightPlaceholder: '' as IntlString,
|
||||
CategoryPlaceholder: '' as IntlString,
|
||||
TagTooltip: '' as IntlString,
|
||||
Tags: '' as IntlString,
|
||||
Tag: '' as IntlString,
|
||||
TagCreateLabel: '' as IntlString,
|
||||
TagName: '' as IntlString,
|
||||
|
@ -14,7 +14,7 @@
|
||||
//
|
||||
|
||||
import type { AttachedDoc, Class, Doc, Ref, Space } from '@hcengineering/core'
|
||||
import type { Asset, Plugin } from '@hcengineering/platform'
|
||||
import type { Asset, IntlString, Plugin } from '@hcengineering/platform'
|
||||
import { plugin } from '@hcengineering/platform'
|
||||
import { AnyComponent } from '@hcengineering/ui'
|
||||
import { writable } from 'svelte/store'
|
||||
@ -100,6 +100,8 @@ const tagsPlugin = plugin(tagsId, {
|
||||
Level3: '' as Asset
|
||||
},
|
||||
component: {
|
||||
DraftTagsEditor: '' as AnyComponent,
|
||||
DocTagsEditor: '' as AnyComponent,
|
||||
TagsView: '' as AnyComponent,
|
||||
TagsEditor: '' as AnyComponent,
|
||||
TagsDropdownEditor: '' as AnyComponent,
|
||||
@ -111,6 +113,11 @@ const tagsPlugin = plugin(tagsId, {
|
||||
TagsEditorPopup: '' as AnyComponent,
|
||||
ObjectsTagsEditorPopup: '' as AnyComponent
|
||||
},
|
||||
string: {
|
||||
Tags: '' as IntlString,
|
||||
AddLabel: '' as IntlString,
|
||||
TagLabel: '' as IntlString
|
||||
},
|
||||
category: {
|
||||
NoCategory: '' as Ref<TagCategory>
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user