UBER-417: replace AddSavedView with select popup, allow renaming (#3423)

Signed-off-by: Vyacheslav Tumanov <me@slavatumanov.me>
This commit is contained in:
Vyacheslav Tumanov 2023-06-12 22:07:58 +05:00 committed by GitHub
parent 14b7806967
commit 7c417e2f1c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 60 additions and 87 deletions

View File

@ -95,6 +95,7 @@
"AddSavedView": "Add saved view",
"Public": "Public",
"Hide": "Hide",
"Rename": "Rename",
"SaveAs": "Save as",
"And": "and",
"Between": "is between",

View File

@ -91,6 +91,7 @@
"BetweenDates": "Между датами",
"Public": "Публичный",
"Hide": "Спрятать",
"Rename": "Переименовать",
"SaveAs": "Сохранить как",
"And": "и",
"Between": "между",

View File

@ -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>

View File

@ -31,12 +31,12 @@
export let selected = false
export let bold = 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'
let hovered = false
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 = true

View File

@ -22,7 +22,7 @@
export let icon: Asset | undefined = undefined
export let title: string
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 bold = false
export let indent: 'default' | 'ml-2' | 'ml-4' | 'ml-8' = 'default'

View File

@ -108,7 +108,6 @@ import { AggregationMiddleware } from './middleware'
import { grouppingStatusManager, StatusAggregationManager } from './status'
export { getActions, invokeAction } from './actions'
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 FixedColumn } from './components/FixedColumn.svelte'
export { default as SourcePresenter } from './components/inference/SourcePresenter.svelte'

View File

@ -824,6 +824,7 @@ const view = plugin(viewId, {
Timeline: '' as IntlString,
Public: '' as IntlString,
Hide: '' as IntlString,
Rename: '' as IntlString,
Assigned: '' as IntlString,
Open: '' as IntlString,
Created: '' as IntlString,

View File

@ -1,11 +1,20 @@
<script lang="ts">
import { Ref, getCurrentAccount } from '@hcengineering/core'
import { Ref, getCurrentAccount, toIdMap } from '@hcengineering/core'
import { createQuery, getClient } from '@hcengineering/presentation'
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 {
AddSavedView,
TreeItem,
TreeNode,
activeViewlet,
@ -16,11 +25,13 @@
setActiveViewletId,
setFilters,
setViewOptions,
viewOptionStore
viewOptionStore,
EditBoxPopup
} from '@hcengineering/view-resources'
import { Application } from '@hcengineering/workbench'
import copy from 'fast-copy'
import { createEventDispatcher } from 'svelte'
import contact from '@hcengineering/contact'
export let currentApplication: Application | undefined
@ -48,8 +59,33 @@
]
}
async function viewAction (filteredView: FilteredView): Promise<Action[]> {
if (filteredView.createdBy === me) return await removeAction(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 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)
}
@ -142,11 +178,21 @@
async function getActions (availableFilteredViews: FilteredView[]): Promise<Action[]> {
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 = {
label: view.string.AddSavedView,
icon: IconAdd,
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]
@ -164,7 +210,7 @@
title={fv.name}
selected={selectedId === fv._id}
on:click={() => load(fv)}
actions={() => viewAction(fv)}
actions={(ov) => viewAction(fv, ov)}
/>
{/each}
</TreeNode>