diff --git a/packages/ui/lang/en.json b/packages/ui/lang/en.json index 2570573528..733827aefd 100644 --- a/packages/ui/lang/en.json +++ b/packages/ui/lang/en.json @@ -5,6 +5,7 @@ "Hours": "{hours, plural, =0 {less than an hour ago} =1 {an hour ago} other {# hours ago}}", "Days": "{days, plural, =0 {today} =1 {yesterday} other {# days ago}}", "ShowMore": "Show more", - "ShowLess": "Show less" + "ShowLess": "Show less", + "Search": "Search" } } diff --git a/packages/ui/src/components/EditWithIcon.svelte b/packages/ui/src/components/EditWithIcon.svelte index 286507a95b..d0f0805f37 100644 --- a/packages/ui/src/components/EditWithIcon.svelte +++ b/packages/ui/src/components/EditWithIcon.svelte @@ -15,6 +15,7 @@ <script lang="ts"> import type { Asset } from '@anticrm/platform' + import { createEventDispatcher } from 'svelte' import type { AnySvelteComponent } from '../types' import Icon from './Icon.svelte' import IconClose from './icons/Close.svelte' @@ -33,13 +34,14 @@ focus = false } } + const dispatch = createEventDispatcher() </script> <div class="flex-between editbox" style={width ? 'width: ' + width : ''} on:click={() => textHTML.focus()}> <div class="mr-2"><Icon {icon} size={'small'} /></div> - <input bind:this={textHTML} type="text" bind:value {placeholder} on:change/> + <input bind:this={textHTML} type="text" bind:value {placeholder} on:change on:input on:keydown/> {#if value} - <div class="ml-2 btn" on:click={() => { textHTML.value = ''; textHTML.dispatchEvent(new Event('change')) }}> + <div class="ml-2 btn" on:click={() => { value = ''; dispatch('change', '') }}> <Icon icon={IconClose} size={'x-small'} /> </div> {/if} diff --git a/packages/ui/src/components/SearchEdit.svelte b/packages/ui/src/components/SearchEdit.svelte new file mode 100644 index 0000000000..65145030a1 --- /dev/null +++ b/packages/ui/src/components/SearchEdit.svelte @@ -0,0 +1,42 @@ +<script lang="ts"> + import { translate } from '@anticrm/platform' + + import { createEventDispatcher } from 'svelte' + import ui from '../plugin' + import EditWithIcon from './EditWithIcon.svelte' + import IconSearch from './icons/Search.svelte' + + export let value: string = '' + + $: _search = value + const dispatch = createEventDispatcher() + let placeholder = '' + + translate(ui.string.Search, {}).then((v) => { + placeholder = v + }) +</script> + +<EditWithIcon + icon={IconSearch} + placeholder={placeholder} + bind:value={_search} + on:change={() => { + if (_search === '') { + value = '' + dispatch('change', '') + } + }} + on:input={() => { + if (_search === '') { + value = '' + dispatch('change', '') + } + }} + on:keydown={(evt) => { + if (evt.key === 'Enter') { + value = _search + dispatch('change', _search) + } + }} +/> diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts index a925c511dd..df3efccda9 100644 --- a/packages/ui/src/index.ts +++ b/packages/ui/src/index.ts @@ -53,6 +53,7 @@ export { default as Row } from './components/Row.svelte' // export { default as CheckBoxWithLabel } from './components/CheckBoxWithLabel.svelte' // export { default as CheckBoxList } from './components/CheckBoxList.svelte.txt' export { default as EditWithIcon } from './components/EditWithIcon.svelte' +export { default as SearchEdit } from './components/SearchEdit.svelte' export { default as Loading } from './components/Loading.svelte' export { default as Spinner } from './components/Spinner.svelte' export { default as Popup } from './components/Popup.svelte' diff --git a/packages/ui/src/plugin.ts b/packages/ui/src/plugin.ts index 4d632ee4e9..a2ce649acd 100644 --- a/packages/ui/src/plugin.ts +++ b/packages/ui/src/plugin.ts @@ -1,15 +1,15 @@ // // Copyright © 2020, 2021 Anticrm Platform Contributors. // Copyright © 2021 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. // @@ -29,6 +29,7 @@ export default plugin(uiId, { Hours: '' as IntlString, Days: '' as IntlString, ShowMore: '' as IntlString, - ShowLess: '' as IntlString + ShowLess: '' as IntlString, + Search: '' as IntlString } -}) \ No newline at end of file +}) diff --git a/plugins/contact-resources/src/components/Contacts.svelte b/plugins/contact-resources/src/components/Contacts.svelte index 35a2bc9f7b..da7ccd8909 100644 --- a/plugins/contact-resources/src/components/Contacts.svelte +++ b/plugins/contact-resources/src/components/Contacts.svelte @@ -15,15 +15,20 @@ --> <script lang="ts"> + import { Doc, DocumentQuery } from '@anticrm/core' import { getClient } from '@anticrm/presentation' - import { Button, EditWithIcon, Icon, IconAdd, IconSearch, Label, ScrollBox, showPopup } from '@anticrm/ui' + import { Button, Icon, IconAdd, Label, ScrollBox, SearchEdit, showPopup } from '@anticrm/ui' import view, { Viewlet } from '@anticrm/view' import { Table } from '@anticrm/view-resources' import contact from '../plugin' import CreateContact from './CreateContact.svelte' let search = '' - $: resultQuery = search === '' ? { } : { $search: search } + let resultQuery: DocumentQuery<Doc> = {} + + function updateResultQuery (search: string): void { + resultQuery = (search === '') ? { } : { $search: search } + } const client = getClient() const tableDescriptor = client.findOne<Viewlet>(view.class.Viewlet, { attachTo: contact.class.Contact, descriptor: view.viewlet.Table }) @@ -42,7 +47,9 @@ </div> </div> - <EditWithIcon icon={IconSearch} placeholder={'Search'} bind:value={search} on:change={() => { resultQuery = {} } } /> + <SearchEdit bind:value={search} on:change={() => { + updateResultQuery(search) + }}/> <Button icon={IconAdd} label={contact.string.Create} primary={true} size={'small'} on:click={(ev) => showCreateDialog(ev)}/> </div> diff --git a/plugins/inventory-resources/src/components/Categories.svelte b/plugins/inventory-resources/src/components/Categories.svelte index d62a675364..d51a7fb2b5 100644 --- a/plugins/inventory-resources/src/components/Categories.svelte +++ b/plugins/inventory-resources/src/components/Categories.svelte @@ -14,13 +14,18 @@ // limitations under the License. --> <script lang="ts"> - import { Button, EditWithIcon, Icon, IconSearch, Label, ScrollBox, showPopup } from '@anticrm/ui' - import HierarchyView from './HierarchyView.svelte' - import CreateCategory from './CreateCategory.svelte' + import { Doc, DocumentQuery } from '@anticrm/core' + import { Button, Icon, Label, ScrollBox, SearchEdit, showPopup } from '@anticrm/ui' import inventory from '../plugin' + import CreateCategory from './CreateCategory.svelte' + import HierarchyView from './HierarchyView.svelte' let search = '' - $: resultQuery = search === '' ? {} : { $search: search } + let resultQuery: DocumentQuery<Doc> = {} + + function updateResultQuery (search: string): void { + resultQuery = (search === '') ? { } : { $search: search } + } function showCreateDialog (ev: Event) { showPopup(CreateCategory, { space: inventory.space.Category }, ev.target as HTMLElement) @@ -35,14 +40,9 @@ </div> </div> - <EditWithIcon - icon={IconSearch} - placeholder={'Search'} - bind:value={search} - on:change={() => { - resultQuery = {} - }} - /> + <SearchEdit bind:value={search} on:change={() => { + updateResultQuery(search) + }}/> <Button label={inventory.string.CreateCategoryShort} primary={true} diff --git a/plugins/lead-resources/src/components/Customers.svelte b/plugins/lead-resources/src/components/Customers.svelte index 3362901a5e..f4b9fd21bc 100644 --- a/plugins/lead-resources/src/components/Customers.svelte +++ b/plugins/lead-resources/src/components/Customers.svelte @@ -15,13 +15,17 @@ --> <script lang="ts"> - import { EditWithIcon, Icon, IconSearch, Label, ScrollBox } from '@anticrm/ui' - + import { Doc, DocumentQuery } from '@anticrm/core' + import { Icon, Label, ScrollBox, SearchEdit } from '@anticrm/ui' import { Table } from '@anticrm/view-resources' import lead from '../plugin' let search = '' - $: resultQuery = search === '' ? { } : { $search: search } + let resultQuery: DocumentQuery<Doc> = {} + + function updateResultQuery (search: string): void { + resultQuery = (search === '') ? { } : { $search: search } + } </script> <div class="customers-header-container"> @@ -32,7 +36,9 @@ </div> </div> - <EditWithIcon icon={IconSearch} placeholder={'Search'} bind:value={search} on:change={() => { resultQuery = {} } } /> + <SearchEdit bind:value={search} on:change={() => { + updateResultQuery(search) + }}/> </div> <div class="container"> diff --git a/plugins/recruit-resources/src/components/Candidates.svelte b/plugins/recruit-resources/src/components/Candidates.svelte index 000e8b35ae..6d7764d3f1 100644 --- a/plugins/recruit-resources/src/components/Candidates.svelte +++ b/plugins/recruit-resources/src/components/Candidates.svelte @@ -15,18 +15,21 @@ --> <script lang="ts"> + import contact from '@anticrm/contact' + import { Doc, DocumentQuery } from '@anticrm/core' import { getClient } from '@anticrm/presentation' - - import { Button, EditWithIcon, Icon, IconSearch, Label, ScrollBox, showPopup } from '@anticrm/ui' - + import { Button, Icon, Label, ScrollBox, SearchEdit, showPopup } from '@anticrm/ui' + import view, { Viewlet } from '@anticrm/view' import { Table } from '@anticrm/view-resources' import recruit from '../plugin' - import contact from '@anticrm/contact' - import view, { Viewlet } from '@anticrm/view' import CreateCandidate from './CreateCandidate.svelte' let search = '' - $: resultQuery = search === '' ? { } : { $search: search } + let resultQuery: DocumentQuery<Doc> = {} + + function updateResultQuery (search: string): void { + resultQuery = (search === '') ? { } : { $search: search } + } const client = getClient() const tableDescriptor = client.findOne<Viewlet>(view.class.Viewlet, { attachTo: recruit.mixin.Candidate, descriptor: view.viewlet.Table }) @@ -34,6 +37,7 @@ function showCreateDialog (ev: Event) { showPopup(CreateCandidate, { space: recruit.space.CandidatesPublic }, ev.target as HTMLElement) } + </script> <div class="candidates-header-container"> @@ -44,7 +48,9 @@ </div> </div> - <EditWithIcon icon={IconSearch} placeholder={'Search'} bind:value={search} on:change={() => { resultQuery = {} } } /> + <SearchEdit bind:value={search} on:change={() => { + updateResultQuery(search) + }}/> <Button label={recruit.string.Create} primary={true} size={'small'} on:click={(ev) => showCreateDialog(ev)}/> </div> diff --git a/plugins/workbench-resources/src/components/SpaceHeader.svelte b/plugins/workbench-resources/src/components/SpaceHeader.svelte index 8f6e78eedb..c3433a321f 100644 --- a/plugins/workbench-resources/src/components/SpaceHeader.svelte +++ b/plugins/workbench-resources/src/components/SpaceHeader.svelte @@ -14,17 +14,15 @@ --> <script lang="ts"> - import core, { Class, Doc, WithLookup } from '@anticrm/core' import type { Ref, Space } from '@anticrm/core' - import { getClient, createQuery } from '@anticrm/presentation' - import { Icon, Button, EditWithIcon, IconSearch, Tooltip } from '@anticrm/ui' + import core, { Class, Doc, WithLookup } from '@anticrm/core' + import { createQuery, getClient } from '@anticrm/presentation' import type { AnyComponent } from '@anticrm/ui' - import { showPopup } from '@anticrm/ui' - import view, { Viewlet } from '@anticrm/view' - - import { classIcon } from '../utils' + import { Button, Icon, SearchEdit, showPopup, Tooltip } from '@anticrm/ui' + import { Viewlet } from '@anticrm/view' + import { createEventDispatcher } from 'svelte' import workbench from '../plugin' - + import { classIcon } from '../utils' import Header from './Header.svelte' export let spaceId: Ref<Space> | undefined @@ -37,15 +35,24 @@ const client = getClient() const query = createQuery() let space: Space | undefined + const dispatch = createEventDispatcher() + + const prevSpaceId = spaceId $: query.query(core.class.Space, { _id: spaceId }, result => { space = result[0] }) - function showCreateDialog(ev: Event) { + function showCreateDialog (ev: Event) { showPopup(createItemDialog as AnyComponent, { space: spaceId }, ev.target as HTMLElement) } let selectedViewlet = 0 $: viewlet = viewlets[selectedViewlet] + + $: if (prevSpaceId !== spaceId) { + search = '' + dispatch('search', '') + } + </script> <div class="spaceheader-container"> @@ -55,14 +62,16 @@ <div class="flex"> {#each viewlets as viewlet, i} <Tooltip label={viewlet.$lookup?.descriptor?.label} direction={'top'}> - <div class="flex-center btn" class:selected={selectedViewlet === i} on:click={()=>{ selectedViewlet = i }}> + <div class="flex-center btn" class:selected={selectedViewlet === i} on:click={() => { selectedViewlet = i }}> <Icon icon={viewlet.$lookup?.descriptor?.icon} size={'small'}/> </div> </Tooltip> {/each} </div> {/if} - <EditWithIcon icon={IconSearch} placeholder={'Search'} bind:value={search} /> + <SearchEdit bind:value={search} on:change={() => { + dispatch('search', search) + }}/> {#if createItemDialog} <Button label={workbench.string.Create} primary={true} size={'small'} on:click={(ev) => showCreateDialog(ev)}/> {/if} diff --git a/plugins/workbench-resources/src/components/SpaceView.svelte b/plugins/workbench-resources/src/components/SpaceView.svelte index 9cf51edad0..02a8db6264 100644 --- a/plugins/workbench-resources/src/components/SpaceView.svelte +++ b/plugins/workbench-resources/src/components/SpaceView.svelte @@ -36,11 +36,13 @@ let viewlets: WithLookup<Viewlet>[] = [] - async function update(attachTo?: Ref<Class<Doc>>, currentSpace?: Ref<Space>): Promise<void> { + async function update (attachTo?: Ref<Class<Doc>>, currentSpace?: Ref<Space>): Promise<void> { if (attachTo) { - viewlets = await client.findAll(view.class.Viewlet, { attachTo }, { lookup: { - descriptor: core.class.Class - }}) + viewlets = await client.findAll(view.class.Viewlet, { attachTo }, { + lookup: { + descriptor: core.class.Class + } + }) _class = attachTo } viewlet = viewlets[0] @@ -48,12 +50,6 @@ } $: update(currentView?.class, currentSpace) - - function resetSearch (_space: Ref<Space> | undefined): void { - search = '' - } - - $: resetSearch(currentSpace) </script> <SpaceHeader spaceId={space} {_class} {viewlets} {createItemDialog} bind:search={search} bind:viewlet={viewlet} />