Fix Channel editor (#1754)

Signed-off-by: Alexander Platov <sas_lord@mail.ru>
This commit is contained in:
Alexander Platov 2022-05-14 12:47:00 +03:00 committed by GitHub
parent ba17bed87e
commit 8bf582475f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 237 additions and 108 deletions

View File

@ -28,6 +28,7 @@
export let maxWidth: string
export let focus: boolean = false
export let editable = true
export let focusIndex = -1
const client = getClient()
const hierarchy = client.getHierarchy()
@ -64,6 +65,7 @@
value={getAttribute(client, object, { key: attributeKey, attr: attribute })}
{onChange}
{focus}
{focusIndex}
/>
{/await}
{/if}

View File

@ -45,7 +45,7 @@
async function onSpaceEdit (): Promise<void> {
if (dm === undefined) return
showPanel(chunter.component.EditChannel, dm._id, dm._class, 'right')
showPanel(chunter.component.EditChannel, dm._id, dm._class, 'content')
}
</script>

View File

@ -16,7 +16,15 @@
import { createEventDispatcher, onMount } from 'svelte'
import type { IntlString } from '@anticrm/platform'
import { translate } from '@anticrm/platform'
import { Button, IconClose, closeTooltip, IconBlueCheck, registerFocus, createFocusManager } from '@anticrm/ui'
import {
Button,
IconClose,
closeTooltip,
IconBlueCheck,
registerFocus,
createFocusManager,
IconArrowRight
} from '@anticrm/ui'
import IconCopy from './icons/Copy.svelte'
import { FocusHandler } from '@anticrm/ui'
import plugin from '../plugin'
@ -24,6 +32,7 @@
export let value: string = ''
export let placeholder: IntlString
export let editable: boolean = false
export let integration: boolean = false
const dispatch = createEventDispatcher()
let input: HTMLInputElement
@ -65,8 +74,8 @@
</script>
<FocusHandler manager={mgr} />
<div class="buttons-group xsmall-gap">
{#if editable}
{#if editable}
<div class="editor-container buttons-group xsmall-gap">
<div class="cover-channel" class:show class:copied={label === plugin.string.Copied} data-tooltip={lTraslate}>
<input
bind:this={input}
@ -77,7 +86,7 @@
style="width: 100%;"
on:keypress={(ev) => {
if (ev.key === 'Enter') {
dispatch('update', value)
dispatch('close', value)
closeTooltip()
}
}}
@ -97,48 +106,58 @@
}
}}
/>
{:else}
<Button
focusIndex={3}
kind={'transparent'}
size={'small'}
icon={IconBlueCheck}
on:click={() => {
dispatch('close', value)
}}
/>
</div>
{:else}
<div class="buttons-group xsmall-gap">
<span
class="select-text cover-channel"
class:show
class:copied={label === plugin.string.Copied}
data-tooltip={lTraslate}>{value}</span
>
{/if}
<Button
focusIndex={3}
kind={'transparent'}
size={'small'}
icon={IconCopy}
on:mousemove={() => {
show = true
}}
on:focus={() => {
show = true
}}
on:mouseleave={() => {
show = false
label = plugin.string.CopyToClipboard
}}
on:blur={() => {
show = false
label = plugin.string.CopyToClipboard
}}
on:click={copyChannel}
/>
{#if editable}
<Button
focusIndex={4}
focusIndex={3}
kind={'transparent'}
size={'small'}
icon={IconBlueCheck}
on:click={() => {
dispatch('update', value)
closeTooltip()
icon={IconCopy}
on:mousemove={() => {
show = true
}}
on:focus={() => {
show = true
}}
on:mouseleave={() => {
show = false
label = plugin.string.CopyToClipboard
}}
on:blur={() => {
show = false
label = plugin.string.CopyToClipboard
}}
on:click={copyChannel}
/>
{/if}
</div>
{#if integration}
<Button
focusIndex={4}
kind={'transparent'}
size={'small'}
icon={IconArrowRight}
on:click={() => {
dispatch('update', 'open')
}}
/>
{/if}
</div>
{/if}
<style lang="scss">
.cover-channel {
@ -176,4 +195,13 @@
transform: translate(-50%, -50%);
}
}
.editor-container {
margin-top: 0.25rem;
padding: 0.5rem;
background-color: var(--accent-bg-color);
border: 1px solid var(--divider-color);
border-radius: 0.25rem;
box-shadow: var(--popup-panel-shadow);
}
</style>

View File

@ -31,7 +31,7 @@
getFocusManager,
Menu,
showPopup,
showTooltip
Tooltip
} from '@anticrm/ui'
import { createEventDispatcher, tick } from 'svelte'
import { getChannelProviders } from '../utils'
@ -122,6 +122,7 @@
let addBtn: HTMLButtonElement
const btns: HTMLButtonElement[] = []
let anchor: HTMLElement
let opened: number | undefined = undefined
function filterUndefined (channels: AttachedData<Channel>[]): AttachedData<Channel>[] {
return channels.filter((channel) => channel.value !== undefined)
@ -175,33 +176,41 @@
}
const editChannel = (el: HTMLElement, n: number, item: Item): void => {
showTooltip(
undefined,
el,
undefined,
ChannelEditor,
{
value: item.value,
placeholder: item.placeholder,
editable
},
anchor,
(result) => {
if (result.detail != null) {
if (result.detail === '') {
displayItems = dropItem(n)
} else {
displayItems[n].value = result.detail
if (opened !== n) {
opened = n
showPopup(
ChannelEditor,
{
value: item.value,
placeholder: item.placeholder,
editable
},
el,
(result) => {
if (result != null) {
if (result === '') {
displayItems = dropItem(n)
} else {
displayItems[n].value = result
}
saveItems()
focusManager?.setFocusPos(focusIndex + 1 + n)
}
if (result === undefined && item.value === '') displayItems = dropItem(n)
opened = undefined
},
(result) => {
if (result != null) {
if (result === '') {
displayItems = dropItem(n)
} else {
displayItems[n].value = result
}
saveItems()
}
saveItems()
focusManager?.setFocusPos(focusIndex + 1 + n)
}
}
)
}
const _focus = (ev: Event, n: number, item: Item): void => {
const el = ev.target as HTMLButtonElement
if (el) editChannel(el, n, item)
)
}
}
</script>
@ -213,39 +222,62 @@
class:short={displayItems.length > 4 && length === 'short'}
>
{#each displayItems as item, i}
<Button
focusIndex={focusIndex === -1 ? focusIndex : focusIndex + 1 + i}
id={item.label}
bind:input={btns[i]}
icon={item.icon}
{kind}
{size}
{shape}
highlight={item.integration || item.notification}
on:mousemove={(ev) => {
_focus(ev, i, item)
}}
on:click={(ev) => {
if (editable) {
editChannel(eventToHTMLElement(ev), i, item)
} else {
<Tooltip
component={opened !== i ? ChannelEditor : undefined}
props={{ value: item.value, placeholder: item.placeholder, editable: false, integration: item.integration }}
onUpdate={(result) => {
if (result.detail === 'open') {
closeTooltip()
dispatch('open', item)
}
dispatch('open', item)
}}
/>
>
<Button
focusIndex={focusIndex === -1 ? focusIndex : focusIndex + 1 + i}
id={item.label}
bind:input={btns[i]}
icon={item.icon}
{kind}
{size}
{shape}
highlight={item.integration || item.notification}
on:click={(ev) => {
if (editable) {
closeTooltip()
editChannel(eventToHTMLElement(ev), i, item)
} else {
dispatch('open', item)
}
}}
/>
</Tooltip>
{/each}
{#if actions.length > 0 && editable}
<Button
focusIndex={focusIndex === -1 ? focusIndex : focusIndex + 2 + displayItems.length}
id={presentation.string.AddSocialLinks}
bind:input={addBtn}
icon={contact.icon.SocialEdit}
label={displayItems.length === 0 ? presentation.string.AddSocialLinks : undefined}
{kind}
{size}
{shape}
on:click={showMenu}
/>
{#if displayItems.length === 0}
<Button
focusIndex={focusIndex === -1 ? focusIndex : focusIndex + 2 + displayItems.length}
id={presentation.string.AddSocialLinks}
bind:input={addBtn}
icon={contact.icon.SocialEdit}
label={presentation.string.AddSocialLinks}
{kind}
{size}
{shape}
on:click={showMenu}
/>
{:else}
<Tooltip label={presentation.string.AddSocialLinks}>
<Button
focusIndex={focusIndex === -1 ? focusIndex : focusIndex + 2 + displayItems.length}
id={presentation.string.AddSocialLinks}
bind:input={addBtn}
icon={contact.icon.SocialEdit}
{kind}
{size}
{shape}
on:click={showMenu}
/>
</Tooltip>
{/if}
{/if}
</div>

View File

@ -28,6 +28,7 @@
export let integrations: Set<Ref<Doc>> | undefined = undefined
export let editable = true
export let allowOpen = true
export let focusIndex = -1
export let kind: ButtonKind = 'link-bordered'
export let size: ButtonSize = 'small'
@ -124,6 +125,7 @@
{integrations}
{editable}
{shape}
{focusIndex}
on:change={(e) => {
if (editable) save(e.detail)
}}

View File

@ -16,7 +16,7 @@
import { Channel, Organization } from '@anticrm/contact'
import { AttachedData, generateId } from '@anticrm/core'
import { Card, getClient } from '@anticrm/presentation'
import { Button, EditBox } from '@anticrm/ui'
import { Button, EditBox, createFocusManager, FocusHandler } from '@anticrm/ui'
import { createEventDispatcher } from 'svelte'
import contact from '../plugin'
import ChannelsDropdown from './ChannelsDropdown.svelte'
@ -55,8 +55,12 @@
}
let channels: AttachedData<Channel>[] = []
const manager = createFocusManager()
</script>
<FocusHandler {manager} />
<Card
label={contact.string.CreateOrganization}
okAction={createOrganization}
@ -76,9 +80,10 @@
maxWidth={'37.5rem'}
kind={'large-style'}
focus
focusIndex={1}
/>
</div>
<svelte:fragment slot="pool">
<ChannelsDropdown bind:value={channels} editable />
<ChannelsDropdown bind:value={channels} focusIndex={10} editable />
</svelte:fragment>
</Card>

View File

@ -18,7 +18,7 @@
import { AttachedData, Data, generateId } from '@anticrm/core'
import { getResource } from '@anticrm/platform'
import { Card, EditableAvatar, getClient } from '@anticrm/presentation'
import { EditBox, IconInfo, Label } from '@anticrm/ui'
import { EditBox, IconInfo, Label, createFocusManager, FocusHandler } from '@anticrm/ui'
import { createEventDispatcher } from 'svelte'
import { ChannelsDropdown } from '..'
import contact from '../plugin'
@ -78,8 +78,12 @@
$: findPerson(client, { ...object, name: combineName(firstName, lastName) }, channels).then((p) => {
matches = p
})
const manager = createFocusManager()
</script>
<FocusHandler {manager} />
<Card
label={contact.string.CreatePerson}
okAction={createPerson}
@ -108,12 +112,14 @@
kind={'large-style'}
maxWidth={'32rem'}
focus
focusIndex={1}
/>
<EditBox
placeholder={contact.string.PersonLastNamePlaceholder}
bind:value={lastName}
kind={'large-style'}
maxWidth={'32rem'}
focusIndex={2}
/>
<div class="mt-1">
<EditBox
@ -121,6 +127,7 @@
bind:value={object.city}
kind={'small-style'}
maxWidth={'32rem'}
focusIndex={3}
/>
</div>
</div>
@ -129,6 +136,6 @@
</div>
</div>
<svelte:fragment slot="pool">
<ChannelsDropdown bind:value={channels} kind={'no-border'} editable />
<ChannelsDropdown bind:value={channels} focusIndex={10} kind={'no-border'} editable />
</svelte:fragment>
</Card>

View File

@ -16,7 +16,7 @@
<script lang="ts">
import { createEventDispatcher, onMount } from 'svelte'
import { getCurrentAccount, Ref, Space } from '@anticrm/core'
import { EditBox } from '@anticrm/ui'
import { EditBox, createFocusManager, FocusHandler } from '@anticrm/ui'
import { getClient, createQuery } from '@anticrm/presentation'
import setting from '@anticrm/setting'
import { IntegrationType } from '@anticrm/setting'
@ -49,8 +49,12 @@
onMount(() => {
dispatch('open', { ignoreKeys: ['comments', 'name', 'channels'] })
})
const manager = createFocusManager()
</script>
<FocusHandler {manager} />
{#if object !== undefined}
<div class="flex-row-center">
<div class="mr-8 flex-center logo">
@ -63,11 +67,13 @@
maxWidth="20rem"
bind:value={object.name}
on:change={nameChange}
focus
focusIndex={1}
/>
</div>
<div class="separator" />
<div class="flex-row-center">
<ChannelsEditor attachedTo={object._id} attachedClass={object._class} {integrations} on:click />
<ChannelsEditor attachedTo={object._id} attachedClass={object._class} {integrations} focusIndex={10} on:click />
</div>
</div>
</div>

View File

@ -20,7 +20,7 @@
import { getResource } from '@anticrm/platform'
import { AttributeEditor, Avatar, createQuery, EditableAvatar, getClient } from '@anticrm/presentation'
import setting, { IntegrationType } from '@anticrm/setting'
import { EditBox } from '@anticrm/ui'
import { EditBox, createFocusManager, FocusHandler } from '@anticrm/ui'
import { afterUpdate, createEventDispatcher, onMount } from 'svelte'
import contact from '../plugin'
import ChannelsEditor from './ChannelsEditor.svelte'
@ -93,8 +93,12 @@
await deleteFile(object.avatar)
}
}
const manager = createFocusManager()
</script>
<FocusHandler {manager} />
{#if object !== undefined}
<div class="flex-row-stretch flex-grow">
<div class="mr-8">
@ -115,6 +119,7 @@
maxWidth="20rem"
bind:value={firstName}
on:change={firstNameChange}
focusIndex={1}
/>
{:else}
{firstName}
@ -127,13 +132,21 @@
maxWidth="20rem"
bind:value={lastName}
on:change={lastNameChange}
focusIndex={2}
/>
{:else}
{lastName}
{/if}
</div>
<div class="location">
<AttributeEditor maxWidth="20rem" _class={contact.class.Person} {editable} {object} key="city" />
<AttributeEditor
maxWidth="20rem"
_class={contact.class.Person}
{editable}
{object}
key="city"
focusIndex={3}
/>
</div>
</div>
@ -145,6 +158,7 @@
{editable}
bind:integrations
shape={'circle'}
focusIndex={10}
/>
</div>
</div>

View File

@ -10,7 +10,7 @@
let container: HTMLElement
function onEdit (event: MouseEvent) {
function onEdit () {
showPopup(
EmployeePreviewPopup,
{

View File

@ -22,7 +22,17 @@
import type { Customer } from '@anticrm/lead'
import { getResource } from '@anticrm/platform'
import { Card, EditableAvatar, getClient } from '@anticrm/presentation'
import { Button, EditBox, eventToHTMLElement, IconInfo, Label, SelectPopup, showPopup } from '@anticrm/ui'
import {
Button,
EditBox,
eventToHTMLElement,
IconInfo,
Label,
SelectPopup,
showPopup,
createFocusManager,
FocusHandler
} from '@anticrm/ui'
import { createEventDispatcher } from 'svelte'
import lead from '../plugin'
@ -149,8 +159,12 @@
)
}
$: canSave = formatName(targetClass._id, firstName, lastName, object.name).length > 0
const manager = createFocusManager()
</script>
<FocusHandler {manager} />
<Card
label={lead.string.CreateCustomer}
okAction={createCustomer}
@ -168,6 +182,7 @@
size={'small'}
kind={'no-border'}
on:click={selectTarget}
focusIndex={100}
/>
</svelte:fragment>
{#if targetClass._id === contact.class.Person}
@ -179,12 +194,14 @@
kind={'large-style'}
maxWidth={'32rem'}
focus
focusIndex={1}
/>
<EditBox
placeholder={contact.string.PersonLastNamePlaceholder}
bind:value={lastName}
kind={'large-style'}
maxWidth={'32rem'}
focusIndex={2}
/>
<div class="mt-1">
<EditBox
@ -192,6 +209,7 @@
bind:value={object.city}
kind={'small-style'}
maxWidth={'32rem'}
focusIndex={3}
/>
</div>
<EditBox
@ -199,6 +217,7 @@
bind:value={object.description}
kind={'small-style'}
maxWidth={'32rem'}
focusIndex={4}
/>
</div>
<div class="ml-4 flex">
@ -222,11 +241,12 @@
maxWidth={'37.5rem'}
kind={'large-style'}
focus
focusIndex={1}
/>
</div>
{/if}
<svelte:fragment slot="pool">
<ChannelsDropdown bind:value={channels} editable />
<ChannelsDropdown bind:value={channels} focusIndex={10} editable />
</svelte:fragment>
<svelte:fragment slot="footer">
{#if matches.length > 0}

View File

@ -16,7 +16,7 @@
import { AttributeEditor, createQuery, EditableAvatar, getClient } from '@anticrm/presentation'
import setting from '@anticrm/setting'
import { EditBox, Icon, Label } from '@anticrm/ui'
import { EditBox, Icon, Label, createFocusManager, FocusHandler } from '@anticrm/ui'
import contact, { Employee, EmployeeAccount, getFirstName, getLastName } from '@anticrm/contact'
import contactRes from '@anticrm/contact-resources/src/plugin'
import { getCurrentAccount } from '@anticrm/core'
@ -69,8 +69,12 @@
await deleteFile(employee.avatar)
}
}
const manager = createFocusManager()
</script>
<FocusHandler {manager} />
<div class="antiComponent">
<div class="ac-header short divide">
<div class="ac-header__icon"><Icon icon={setting.icon.EditProfile} size={'medium'} /></div>
@ -88,6 +92,8 @@
placeholder={contactRes.string.PersonFirstNamePlaceholder}
maxWidth="20rem"
bind:value={firstName}
focus
focusIndex={1}
on:change={() => {
changeName(firstName, lastName)
}}
@ -98,17 +104,24 @@
placeholder={contactRes.string.PersonLastNamePlaceholder}
maxWidth="20rem"
bind:value={lastName}
focusIndex={2}
on:change={() => {
changeName(firstName, lastName)
}}
/>
</div>
<div class="location">
<AttributeEditor maxWidth="20rem" _class={contact.class.Person} object={employee} key="city" />
<AttributeEditor
maxWidth="20rem"
_class={contact.class.Person}
object={employee}
focusIndex={3}
key="city"
/>
</div>
</div>
<div class="separator" />
<ChannelsEditor attachedTo={employee._id} attachedClass={employee._class} allowOpen={false} />
<ChannelsEditor attachedTo={employee._id} attachedClass={employee._class} focusIndex={10} allowOpen={false} />
</div>
</div>
{/if}

View File

@ -84,7 +84,7 @@
</div>
</div>
<div class="antiPanel-component filled">
<div class="antiPanel-component border-left filled">
{#if category}
<Component is={category.component} />
{/if}

View File

@ -34,10 +34,10 @@ test.describe('contact tests', () => {
await page.click('[id="presentation:string:AddSocialLinks"]')
await page.click('.popup button:has-text("Email")')
}
await page.hover('[id="gmail:string:Email"]')
// await page.hover('[id="gmail:string:Email"]')
await page.fill('[placeholder="john\\.appleseed\\@apple\\.com"]', 'wer@qwe.com')
// Click text=Apply
await page.click('button:nth-child(4)')
await page.click('button:nth-child(3)')
})
test('create-template', async ({ page }) => {
// Go to http://localhost:8083/workbench%3Acomponent%3AWorkbenchApp