UBERF-4248: Task type (#4042)

Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
Andrey Sobolev
2023-12-14 23:26:02 +07:00
committed by GitHub
parent 58b841518a
commit 19d6764250
196 changed files with 4690 additions and 2524 deletions
@@ -34,14 +34,15 @@
deviceOptionsStore,
capitalizeFirstLetter,
formatKey,
themeStore
themeStore,
ListView,
resizeObserver
} from '@hcengineering/ui'
import { Action, ActionCategory, ViewContext } from '@hcengineering/view'
import { filterActions, getSelection } from '../actions'
import view from '../plugin'
import { focusStore, selectionStore } from '../selection'
import { openDoc } from '../utils'
import { ListView, resizeObserver } from '@hcengineering/ui'
import ObjectPresenter from './ObjectPresenter.svelte'
import { createEventDispatcher, tick } from 'svelte'
@@ -14,9 +14,21 @@
-->
<script lang="ts">
import type { Class, Doc } from '@hcengineering/core'
import { Label } from '@hcengineering/ui'
import { getClient } from '@hcengineering/presentation'
import { Component, Label } from '@hcengineering/ui'
import view from '@hcengineering/view'
export let value: Class<Doc>
$: presenters =
value !== undefined ? getClient().getHierarchy().findMixinMixins(value, view.mixin.ObjectPresenter) : []
</script>
<Label label={value.label} />
<div class="flex-row-center text-nowrap">
<Label label={value.label} />
{#if presenters.length > 0}
{#each presenters as presenter}
<Component is={presenter.presenter} props={{ value }} />
{/each}
{/if}
</div>
@@ -23,11 +23,12 @@
export let columns: number = 8
export let selected: string | undefined = undefined
export let key: 'color' | 'icon' = 'color'
export let embedded: boolean = false
const dispatch = createEventDispatcher()
</script>
<PopupDialog label={view.string.ChooseAColor}>
<PopupDialog label={view.string.ChooseAColor} {embedded}>
<div class="color-grid" style="grid-template-columns: repeat({columns}, 1.5rem)">
{#each colors as color, i}
{@const col = key === 'color' ? color.color : color.icon}
@@ -14,84 +14,64 @@
-->
<script lang="ts">
import { Asset, Metadata } from '@hcengineering/platform'
import presentation, { Card } from '@hcengineering/presentation'
import {
Button,
EmojiPopup,
Label,
TabsControl,
eventToHTMLElement,
getPlatformColor,
getPlatformColorDef,
showPopup,
themeStore
} from '@hcengineering/ui'
import { Button, EmojiPopup, TabsControl, getPlatformColor, getPlatformColorDef, themeStore } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
import view from '../plugin'
import ColorsPopup from './ColorsPopup.svelte'
import PopupDialog from './PopupDialog.svelte'
export let icon: Metadata<string> | undefined = undefined
export let icons: Asset[]
export let iconWithEmoji: Asset = view.ids.IconWithEmoji
export let color: number = 0
export let showColor: boolean = true
const dispatch = createEventDispatcher()
let _color = color
let _icon = icon ?? icons[0]
function save () {
dispatch('close', { icon: _icon, color: _color })
}
function pickColor (evt: MouseEvent) {
showPopup(
ColorsPopup,
{ selected: getPlatformColorDef(_color, $themeStore.dark).name },
eventToHTMLElement(evt),
(newColor) => {
if (newColor != null) {
_color = newColor
}
}
)
}
</script>
<Card
label={view.string.ChooseIcon}
okLabel={presentation.string.Save}
okAction={save}
canSave={_icon !== undefined}
on:close={() => {
dispatch('close')
}}
on:changeContent
>
<div class="float-left-box">
<PopupDialog label={view.string.ChooseIcon} on:changeContent>
<div class="float-left-box w-85">
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<TabsControl size={'small'} model={[{ label: view.string.IconCategory }, { label: view.string.EmojiCategory }]}>
<svelte:fragment slot="content" let:selected>
{#if selected === 0}
<div class="flex-row-center">
<Label label={view.string.IconColor} />
<div class="flex-no-shrink ml-2 color" on:click={pickColor}>
<div class="dot" style="background-color: {getPlatformColor(_color ?? 0, $themeStore.dark)}" />
</div>
</div>
{#each icons as obj}
<div class="float-left p-2">
<Button
icon={obj}
iconProps={{ fill: getPlatformColor(_color ?? 0, $themeStore.dark) }}
size="medium"
kind={obj === _icon ? 'primary' : 'ghost'}
on:click={() => {
_icon = obj
<div class="flex-col mt-2">
{#if icons.length > 0}
<div class="flex">
{#each icons as obj}
<div class="float-left">
<Button
icon={obj}
iconProps={showColor ? { fill: getPlatformColor(_color ?? 0, $themeStore.dark) } : undefined}
size="medium"
kind={obj === _icon ? 'primary' : 'ghost'}
on:click={() => {
_icon = obj
dispatch(!showColor ? 'close' : 'update', { icon: _icon, color: _color })
}}
/>
</div>
{/each}
</div>
{/if}
{#if showColor}
<ColorsPopup
selected={getPlatformColorDef(_color, $themeStore.dark).name}
embedded
on:close={(evt) => {
_color = evt.detail
dispatch(icons.length === 0 ? 'close' : 'update', {
icon: icons.length === 0 ? null : _icon,
color: _color
})
}}
/>
</div>
{/each}
{/if}
</div>
{:else}
<EmojiPopup
embedded
@@ -103,7 +83,7 @@
</svelte:fragment>
</TabsControl>
</div>
</Card>
</PopupDialog>
<style lang="scss">
.color {
@@ -14,12 +14,11 @@
// limitations under the License.
-->
<script lang="ts">
import { getClient } from '@hcengineering/presentation'
import { getClient, SpaceSelect } from '@hcengineering/presentation'
import { Button, Label, Status as StatusControl, themeStore } from '@hcengineering/ui'
import core, { Class, Client, Doc, Ref, SortingOrder, Space } from '@hcengineering/core'
import { OK, Resource, Status, getResource, translate } from '@hcengineering/platform'
import { SpaceSelect } from '@hcengineering/presentation'
import task, { Project, Task, calcRank } from '@hcengineering/task'
import { createEventDispatcher } from 'svelte'
import view from '../plugin'
@@ -14,19 +14,19 @@
// limitations under the License.
-->
<script lang="ts">
import { Class, Doc, DocumentQuery, FindOptions, Hierarchy, Ref } from '@hcengineering/core'
import { Class, Doc, DocumentQuery, FindOptions, Hierarchy, Ref, mergeQueries } from '@hcengineering/core'
import { Asset, IntlString } from '@hcengineering/platform'
import presentation, { getClient, ObjectCreate } from '@hcengineering/presentation'
import presentation, { ObjectCreate, getClient } from '@hcengineering/presentation'
import {
ActionIcon,
AnySvelteComponent,
Button,
ButtonKind,
ButtonSize,
getEventPositionElement,
getFocusManager,
Label,
LabelAndProps,
getEventPositionElement,
getFocusManager,
showPanel,
showPopup
} from '@hcengineering/ui'
@@ -58,6 +58,8 @@
export let searchField: string = 'name'
export let docProps: Record<string, any> = {}
export let shouldShowAvatar = false
export let autoSelect = false
export let findDefault: (() => Promise<Doc | undefined>) | undefined = undefined
export let create: ObjectCreate | undefined = undefined
@@ -68,11 +70,33 @@
const client = getClient()
async function updateSelected (value: Ref<Doc> | null | undefined) {
selected = value ? await client.findOne(_class, { _id: value }) : undefined
async function updateSelected (
_value: Ref<Doc> | null | undefined,
docQuery: DocumentQuery<Doc> | undefined = undefined
): Promise<void> {
selected = _value ? await client.findOne(_class, { ...(docQuery ?? {}), _id: _value }) : undefined
if (typeof docQuery?._id === 'object' && _value != null) {
const merged = mergeQueries({ _id: _value }, docQuery)
if (typeof merged._id === 'object' && Object.keys(merged._id).length === 0) {
// We do not have match.
selected = undefined
}
}
if (selected === undefined && autoSelect) {
selected = (await findDefault?.()) ?? (await client.findOne(_class, { ...(docQuery ?? {}) }))
if (selected !== undefined) {
value = selected._id ?? undefined
dispatch('change', value)
}
}
if (selected !== undefined) {
dispatch('object', selected)
}
}
$: updateSelected(value)
$: void updateSelected(value, docQuery)
const mgr = getFocusManager()
@@ -18,9 +18,10 @@
import { Label } from '@hcengineering/ui'
export let label: IntlString
export let embedded: boolean = false
</script>
<div class="card-container">
<div class:card-container={!embedded}>
<div class="overflow-label label"><Label {label} /></div>
<div class="content"><slot /></div>
</div>
@@ -24,16 +24,19 @@
<div class="ac-header__wrap-title">
{#if showLabelSelector}
<slot name="label_selector" />
{:else}
{#if label}
<span class="ac-header__title">{label}</span>
{/if}
{#if modeSelectorProps !== undefined}
<ModeSelector props={modeSelectorProps} />
{/if}
{:else if label}
<span class="ac-header__title">{label}</span>
{/if}
{#if $$slots.type_selector}
<div class="ml-2">
<slot name="type_selector" />
</div>
{/if}
{#if modeSelectorProps !== undefined}
<ModeSelector props={modeSelectorProps} />
{/if}
</div>
<div class="mb-1 clear-mins">
<div class="mb-1 clear-mins flex-row-center">
<ViewletSelector bind:viewlet bind:viewlets viewletQuery={viewletQuery ?? { attachTo: _class }} />
<slot name="header-tools" />
</div>
@@ -15,7 +15,7 @@
-->
<script lang="ts">
import type { IntlString } from '@hcengineering/platform'
import type { ButtonSize, ButtonKind } from '@hcengineering/ui'
import type { ButtonSize, ButtonKind, EditStyle } from '@hcengineering/ui'
import { EditBox, Label, showPopup, eventToHTMLElement, Button } from '@hcengineering/ui'
import EditBoxPopup from './EditBoxPopup.svelte'
@@ -30,6 +30,7 @@
export let size: ButtonSize = 'small'
export let justify: 'left' | 'center' = 'center'
export let width: string | undefined = 'fit-content'
export let editKind: EditStyle | undefined = undefined
let shown: boolean = false
@@ -71,5 +72,5 @@
<span class="content-dark-color"><Label label={placeholder} /></span>
{/if}
{:else}
<EditBox {placeholder} bind:value {autoFocus} {select} on:change={_onchange} />
<EditBox {placeholder} bind:value {autoFocus} {select} on:change={_onchange} kind={editKind} />
{/if}
@@ -24,9 +24,10 @@
FindOptions,
Lookup,
Ref,
TxOperations
TxOperations,
getObjectValue,
SortingOrder
} from '@hcengineering/core'
import { getObjectValue, SortingOrder } from '@hcengineering/core'
import notification from '@hcengineering/notification'
import { createQuery, getClient, updateAttribute } from '@hcengineering/presentation'
import ui, {
@@ -75,9 +75,6 @@
groupDepth: viewlet.viewOptions?.groupDepth
}
if (classes.length > 1) {
mergedModel.groupBy.push('_class')
}
for (const ev of extraViewlets) {
mergedModel.groupBy.push(...(ev.viewOptions?.groupBy ?? []))
mergedModel.orderBy.push(...(ev.viewOptions?.orderBy ?? []))
@@ -67,7 +67,7 @@
$: resultOptions = { ...options, lookup, ...(orderBy !== undefined ? { sort: { [orderBy[0]]: orderBy[1] } } : {}) }
let resultQuery: DocumentQuery<Doc> = query
$: getResultQuery(query, viewOptionsConfig, viewOptions).then((p) => {
$: void getResultQuery(query, viewOptionsConfig, viewOptions).then((p) => {
resultQuery = mergeQueries(p, query)
})
@@ -88,7 +88,7 @@
$: groupByKey = viewOptions.groupBy[level] ?? noCategory
let categories: CategoryType[] = []
$: updateCategories(_class, space, docs, groupByKey, viewOptions, viewOptionsConfig)
$: void updateCategories(_class, space, docs, groupByKey, viewOptions, viewOptionsConfig)
$: groupByDocs = groupBy(docs, groupByKey, categories)
@@ -100,8 +100,8 @@
CategoryQuery.remove(queryId)
})
function update () {
updateCategories(_class, space, docs, groupByKey, viewOptions, viewOptionsConfig)
function update (): void {
void updateCategories(_class, space, docs, groupByKey, viewOptions, viewOptionsConfig)
}
async function updateCategories (
@@ -111,7 +111,7 @@
groupByKey: string,
viewOptions: ViewOptions,
viewOptionsModel: ViewOptionModel[] | undefined
) {
): Promise<void> {
categories = await getCategories(client, _class, space, docs, groupByKey)
if (level === 0) {
for (const viewOption of viewOptionsModel ?? []) {