mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-24 17:30:03 +00:00
UBER-417: replace AddSavedView with select popup, allow renaming (#3423)
Signed-off-by: Vyacheslav Tumanov <me@slavatumanov.me>
This commit is contained in:
parent
14b7806967
commit
7c417e2f1c
@ -95,6 +95,7 @@
|
|||||||
"AddSavedView": "Add saved view",
|
"AddSavedView": "Add saved view",
|
||||||
"Public": "Public",
|
"Public": "Public",
|
||||||
"Hide": "Hide",
|
"Hide": "Hide",
|
||||||
|
"Rename": "Rename",
|
||||||
"SaveAs": "Save as",
|
"SaveAs": "Save as",
|
||||||
"And": "and",
|
"And": "and",
|
||||||
"Between": "is between",
|
"Between": "is between",
|
||||||
|
@ -91,6 +91,7 @@
|
|||||||
"BetweenDates": "Между датами",
|
"BetweenDates": "Между датами",
|
||||||
"Public": "Публичный",
|
"Public": "Публичный",
|
||||||
"Hide": "Спрятать",
|
"Hide": "Спрятать",
|
||||||
|
"Rename": "Переименовать",
|
||||||
"SaveAs": "Сохранить как",
|
"SaveAs": "Сохранить как",
|
||||||
"And": "и",
|
"And": "и",
|
||||||
"Between": "между",
|
"Between": "между",
|
||||||
|
@ -1,75 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
import { getCurrentAccount } from '@hcengineering/core'
|
|
||||||
import { translate } from '@hcengineering/platform'
|
|
||||||
import presentation, { createQuery, getClient } from '@hcengineering/presentation'
|
|
||||||
import { deviceOptionsStore, resizeObserver } from '@hcengineering/ui'
|
|
||||||
import { FilteredView } from '@hcengineering/view'
|
|
||||||
import { createEventDispatcher, onMount } from 'svelte'
|
|
||||||
import view from '../../plugin'
|
|
||||||
|
|
||||||
export let attachedTo: string | undefined
|
|
||||||
|
|
||||||
const me = getCurrentAccount()._id
|
|
||||||
const q = createQuery()
|
|
||||||
let views: FilteredView[] = []
|
|
||||||
|
|
||||||
const baseQuery = {
|
|
||||||
attachedTo,
|
|
||||||
sharable: true,
|
|
||||||
createdBy: { $ne: me }
|
|
||||||
}
|
|
||||||
|
|
||||||
$: query =
|
|
||||||
search === ''
|
|
||||||
? baseQuery
|
|
||||||
: {
|
|
||||||
...baseQuery,
|
|
||||||
name: { $like: `%${search}%` }
|
|
||||||
}
|
|
||||||
|
|
||||||
$: q.query(view.class.FilteredView, query, (res) => {
|
|
||||||
views = res.filter((p) => !p.users.includes(me))
|
|
||||||
})
|
|
||||||
|
|
||||||
const client = getClient()
|
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
|
||||||
|
|
||||||
async function add (sv: FilteredView): Promise<void> {
|
|
||||||
await client.update(sv, { $push: { users: me } })
|
|
||||||
dispatch('close')
|
|
||||||
}
|
|
||||||
|
|
||||||
let search: string = ''
|
|
||||||
let phTraslate: string = ''
|
|
||||||
let searchInput: HTMLInputElement
|
|
||||||
$: translate(presentation.string.Search, {}).then((res) => {
|
|
||||||
phTraslate = res
|
|
||||||
})
|
|
||||||
|
|
||||||
onMount(() => {
|
|
||||||
if (searchInput && !$deviceOptionsStore.isMobile) searchInput.focus()
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}>
|
|
||||||
<div class="header">
|
|
||||||
<input bind:this={searchInput} type="text" bind:value={search} placeholder={phTraslate} />
|
|
||||||
</div>
|
|
||||||
<div class="scroll">
|
|
||||||
<div class="box">
|
|
||||||
{#each views as value}
|
|
||||||
<button
|
|
||||||
class="menu-item no-focus"
|
|
||||||
on:click={() => {
|
|
||||||
add(value)
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div class="flex-row-center w-full">
|
|
||||||
{value.name}
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
@ -31,12 +31,12 @@
|
|||||||
export let selected = false
|
export let selected = false
|
||||||
export let bold = false
|
export let bold = false
|
||||||
export let shortDropbox = false
|
export let shortDropbox = false
|
||||||
export let actions: () => Promise<Action[]> = async () => []
|
export let actions: (originalEvent?: MouseEvent) => Promise<Action[]> = async () => []
|
||||||
export let indent: 'default' | 'ml-2' | 'ml-4' | 'ml-8' = 'default'
|
export let indent: 'default' | 'ml-2' | 'ml-4' | 'ml-8' = 'default'
|
||||||
|
|
||||||
let hovered = false
|
let hovered = false
|
||||||
async function onMenuClick (ev: MouseEvent) {
|
async function onMenuClick (ev: MouseEvent) {
|
||||||
showPopup(Menu, { actions: await actions(), ctx: _id }, ev.target as HTMLElement, () => {
|
showPopup(Menu, { actions: await actions(ev), ctx: _id }, ev.target as HTMLElement, () => {
|
||||||
hovered = false
|
hovered = false
|
||||||
})
|
})
|
||||||
hovered = true
|
hovered = true
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
export let icon: Asset | undefined = undefined
|
export let icon: Asset | undefined = undefined
|
||||||
export let title: string
|
export let title: string
|
||||||
export let notifications = 0
|
export let notifications = 0
|
||||||
export let actions: () => Promise<Action[]> = async () => []
|
export let actions: (originalEvent?: MouseEvent) => Promise<Action[]> = async () => []
|
||||||
export let selected: boolean = false
|
export let selected: boolean = false
|
||||||
export let bold = false
|
export let bold = false
|
||||||
export let indent: 'default' | 'ml-2' | 'ml-4' | 'ml-8' = 'default'
|
export let indent: 'default' | 'ml-2' | 'ml-4' | 'ml-8' = 'default'
|
||||||
|
@ -108,7 +108,6 @@ import { AggregationMiddleware } from './middleware'
|
|||||||
import { grouppingStatusManager, StatusAggregationManager } from './status'
|
import { grouppingStatusManager, StatusAggregationManager } from './status'
|
||||||
export { getActions, invokeAction } from './actions'
|
export { getActions, invokeAction } from './actions'
|
||||||
export { default as ActionHandler } from './components/ActionHandler.svelte'
|
export { default as ActionHandler } from './components/ActionHandler.svelte'
|
||||||
export { default as AddSavedView } from './components/filter/AddSavedView.svelte'
|
|
||||||
export { default as FilterButton } from './components/filter/FilterButton.svelte'
|
export { default as FilterButton } from './components/filter/FilterButton.svelte'
|
||||||
export { default as FixedColumn } from './components/FixedColumn.svelte'
|
export { default as FixedColumn } from './components/FixedColumn.svelte'
|
||||||
export { default as SourcePresenter } from './components/inference/SourcePresenter.svelte'
|
export { default as SourcePresenter } from './components/inference/SourcePresenter.svelte'
|
||||||
|
@ -824,6 +824,7 @@ const view = plugin(viewId, {
|
|||||||
Timeline: '' as IntlString,
|
Timeline: '' as IntlString,
|
||||||
Public: '' as IntlString,
|
Public: '' as IntlString,
|
||||||
Hide: '' as IntlString,
|
Hide: '' as IntlString,
|
||||||
|
Rename: '' as IntlString,
|
||||||
Assigned: '' as IntlString,
|
Assigned: '' as IntlString,
|
||||||
Open: '' as IntlString,
|
Open: '' as IntlString,
|
||||||
Created: '' as IntlString,
|
Created: '' as IntlString,
|
||||||
|
@ -1,11 +1,20 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Ref, getCurrentAccount } from '@hcengineering/core'
|
import { Ref, getCurrentAccount, toIdMap } from '@hcengineering/core'
|
||||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||||
import setting from '@hcengineering/setting'
|
import setting from '@hcengineering/setting'
|
||||||
import { Action, IconAdd, Location, eventToHTMLElement, location, navigate, showPopup } from '@hcengineering/ui'
|
import {
|
||||||
|
Action,
|
||||||
|
IconAdd,
|
||||||
|
Location,
|
||||||
|
eventToHTMLElement,
|
||||||
|
location,
|
||||||
|
navigate,
|
||||||
|
showPopup,
|
||||||
|
SelectPopup,
|
||||||
|
getEventPopupPositionElement
|
||||||
|
} from '@hcengineering/ui'
|
||||||
import view, { Filter, FilteredView, ViewOptions, Viewlet } from '@hcengineering/view'
|
import view, { Filter, FilteredView, ViewOptions, Viewlet } from '@hcengineering/view'
|
||||||
import {
|
import {
|
||||||
AddSavedView,
|
|
||||||
TreeItem,
|
TreeItem,
|
||||||
TreeNode,
|
TreeNode,
|
||||||
activeViewlet,
|
activeViewlet,
|
||||||
@ -16,11 +25,13 @@
|
|||||||
setActiveViewletId,
|
setActiveViewletId,
|
||||||
setFilters,
|
setFilters,
|
||||||
setViewOptions,
|
setViewOptions,
|
||||||
viewOptionStore
|
viewOptionStore,
|
||||||
|
EditBoxPopup
|
||||||
} from '@hcengineering/view-resources'
|
} from '@hcengineering/view-resources'
|
||||||
import { Application } from '@hcengineering/workbench'
|
import { Application } from '@hcengineering/workbench'
|
||||||
import copy from 'fast-copy'
|
import copy from 'fast-copy'
|
||||||
import { createEventDispatcher } from 'svelte'
|
import { createEventDispatcher } from 'svelte'
|
||||||
|
import contact from '@hcengineering/contact'
|
||||||
|
|
||||||
export let currentApplication: Application | undefined
|
export let currentApplication: Application | undefined
|
||||||
|
|
||||||
@ -48,8 +59,33 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
async function viewAction (filteredView: FilteredView): Promise<Action[]> {
|
async function renameAction (object: FilteredView, originalEvent: MouseEvent | undefined): Promise<Action[]> {
|
||||||
if (filteredView.createdBy === me) return await removeAction(filteredView)
|
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 viewAction (filteredView: FilteredView, originalEvent: MouseEvent | undefined): Promise<Action[]> {
|
||||||
|
const rename = await renameAction(filteredView, originalEvent)
|
||||||
|
if (filteredView.createdBy === me) {
|
||||||
|
const remove = await removeAction(filteredView)
|
||||||
|
return [...remove, ...rename]
|
||||||
|
}
|
||||||
return await hideAction(filteredView)
|
return await hideAction(filteredView)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,11 +178,21 @@
|
|||||||
|
|
||||||
async function getActions (availableFilteredViews: FilteredView[]): Promise<Action[]> {
|
async function getActions (availableFilteredViews: FilteredView[]): Promise<Action[]> {
|
||||||
if (availableFilteredViews.length > 0) {
|
if (availableFilteredViews.length > 0) {
|
||||||
|
const filteredViewsIdMap = toIdMap(availableFilteredViews)
|
||||||
|
const pushMeToFV = async (id: Ref<FilteredView>) => {
|
||||||
|
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 = {
|
const add: Action = {
|
||||||
label: view.string.AddSavedView,
|
label: view.string.AddSavedView,
|
||||||
icon: IconAdd,
|
icon: IconAdd,
|
||||||
action: async (_, e): Promise<void> => {
|
action: async (_, e): Promise<void> => {
|
||||||
showPopup(AddSavedView, { attachedTo: currentApplication?.alias }, eventToHTMLElement(e as MouseEvent))
|
showPopup(SelectPopup, { value, searchable: true }, eventToHTMLElement(e as MouseEvent), pushMeToFV)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return [add]
|
return [add]
|
||||||
@ -164,7 +210,7 @@
|
|||||||
title={fv.name}
|
title={fv.name}
|
||||||
selected={selectedId === fv._id}
|
selected={selectedId === fv._id}
|
||||||
on:click={() => load(fv)}
|
on:click={() => load(fv)}
|
||||||
actions={() => viewAction(fv)}
|
actions={(ov) => viewAction(fv, ov)}
|
||||||
/>
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
</TreeNode>
|
</TreeNode>
|
||||||
|
Loading…
Reference in New Issue
Block a user