mirror of
https://github.com/hcengineering/platform.git
synced 2025-02-13 14:57:59 +00:00
0d1d1a8b8d
Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
289 lines
8.7 KiB
Svelte
289 lines
8.7 KiB
Svelte
<script lang="ts">
|
|
import contact from '@hcengineering/contact'
|
|
import { Ref, getCurrentAccount, toIdMap } from '@hcengineering/core'
|
|
import { copyTextToClipboard, createQuery, getClient } from '@hcengineering/presentation'
|
|
import setting from '@hcengineering/setting'
|
|
import {
|
|
Action,
|
|
IconAdd,
|
|
Location,
|
|
SelectPopup,
|
|
eventToHTMLElement,
|
|
getEventPopupPositionElement,
|
|
getLocation,
|
|
getPopupPositionElement,
|
|
location,
|
|
locationToUrl,
|
|
navigate,
|
|
showPopup
|
|
} from '@hcengineering/ui'
|
|
import view, { Filter, FilteredView, ViewOptions, Viewlet } from '@hcengineering/view'
|
|
import {
|
|
EditBoxPopup,
|
|
TreeItem,
|
|
TreeNode,
|
|
activeViewlet,
|
|
filterStore,
|
|
getViewOptions,
|
|
makeViewletKey,
|
|
selectedFilterStore,
|
|
setActiveViewletId,
|
|
setFilters,
|
|
setViewOptions,
|
|
viewOptionStore
|
|
} from '@hcengineering/view-resources'
|
|
import { Application } from '@hcengineering/workbench'
|
|
import copy from 'fast-copy'
|
|
import { createEventDispatcher } from 'svelte'
|
|
import TodoCheck from './icons/TodoCheck.svelte'
|
|
import TodoUncheck from './icons/TodoUncheck.svelte'
|
|
|
|
export let currentApplication: Application | undefined
|
|
|
|
const dispatch = createEventDispatcher()
|
|
const client = getClient()
|
|
const me = getCurrentAccount()._id
|
|
|
|
const filteredViewsQuery = createQuery()
|
|
let availableFilteredViews: FilteredView[] = []
|
|
let myFilteredViews: FilteredView[] = []
|
|
$: filteredViewsQuery.query<FilteredView>(
|
|
view.class.FilteredView,
|
|
{ attachedTo: currentApplication?.alias },
|
|
(result) => {
|
|
myFilteredViews = result.filter((p) => p.users.includes(me))
|
|
availableFilteredViews = result.filter((p) => p.sharable && !p.users.includes(me))
|
|
|
|
const location = getLocation()
|
|
if (location.query?.filterViewId) {
|
|
const targetView = result.find((view) => view._id === location.query?.filterViewId)
|
|
if (targetView) {
|
|
load(targetView)
|
|
}
|
|
}
|
|
}
|
|
)
|
|
|
|
async function removeAction (filteredView: FilteredView): Promise<Action[]> {
|
|
return [
|
|
{
|
|
icon: view.icon.Delete,
|
|
label: setting.string.Delete,
|
|
action: async (ctx: any, evt: Event) => {
|
|
await client.remove(filteredView)
|
|
}
|
|
}
|
|
]
|
|
}
|
|
|
|
async function renameAction (object: FilteredView, originalEvent: MouseEvent | undefined): Promise<Action[]> {
|
|
return [
|
|
{
|
|
icon: contact.icon.Edit,
|
|
label: view.string.Rename,
|
|
action: async (ctx: any, evt: Event) => {
|
|
showPopup(
|
|
EditBoxPopup,
|
|
{ value: object.name, format: 'text' },
|
|
getEventPopupPositionElement(originalEvent ?? evt),
|
|
async (res) => {
|
|
if (res !== undefined) {
|
|
await client.update(object, { name: res })
|
|
}
|
|
}
|
|
)
|
|
}
|
|
}
|
|
]
|
|
}
|
|
|
|
async function switchPublicAction (object: FilteredView, originalEvent: MouseEvent | undefined): Promise<Action[]> {
|
|
return [
|
|
{
|
|
icon: object.sharable ? TodoCheck : TodoUncheck,
|
|
label: view.string.PublicView,
|
|
action: async (ctx: any, evt: Event) => {
|
|
await client.update(object, { sharable: !object.sharable })
|
|
}
|
|
}
|
|
]
|
|
}
|
|
|
|
async function copyUrlAction (filteredView: FilteredView): Promise<Action[]> {
|
|
return [
|
|
{
|
|
icon: view.icon.CopyLink,
|
|
label: view.string.CopyToClipboard,
|
|
inline: true,
|
|
action: async (ctx: any, evt: Event) => {
|
|
const { protocol, hostname, port } = window.location
|
|
const baseUrl = `${protocol}//${hostname}${port ? `:${port}` : ''}`
|
|
const query = filteredView.location.query || {}
|
|
query.filterViewId = filteredView._id
|
|
|
|
const targetUrl = locationToUrl({
|
|
path: filteredView.location.path,
|
|
query,
|
|
fragment: filteredView.location.fragment ?? undefined
|
|
})
|
|
copyTextToClipboard(baseUrl + targetUrl)
|
|
}
|
|
}
|
|
]
|
|
}
|
|
|
|
async function viewAction (filteredView: FilteredView, originalEvent: MouseEvent | undefined): Promise<Action[]> {
|
|
const copyUrl = await copyUrlAction(filteredView)
|
|
const rename = await renameAction(filteredView, originalEvent)
|
|
const setPublic = await switchPublicAction(filteredView, originalEvent)
|
|
const hide = await hideAction(filteredView)
|
|
|
|
if (filteredView.createdBy === me) {
|
|
const remove = await removeAction(filteredView)
|
|
return [...setPublic, ...rename, ...remove, ...copyUrl]
|
|
}
|
|
return [...hide, ...copyUrl]
|
|
}
|
|
|
|
async function hideAction (object: FilteredView): Promise<Action[]> {
|
|
return [
|
|
{
|
|
icon: view.icon.Archive,
|
|
label: view.string.Hide,
|
|
action: async (ctx: any, evt: Event) => {
|
|
await client.update(object, { $pull: { users: me } })
|
|
}
|
|
}
|
|
]
|
|
}
|
|
|
|
let selectedId: Ref<FilteredView> | undefined = undefined
|
|
|
|
async function load (fv: FilteredView): Promise<void> {
|
|
selectedFilterStore.set(fv)
|
|
navigate({
|
|
path: fv.location.path,
|
|
query: fv.location.query ?? undefined,
|
|
fragment: fv.location.fragment ?? undefined
|
|
})
|
|
if (fv.viewletId !== undefined && fv.viewletId !== null) {
|
|
const viewlet = await client.findOne<Viewlet>(view.class.Viewlet, { _id: fv.viewletId })
|
|
setActiveViewletId(fv.viewletId, fv.location)
|
|
if (viewlet !== undefined && fv.viewOptions !== undefined) {
|
|
setViewOptions(viewlet, copy(fv.viewOptions))
|
|
}
|
|
}
|
|
setFilters(JSON.parse(fv.filters))
|
|
}
|
|
|
|
const clearSelection = (): void => {
|
|
selectedFilterStore.set(undefined)
|
|
selectedId = undefined
|
|
dispatch('select', false)
|
|
}
|
|
|
|
function checkFilter (
|
|
fv: FilteredView,
|
|
loc: Location,
|
|
filters: string,
|
|
viewOptionStore: Map<string, ViewOptions>
|
|
): boolean {
|
|
if (fv.location.path.join() !== loc.path.join()) return false
|
|
if (fv.filters !== filters) return false
|
|
const key = makeViewletKey(loc)
|
|
if (fv.viewletId !== $activeViewlet[key]) return false
|
|
if (fv.viewletId !== null) {
|
|
const viewOptions = getViewOptions({ _id: fv.viewletId } as unknown as Viewlet, viewOptionStore)
|
|
if (JSON.stringify(fv.viewOptions) !== JSON.stringify(viewOptions)) return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
function checkSelected (
|
|
fs: Filter[],
|
|
loc: Location,
|
|
filteredViews: FilteredView[] | undefined,
|
|
viewOptionStore: Map<string, ViewOptions>
|
|
): void {
|
|
const filters = JSON.stringify(fs)
|
|
if (loc && Array.isArray(fs) && fs.length > 0 && Array.isArray(filteredViews)) {
|
|
if ($selectedFilterStore !== undefined) {
|
|
if ($selectedFilterStore.location.path.join() === loc.path.join()) {
|
|
selectedId = $selectedFilterStore._id
|
|
dispatch('select', true)
|
|
return
|
|
}
|
|
}
|
|
for (const fv of filteredViews) {
|
|
if (checkFilter(fv, loc, filters, viewOptionStore)) {
|
|
selectedId = fv._id
|
|
dispatch('select', true)
|
|
return
|
|
}
|
|
}
|
|
clearSelection()
|
|
} else {
|
|
clearSelection()
|
|
}
|
|
}
|
|
|
|
$: checkSelected($filterStore, $location, myFilteredViews, $viewOptionStore)
|
|
|
|
$: shown = myFilteredViews.length > 0 || availableFilteredViews.length > 0
|
|
$: dispatch('shown', shown)
|
|
|
|
async function getActions (availableFilteredViews: FilteredView[]): Promise<Action[]> {
|
|
if (availableFilteredViews.length > 0) {
|
|
const filteredViewsIdMap = toIdMap(availableFilteredViews)
|
|
const pushMeToFV = async (id: Ref<FilteredView>): Promise<void> => {
|
|
if (id === undefined) return
|
|
const filteredView = filteredViewsIdMap.get(id)
|
|
if (filteredView) await client.update(filteredView, { $push: { users: me } })
|
|
}
|
|
const value = availableFilteredViews.map((p) => ({
|
|
id: p._id,
|
|
text: p.name
|
|
}))
|
|
const add: Action = {
|
|
label: view.string.AddSavedView,
|
|
icon: IconAdd,
|
|
action: async (_, e): Promise<void> => {
|
|
showPopup(
|
|
SelectPopup,
|
|
{ value, searchable: true },
|
|
getPopupPositionElement(eventToHTMLElement(e as MouseEvent), {
|
|
v: 'top',
|
|
h: 'right'
|
|
}),
|
|
pushMeToFV
|
|
)
|
|
}
|
|
}
|
|
return [add]
|
|
} else {
|
|
return []
|
|
}
|
|
}
|
|
</script>
|
|
|
|
{#if shown}
|
|
<TreeNode
|
|
_id={'tree-saved'}
|
|
label={view.string.FilteredViews}
|
|
node
|
|
actions={async () => await getActions(availableFilteredViews)}
|
|
>
|
|
{#each myFilteredViews as fv}
|
|
<TreeItem
|
|
_id={fv._id}
|
|
title={fv.name}
|
|
selected={selectedId === fv._id}
|
|
on:click={async () => {
|
|
await load(fv)
|
|
}}
|
|
actions={async (ov) => await viewAction(fv, ov)}
|
|
/>
|
|
{/each}
|
|
</TreeNode>
|
|
{/if}
|