platform/plugins/task-resources/src/components/AssignedTasks.svelte
Vyacheslav Tumanov 9e0a69d8be
allow adding columns to table in MyApplications ()
Signed-off-by: Vyacheslav Tumanov <me@slavatumanov.me>
2023-05-30 17:13:07 +07:00

210 lines
6.8 KiB
Svelte

<!--
// Copyright © 2022 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 { EmployeeAccount } from '@hcengineering/contact'
import { Class, Doc, DocumentQuery, getCurrentAccount, Ref, WithLookup } from '@hcengineering/core'
import { createQuery, getClient } from '@hcengineering/presentation'
import tags, { selectedTagElements, TagCategory, TagElement } from '@hcengineering/tags'
import { DoneState, Task } from '@hcengineering/task'
import {
Component,
IModeSelector,
Label,
resolvedLocationStore,
SearchEdit,
ModeSelector,
Loading
} from '@hcengineering/ui'
import {
activeViewlet,
FilterButton,
getViewOptions,
makeViewletKey,
TableBrowser,
updateActiveViewlet,
viewOptionStore
} from '@hcengineering/view-resources'
import task from '../plugin'
import { IntlString } from '@hcengineering/platform'
import ViewletSettingButton from '@hcengineering/view-resources/src/components/ViewletSettingButton.svelte'
import view, { Viewlet, ViewletPreference } from '@hcengineering/view'
import { onDestroy } from 'svelte'
import FilterBar from '@hcengineering/view-resources/src/components/filter/FilterBar.svelte'
export let _class: Ref<Class<Task>> = task.class.Task
export let labelTasks = task.string.Tasks
let search = ''
const currentUser = getCurrentAccount() as EmployeeAccount
const assigned = { assignee: currentUser.employee }
const created = { createdBy: currentUser._id }
let subscribed = { _id: { $in: [] as Ref<Task>[] } }
$: baseQuery = updateBaseQuery(mode, { assigned, created, subscribed })
function updateBaseQuery (mode: string, queries: { [key: string]: DocumentQuery<Task> }) {
return { ...queries[mode] }
}
let searchQuery: DocumentQuery<Task> = { ...baseQuery }
function updateSearchQuery (search: string): void {
searchQuery = search === '' ? { ...baseQuery } : { ...baseQuery, $search: search }
}
$: if (baseQuery) updateSearchQuery(search)
$: resultQuery = { ...searchQuery }
const client = getClient()
let category: Ref<TagCategory> | undefined = undefined
let loading = true
let preference: ViewletPreference | undefined
let documentIds: Ref<Task>[] = []
function updateResultQuery (search: string, documentIds: Ref<Task>[], doneStates: DoneState[]): void {
resultQuery.doneState = { $nin: doneStates.map((it) => it._id) }
if (documentIds.length > 0) {
resultQuery._id = { $in: documentIds }
}
}
let doneStates: DoneState[] = []
const doneStateQuery = createQuery()
doneStateQuery.query(task.class.DoneState, {}, (res) => (doneStates = res))
// Find all tags for object class with matched elements
const query = createQuery()
$: query.query(tags.class.TagReference, { tag: { $in: $selectedTagElements } }, (result) => {
documentIds = Array.from(
new Set<Ref<Task>>(
result
.filter((it) => client.getHierarchy().isDerived(it.attachedToClass, _class))
.map((it) => it.attachedTo as Ref<Task>)
).values()
)
})
const subscribedQuery = createQuery()
function getSubscribed () {
subscribedQuery.query(
_class,
{ 'notification:mixin:Collaborators.collaborators': getCurrentAccount()._id },
(result) => {
const newSub = result.map((p) => p._id as Ref<Doc> as Ref<Task>)
const curSub = subscribed._id.$in
if (curSub.length !== newSub.length || curSub.some((id, i) => newSub[i] !== id)) {
subscribed = { _id: { $in: newSub } }
}
},
{ sort: { _id: 1 } }
)
}
$: if (mode === 'subscribed') getSubscribed()
const config: [string, IntlString, object][] = [
['assigned', view.string.Assigned, {}],
['created', view.string.Created, {}],
['subscribed', view.string.Subscribed, {}]
]
let [[mode]] = config
function handleChangeMode (newMode: string) {
if (newMode === mode) return
mode = newMode
}
$: modeSelectorProps = {
config,
mode,
onChange: handleChangeMode
} as IModeSelector
$: updateResultQuery(search, documentIds, doneStates)
let viewlets: WithLookup<Viewlet>[] | undefined
let key = makeViewletKey()
onDestroy(
resolvedLocationStore.subscribe((loc) => {
key = makeViewletKey(loc)
})
)
$: viewlet = viewlets && updateActiveViewlet(viewlets, active)
$: active = $activeViewlet[key]
const viewletQuery = createQuery()
const preferenceQuery = createQuery()
viewletQuery.query(view.class.Viewlet, { attachTo: _class, descriptor: task.viewlet.StatusTable }, (res) => {
viewlets = res
preferenceQuery.query(
view.class.ViewletPreference,
{
attachedTo: res[0]._id
},
(pref) => {
preference = pref[0]
loading = false
},
{ limit: 1 }
)
})
$: viewOptions = getViewOptions(viewlet, $viewOptionStore)
function updateCategory (detail: { category: Ref<TagCategory> | null; elements: TagElement[] }) {
category = detail.category ?? undefined
selectedTagElements.set(Array.from(detail.elements ?? []).map((it) => it._id))
}
const handleChange = (evt: any) => updateCategory(evt.detail)
</script>
<div
class="ac-header full divide"
class:header-with-mode-selector={modeSelectorProps !== undefined}
class:header-without-label={!labelTasks}
>
<div class="ac-header__wrap-title">
<span class="ac-header__title"><Label label={labelTasks} /></span>
{#if modeSelectorProps !== undefined}
<ModeSelector props={modeSelectorProps} />
{/if}
</div>
</div>
<div class="ac-header full divide search-start">
<div class="ac-header-full small-gap">
<SearchEdit
bind:value={search}
on:change={() => {
updateResultQuery(search, documentIds, doneStates)
}}
/>
<div class="buttons-divider" />
<FilterButton {_class} />
</div>
{#if viewlet}
<ViewletSettingButton bind:viewOptions {viewlet} />
{/if}
</div>
<FilterBar {_class} query={searchQuery} {viewOptions} on:change={(e) => (resultQuery = e.detail)} />
<Component is={tags.component.TagsCategoryBar} props={{ targetClass: _class, category }} on:change={handleChange} />
{#if viewlet}
{#if loading}
<Loading />
{:else}
<TableBrowser
{_class}
config={preference?.config ?? viewlet.config}
options={viewlet.options}
query={resultQuery}
showNotification
/>
{/if}
{/if}