mirror of
https://github.com/hcengineering/platform.git
synced 2024-12-22 11:01:54 +03:00
UBER-177: fixed Filter pop-ups (#3225)
Signed-off-by: Alexander Platov <sas_lord@mail.ru>
This commit is contained in:
parent
c0bb68be9e
commit
78034e6a00
@ -745,7 +745,7 @@
|
|||||||
.list-container .datetime-button,
|
.list-container .datetime-button,
|
||||||
.list-container .datetime-button:hover {
|
.list-container .datetime-button:hover {
|
||||||
background-color: var(--theme-list-button-color) !important;
|
background-color: var(--theme-list-button-color) !important;
|
||||||
.icon {
|
.icon, .btn-icon {
|
||||||
margin-right: .5rem;
|
margin-right: .5rem;
|
||||||
color: var(--theme-halfcontent-color) !important;
|
color: var(--theme-halfcontent-color) !important;
|
||||||
}
|
}
|
||||||
|
@ -48,11 +48,12 @@
|
|||||||
max-width: 40rem !important;
|
max-width: 40rem !important;
|
||||||
}
|
}
|
||||||
.header {
|
.header {
|
||||||
margin-bottom: .5rem;
|
|
||||||
padding: .5rem;
|
padding: .5rem;
|
||||||
border-bottom: 1px solid var(--theme-popup-divider);
|
|
||||||
|
&:not(.no-border) {
|
||||||
&.no-border { border-bottom-color: transparent; }
|
margin-bottom: .5rem;
|
||||||
|
border-bottom: 1px solid var(--theme-popup-divider);
|
||||||
|
}
|
||||||
.clear-btn {
|
.clear-btn {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@ -345,11 +346,13 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
|
margin: 0 .5rem;
|
||||||
padding: .25rem .5rem;
|
padding: .25rem .5rem;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
min-height: 2.25rem;
|
min-height: 2.25rem;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
color: var(--theme-caption-color);
|
color: var(--theme-caption-color);
|
||||||
|
border-radius: .25rem;
|
||||||
outline: none;
|
outline: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
|
@ -153,11 +153,7 @@
|
|||||||
>
|
>
|
||||||
<svelte:fragment slot="item" let:item={itemId}>
|
<svelte:fragment slot="item" let:item={itemId}>
|
||||||
{@const item = filteredObjects[itemId]}
|
{@const item = filteredObjects[itemId]}
|
||||||
<button
|
<button class="menu-item withList w-full" on:click={() => dispatch('close', item.id)}>
|
||||||
class="menu-item withList w-full"
|
|
||||||
class:selected={item.isSelected}
|
|
||||||
on:click={() => dispatch('close', item.id)}
|
|
||||||
>
|
|
||||||
<div class="flex-row-center flex-grow pointer-events-none">
|
<div class="flex-row-center flex-grow pointer-events-none">
|
||||||
{#if item.component}
|
{#if item.component}
|
||||||
<div class="flex-grow clear-mins"><svelte:component this={item.component} {...item.props} /></div>
|
<div class="flex-grow clear-mins"><svelte:component this={item.component} {...item.props} /></div>
|
||||||
|
@ -70,6 +70,7 @@
|
|||||||
"DM": "Direct message",
|
"DM": "Direct message",
|
||||||
"DMNotification": "Sent you a message",
|
"DMNotification": "Sent you a message",
|
||||||
"ConfigLabel": "Chat",
|
"ConfigLabel": "Chat",
|
||||||
"ConfigDescription": "Extension to perform text communications"
|
"ConfigDescription": "Extension to perform text communications",
|
||||||
|
"LastMessage": "Last message"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -70,6 +70,7 @@
|
|||||||
"DM": "Личное сообщение",
|
"DM": "Личное сообщение",
|
||||||
"DMNotification": "Отправил сообщение",
|
"DMNotification": "Отправил сообщение",
|
||||||
"ConfigLabel": "Чат",
|
"ConfigLabel": "Чат",
|
||||||
"ConfigDescription": "Расширение для текстовых переписок"
|
"ConfigDescription": "Расширение для текстовых переписок",
|
||||||
|
"LastMessage": "Последнее сообщение"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -15,7 +15,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { ChannelProvider } from '@hcengineering/contact'
|
import { ChannelProvider } from '@hcengineering/contact'
|
||||||
import { Ref } from '@hcengineering/core'
|
import { Ref } from '@hcengineering/core'
|
||||||
import { CheckBox, Icon, Label, resizeObserver } from '@hcengineering/ui'
|
import { IconCheck, Icon, Label, resizeObserver } from '@hcengineering/ui'
|
||||||
import { Filter } from '@hcengineering/view'
|
import { Filter } from '@hcengineering/view'
|
||||||
import { FILTER_DEBOUNCE_MS, FilterQuery, sortFilterValues } from '@hcengineering/view-resources'
|
import { FILTER_DEBOUNCE_MS, FilterQuery, sortFilterValues } from '@hcengineering/view-resources'
|
||||||
import { createEventDispatcher } from 'svelte'
|
import { createEventDispatcher } from 'svelte'
|
||||||
@ -65,28 +65,28 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}>
|
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}>
|
||||||
|
<div class="menu-space" />
|
||||||
<div class="scroll">
|
<div class="scroll">
|
||||||
<div class="box">
|
<div class="box">
|
||||||
{#each sortFilterValues($channelProviders, (v) => isSelected(v, selected)) as element}
|
{#each sortFilterValues($channelProviders, (v) => isSelected(v, selected)) as element}
|
||||||
<button
|
<button
|
||||||
class="menu-item"
|
class="menu-item no-focus flex-row-center content-pointer-events-none"
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
handleFilterToggle(element)
|
handleFilterToggle(element)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div class="flex-between w-full">
|
{#if element.icon}
|
||||||
<div class="flex">
|
<div class="icon"><Icon icon={element.icon} size={'small'} /></div>
|
||||||
<div class="check pointer-events-none">
|
{/if}
|
||||||
<CheckBox checked={isSelected(element, selected)} primary />
|
<span class="overflow-label label flex-grow"><Label label={element.label} /></span>
|
||||||
</div>
|
<div class="check">
|
||||||
{#if element.icon}
|
{#if isSelected(element, selected)}
|
||||||
<span class="mr-2"><Icon icon={element.icon} size="inline" /></span>
|
<Icon icon={IconCheck} size={'small'} />
|
||||||
{/if}
|
{/if}
|
||||||
<Label label={element.label} />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="menu-space" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -17,11 +17,20 @@
|
|||||||
import core, { Doc, FindResult, getObjectValue, Ref, SortingOrder, Space } from '@hcengineering/core'
|
import core, { Doc, FindResult, getObjectValue, Ref, SortingOrder, Space } from '@hcengineering/core'
|
||||||
import { translate } from '@hcengineering/platform'
|
import { translate } from '@hcengineering/platform'
|
||||||
import presentation, { getClient } from '@hcengineering/presentation'
|
import presentation, { getClient } from '@hcengineering/presentation'
|
||||||
import ui, { addNotification, deviceOptionsStore, Icon, IconCheck, Loading, resizeObserver } from '@hcengineering/ui'
|
import ui, {
|
||||||
|
addNotification,
|
||||||
|
deviceOptionsStore,
|
||||||
|
Icon,
|
||||||
|
IconCheck,
|
||||||
|
Loading,
|
||||||
|
resizeObserver,
|
||||||
|
EditWithIcon,
|
||||||
|
IconSearch
|
||||||
|
} from '@hcengineering/ui'
|
||||||
import { Filter } from '@hcengineering/view'
|
import { Filter } from '@hcengineering/view'
|
||||||
import { FILTER_DEBOUNCE_MS, FilterRemovedNotification, sortFilterValues } from '@hcengineering/view-resources'
|
import { FILTER_DEBOUNCE_MS, FilterRemovedNotification, sortFilterValues } from '@hcengineering/view-resources'
|
||||||
import view from '@hcengineering/view-resources/src/plugin'
|
import view from '@hcengineering/view-resources/src/plugin'
|
||||||
import { createEventDispatcher, onMount } from 'svelte'
|
import { createEventDispatcher } from 'svelte'
|
||||||
import EmployeePresenter from './EmployeePresenter.svelte'
|
import EmployeePresenter from './EmployeePresenter.svelte'
|
||||||
|
|
||||||
export let filter: Filter
|
export let filter: Filter
|
||||||
@ -113,15 +122,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
let search: string = ''
|
let search: string = ''
|
||||||
let phTraslate: string = ''
|
|
||||||
let searchInput: HTMLInputElement
|
|
||||||
$: translate(presentation.string.Search, {}).then((res) => {
|
|
||||||
phTraslate = res
|
|
||||||
})
|
|
||||||
|
|
||||||
onMount(() => {
|
|
||||||
if (searchInput && !$deviceOptionsStore.isMobile) searchInput.focus()
|
|
||||||
})
|
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
$: getValues(search)
|
$: getValues(search)
|
||||||
@ -129,14 +129,16 @@
|
|||||||
|
|
||||||
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}>
|
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}>
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<input
|
<EditWithIcon
|
||||||
bind:this={searchInput}
|
icon={IconSearch}
|
||||||
type="text"
|
size={'large'}
|
||||||
|
width={'100%'}
|
||||||
|
focus={!$deviceOptionsStore.isMobile}
|
||||||
bind:value={search}
|
bind:value={search}
|
||||||
|
placeholder={presentation.string.Search}
|
||||||
on:change={() => {
|
on:change={() => {
|
||||||
getValues(search)
|
getValues(search)
|
||||||
}}
|
}}
|
||||||
placeholder={phTraslate}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="scroll">
|
<div class="scroll">
|
||||||
@ -146,24 +148,23 @@
|
|||||||
{:else}
|
{:else}
|
||||||
{#each sortFilterValues(values, (v) => isSelected(v, filter.value)) as value}
|
{#each sortFilterValues(values, (v) => isSelected(v, filter.value)) as value}
|
||||||
<button
|
<button
|
||||||
class="menu-item no-focus"
|
class="menu-item no-focus flex-row-center"
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
handleFilterToggle(value)
|
handleFilterToggle(value)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div class="flex-between w-full">
|
<div class="clear-mins flex-grow">
|
||||||
<div class="flex-row-center">
|
<EmployeePresenter {value} shouldShowPlaceholder defaultName={ui.string.NotSelected} disabled />
|
||||||
<EmployeePresenter {value} shouldShowPlaceholder defaultName={ui.string.NotSelected} disabled />
|
</div>
|
||||||
</div>
|
<div class="check pointer-events-none">
|
||||||
<div class="pointer-events-none">
|
{#if isSelected(value, filter.value)}
|
||||||
{#if isSelected(value, filter.value)}
|
<Icon icon={IconCheck} size={'small'} />
|
||||||
<Icon icon={IconCheck} size={'small'} />
|
{/if}
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
{/each}
|
{/each}
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="menu-space" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -27,12 +27,12 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if value}
|
{#if value}
|
||||||
<DocNavLink {disabled} object={value} {inline} component={recruit.component.EditVacancy}>
|
<DocNavLink {disabled} object={value} {inline} noUnderline={disabled} component={recruit.component.EditVacancy}>
|
||||||
<div class="flex-presenter" class:inline-presenter={inline} use:tooltip={{ label: getEmbeddedLabel(value.name) }}>
|
<div class="flex-presenter" class:inline-presenter={inline} use:tooltip={{ label: getEmbeddedLabel(value.name) }}>
|
||||||
{#if !inline}
|
{#if !inline}
|
||||||
<div class="icon"><Icon icon={recruit.icon.Vacancy} size={'small'} /></div>
|
<div class="icon"><Icon icon={recruit.icon.Vacancy} size={'small'} /></div>
|
||||||
{/if}
|
{/if}
|
||||||
<span class="label">{value.name}</span>
|
<span class="label" class:no-underline={disabled}>{value.name}</span>
|
||||||
</div>
|
</div>
|
||||||
</DocNavLink>
|
</DocNavLink>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -14,13 +14,14 @@
|
|||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Class, Doc, FindResult, Ref } from '@hcengineering/core'
|
import { Class, Doc, FindResult, Ref } from '@hcengineering/core'
|
||||||
import { translate } from '@hcengineering/platform'
|
|
||||||
import presentation, { getClient } from '@hcengineering/presentation'
|
import presentation, { getClient } from '@hcengineering/presentation'
|
||||||
import { TagCategory, TagElement } from '@hcengineering/tags'
|
import { TagCategory, TagElement } from '@hcengineering/tags'
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Icon,
|
Icon,
|
||||||
IconCheck,
|
IconCheck,
|
||||||
|
IconSearch,
|
||||||
|
EditWithIcon,
|
||||||
Label,
|
Label,
|
||||||
Loading,
|
Loading,
|
||||||
deviceOptionsStore,
|
deviceOptionsStore,
|
||||||
@ -31,7 +32,7 @@
|
|||||||
} from '@hcengineering/ui'
|
} from '@hcengineering/ui'
|
||||||
import { Filter } from '@hcengineering/view'
|
import { Filter } from '@hcengineering/view'
|
||||||
import { FILTER_DEBOUNCE_MS, FilterQuery, sortFilterValues } from '@hcengineering/view-resources'
|
import { FILTER_DEBOUNCE_MS, FilterQuery, sortFilterValues } from '@hcengineering/view-resources'
|
||||||
import { createEventDispatcher, onMount } from 'svelte'
|
import { createEventDispatcher } from 'svelte'
|
||||||
import tags from '../plugin'
|
import tags from '../plugin'
|
||||||
import { tagLevel } from '../utils'
|
import { tagLevel } from '../utils'
|
||||||
import WeightPopup from './WeightPopup.svelte'
|
import WeightPopup from './WeightPopup.svelte'
|
||||||
@ -76,15 +77,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
let search: string = ''
|
let search: string = ''
|
||||||
let phTraslate: string = ''
|
|
||||||
let searchInput: HTMLInputElement
|
|
||||||
$: translate(presentation.string.Search, {}).then((res) => {
|
|
||||||
phTraslate = res
|
|
||||||
})
|
|
||||||
|
|
||||||
onMount(() => {
|
|
||||||
if (searchInput && !$deviceOptionsStore.isMobile) searchInput.focus()
|
|
||||||
})
|
|
||||||
|
|
||||||
const toggleGroup = (ev: MouseEvent): void => {
|
const toggleGroup = (ev: MouseEvent): void => {
|
||||||
const el: HTMLElement = ev.currentTarget as HTMLElement
|
const el: HTMLElement = ev.currentTarget as HTMLElement
|
||||||
@ -137,18 +129,20 @@
|
|||||||
|
|
||||||
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}>
|
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}>
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<input
|
<EditWithIcon
|
||||||
bind:this={searchInput}
|
icon={IconSearch}
|
||||||
type="text"
|
size={'large'}
|
||||||
|
width={'100%'}
|
||||||
|
focus={!$deviceOptionsStore.isMobile}
|
||||||
bind:value={search}
|
bind:value={search}
|
||||||
|
placeholder={presentation.string.Search}
|
||||||
on:change={() => {
|
on:change={() => {
|
||||||
getValues(search)
|
getValues(search)
|
||||||
}}
|
}}
|
||||||
placeholder={phTraslate}
|
|
||||||
/>
|
/>
|
||||||
{#if schema !== '0'}
|
{#if schema !== '0'}
|
||||||
<div class="flex-row-center flex-between flex-grow p-1">
|
<div class="flex-between w-full mt-2">
|
||||||
<Label label={tags.string.Weight} />
|
<span class="overflow-label pl-2 mr-2"><Label label={tags.string.Weight} /></span>
|
||||||
<Button
|
<Button
|
||||||
label={tagLevelLabel}
|
label={tagLevelLabel}
|
||||||
icon={tagLevelIcon}
|
icon={tagLevelIcon}
|
||||||
@ -170,9 +164,10 @@
|
|||||||
{#if objectsPromise}
|
{#if objectsPromise}
|
||||||
<Loading />
|
<Loading />
|
||||||
{:else}
|
{:else}
|
||||||
{#each categories as cat}
|
{#each categories as cat, i}
|
||||||
{@const values = objects.filter((el) => el.category === cat._id)}
|
{@const values = objects.filter((el) => el.category === cat._id)}
|
||||||
{#if values.length > 0}
|
{#if values.length > 0}
|
||||||
|
{#if i > 0}<div class="menu-separator" />{/if}
|
||||||
<div class="sticky-wrapper">
|
<div class="sticky-wrapper">
|
||||||
<button
|
<button
|
||||||
class="menu-group__header"
|
class="menu-group__header"
|
||||||
@ -198,21 +193,17 @@
|
|||||||
<div class="menu-group">
|
<div class="menu-group">
|
||||||
{#each sortFilterValues(values, isSelected) as element}
|
{#each sortFilterValues(values, isSelected) as element}
|
||||||
<button
|
<button
|
||||||
class="menu-item"
|
class="menu-item no-focus flex-row-center"
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
handleFilterToggle(element)
|
handleFilterToggle(element)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div class="flex-between w-full">
|
<div class="tag" style="background-color: {getPlatformColor(element.color)};" />
|
||||||
<div class="flex">
|
<span class="overflow-label label flex-grow">{element.title}</span>
|
||||||
<div class="tag" style="background-color: {getPlatformColor(element.color)};" />
|
<div class="check pointer-events-none">
|
||||||
{element.title}
|
{#if isSelected(element)}
|
||||||
</div>
|
<Icon icon={IconCheck} size={'small'} />
|
||||||
<div class="pointer-events-none">
|
{/if}
|
||||||
{#if isSelected(element)}
|
|
||||||
<Icon icon={IconCheck} size={'small'} />
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
{/each}
|
{/each}
|
||||||
@ -223,6 +214,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="menu-space" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Button, resizeObserver } from '@hcengineering/ui'
|
import { resizeObserver, Icon, IconCheck, Label } from '@hcengineering/ui'
|
||||||
import { createEventDispatcher } from 'svelte'
|
import { createEventDispatcher } from 'svelte'
|
||||||
import tags from '../plugin'
|
import tags from '../plugin'
|
||||||
import { tagLevel } from '../utils'
|
import { tagLevel } from '../utils'
|
||||||
@ -27,34 +27,36 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="selectPopup max-width-40" use:resizeObserver={() => dispatch('changeContent')}>
|
<div class="selectPopup max-width-40" use:resizeObserver={() => dispatch('changeContent')}>
|
||||||
<div class="header no-border p-3">
|
<div class="menu-space" />
|
||||||
{#each labels as l, i}
|
<div class="scroll">
|
||||||
<div class="flex gap-2 p-1">
|
<div class="box">
|
||||||
|
{#each labels as l, i}
|
||||||
{#if schema === '9'}
|
{#if schema === '9'}
|
||||||
{#each Object.entries(tagLevel) as k, j}
|
{#each Object.entries(tagLevel) as k, j}
|
||||||
{@const valueK = i * 3 + j}
|
{@const valueK = i * 3 + j}
|
||||||
<Button
|
<button class="menu-item flex-row-center" on:click={() => dispatch('close', valueK)}>
|
||||||
label={l}
|
<div class="icon"><Icon icon={k[1]} size={'small'} /></div>
|
||||||
icon={k[1]}
|
<span class="overflow-label label flex-grow"><Label label={l} /></span>
|
||||||
size={'small'}
|
<div class="check pointer-events-none">
|
||||||
justify={'left'}
|
{#if value === valueK}
|
||||||
selected={value === valueK}
|
<Icon icon={IconCheck} size={'small'} />
|
||||||
on:click={() => dispatch('close', valueK)}
|
{/if}
|
||||||
width={'8rem'}
|
</div>
|
||||||
/>
|
</button>
|
||||||
{/each}
|
{/each}
|
||||||
{:else}
|
{:else}
|
||||||
{@const valueK = i * 3}
|
{@const valueK = i * 3}
|
||||||
<Button
|
<button class="menu-item flex-row-center" on:click={() => dispatch('close', valueK)}>
|
||||||
label={l}
|
<span class="overflow-label label flex-grow"><Label label={l} /></span>
|
||||||
size={'small'}
|
<div class="check pointer-events-none">
|
||||||
justify={'left'}
|
{#if value === valueK}
|
||||||
selected={value === valueK}
|
<Icon icon={IconCheck} size={'small'} />
|
||||||
on:click={() => dispatch('close', valueK)}
|
{/if}
|
||||||
width={'8rem'}
|
</div>
|
||||||
/>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
{/each}
|
||||||
{/each}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="menu-space" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
export let inline: boolean = false
|
export let inline: boolean = false
|
||||||
export let colorInherit: boolean = false
|
export let colorInherit: boolean = false
|
||||||
export let accent: boolean = false
|
export let accent: boolean = false
|
||||||
|
export let disabled: boolean = false
|
||||||
|
export let oneLine: boolean = false
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
@ -46,7 +48,7 @@
|
|||||||
{#if shouldShowAvatar}
|
{#if shouldShowAvatar}
|
||||||
<div class="state-container" class:inline style="background-color: {fill}" />
|
<div class="state-container" class:inline style="background-color: {fill}" />
|
||||||
{/if}
|
{/if}
|
||||||
<span class="label nowrap">{value.name}</span>
|
<span class="overflow-label label" class:nowrap={oneLine} class:no-underline={disabled}>{value.name}</span>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
@ -14,13 +14,21 @@
|
|||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { DocumentQuery, FindResult, Ref, SortingOrder } from '@hcengineering/core'
|
import { DocumentQuery, FindResult, Ref, SortingOrder } from '@hcengineering/core'
|
||||||
import { translate } from '@hcengineering/platform'
|
|
||||||
import presentation, { getClient } from '@hcengineering/presentation'
|
import presentation, { getClient } from '@hcengineering/presentation'
|
||||||
import { Project, Milestone, MilestoneStatus } from '@hcengineering/tracker'
|
import { Project, Milestone, MilestoneStatus } from '@hcengineering/tracker'
|
||||||
import ui, { CheckBox, Icon, Label, Loading, deviceOptionsStore, resizeObserver } from '@hcengineering/ui'
|
import ui, {
|
||||||
|
IconCheck,
|
||||||
|
Icon,
|
||||||
|
Label,
|
||||||
|
Loading,
|
||||||
|
deviceOptionsStore,
|
||||||
|
resizeObserver,
|
||||||
|
EditWithIcon,
|
||||||
|
IconSearch
|
||||||
|
} from '@hcengineering/ui'
|
||||||
import { FILTER_DEBOUNCE_MS, sortFilterValues } from '@hcengineering/view-resources'
|
import { FILTER_DEBOUNCE_MS, sortFilterValues } from '@hcengineering/view-resources'
|
||||||
import view, { Filter } from '@hcengineering/view'
|
import view, { Filter } from '@hcengineering/view'
|
||||||
import { createEventDispatcher, onMount } from 'svelte'
|
import { createEventDispatcher } from 'svelte'
|
||||||
import tracker from '../../plugin'
|
import tracker from '../../plugin'
|
||||||
import { milestoneStatusAssets } from '../../types'
|
import { milestoneStatusAssets } from '../../types'
|
||||||
import MilestoneTitlePresenter from './MilestoneTitlePresenter.svelte'
|
import MilestoneTitlePresenter from './MilestoneTitlePresenter.svelte'
|
||||||
@ -34,11 +42,6 @@
|
|||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
let search: string = ''
|
let search: string = ''
|
||||||
let phTraslate: string = ''
|
|
||||||
let searchInput: HTMLInputElement
|
|
||||||
$: translate(presentation.string.Search, {}).then((res) => {
|
|
||||||
phTraslate = res
|
|
||||||
})
|
|
||||||
|
|
||||||
let values: Milestone[] = []
|
let values: Milestone[] = []
|
||||||
let objectsPromise: Promise<FindResult<Milestone>> | undefined = undefined
|
let objectsPromise: Promise<FindResult<Milestone>> | undefined = undefined
|
||||||
@ -110,23 +113,21 @@
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
|
||||||
if (searchInput && !$deviceOptionsStore.isMobile) searchInput.focus()
|
|
||||||
})
|
|
||||||
|
|
||||||
getValues(search)
|
getValues(search)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}>
|
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}>
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<input
|
<EditWithIcon
|
||||||
bind:this={searchInput}
|
icon={IconSearch}
|
||||||
type="text"
|
size={'large'}
|
||||||
|
width={'100%'}
|
||||||
|
focus={!$deviceOptionsStore.isMobile}
|
||||||
bind:value={search}
|
bind:value={search}
|
||||||
|
placeholder={presentation.string.Search}
|
||||||
on:change={() => {
|
on:change={() => {
|
||||||
getValues(search)
|
getValues(search)
|
||||||
}}
|
}}
|
||||||
placeholder={phTraslate}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="scroll">
|
<div class="scroll">
|
||||||
@ -135,41 +136,46 @@
|
|||||||
<Loading />
|
<Loading />
|
||||||
{:else}
|
{:else}
|
||||||
<button
|
<button
|
||||||
class="menu-item"
|
class="menu-item no-focus flex-row-center"
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
handleFilterToggle(undefined)
|
handleFilterToggle(undefined)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div class="flex clear-mins">
|
<div class="overflow-label flex-grow">
|
||||||
<div class="check pointer-events-none">
|
|
||||||
<CheckBox checked={isSelected(undefined, selectedValues)} primary />
|
|
||||||
</div>
|
|
||||||
<Label label={ui.string.NotSelected} />
|
<Label label={ui.string.NotSelected} />
|
||||||
</div>
|
</div>
|
||||||
|
<div class="check pointer-events-none">
|
||||||
|
{#if isSelected(undefined, selectedValues)}
|
||||||
|
<Icon icon={IconCheck} size={'small'} />
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
</button>
|
</button>
|
||||||
{#each getStatuses() as group}
|
{#each getStatuses() as group}
|
||||||
{@const status = milestoneStatusAssets[group]}
|
{@const status = milestoneStatusAssets[group]}
|
||||||
{@const items = getStatusItem(group, values)}
|
{@const items = getStatusItem(group, values)}
|
||||||
{#if items.length > 0}
|
{#if items.length > 0}
|
||||||
<div class="flex-row-center p-1">
|
<div class="menu-separator" />
|
||||||
<Icon icon={status.icon} size={'small'} />
|
<div class="menu-group__header">
|
||||||
<div class="ml-2">
|
<div class="flex-row-center gap-2">
|
||||||
<Label label={status.label} />
|
<Icon icon={status.icon} size={'small'} />
|
||||||
|
<span class="overflow-label"><Label label={status.label} /></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{#each sortFilterValues(items, (v) => isSelected(v._id, selectedValues)) as doc}
|
{#each sortFilterValues(items, (v) => isSelected(v._id, selectedValues)) as doc}
|
||||||
<button
|
<button
|
||||||
class="menu-item"
|
class="menu-item no-focus flex-row-center"
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
handleFilterToggle(doc._id)
|
handleFilterToggle(doc._id)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div class="flex clear-mins">
|
<div class="flex-grow clear-mins">
|
||||||
<div class="check pointer-events-none">
|
|
||||||
<CheckBox checked={isSelected(doc._id, selectedValues)} primary />
|
|
||||||
</div>
|
|
||||||
<MilestoneTitlePresenter value={doc} />
|
<MilestoneTitlePresenter value={doc} />
|
||||||
</div>
|
</div>
|
||||||
|
<div class="check pointer-events-none">
|
||||||
|
{#if isSelected(doc._id, selectedValues)}
|
||||||
|
<Icon icon={IconCheck} size={'small'} />
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
</button>
|
</button>
|
||||||
{/each}
|
{/each}
|
||||||
{/if}
|
{/if}
|
||||||
@ -177,4 +183,5 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="menu-space" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -265,6 +265,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}>
|
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}>
|
||||||
|
<div class="menu-space" />
|
||||||
<Scroller>
|
<Scroller>
|
||||||
{#if nestedFrom}
|
{#if nestedFrom}
|
||||||
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
|
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
|
||||||
@ -320,15 +321,9 @@
|
|||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
{#if nextDiffCat(types, i)}
|
{#if nextDiffCat(types, i)}
|
||||||
<div class="divider" />
|
<div class="menu-separator" />
|
||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
</Scroller>
|
</Scroller>
|
||||||
|
<div class="menu-space" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
.divider {
|
|
||||||
height: 1px;
|
|
||||||
background-color: var(--theme-popup-divider);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
@ -20,13 +20,15 @@
|
|||||||
addNotification,
|
addNotification,
|
||||||
Icon,
|
Icon,
|
||||||
IconCheck,
|
IconCheck,
|
||||||
|
IconSearch,
|
||||||
deviceOptionsStore,
|
deviceOptionsStore,
|
||||||
Label,
|
Label,
|
||||||
Loading,
|
Loading,
|
||||||
resizeObserver
|
resizeObserver,
|
||||||
|
EditWithIcon
|
||||||
} from '@hcengineering/ui'
|
} from '@hcengineering/ui'
|
||||||
import { Filter } from '@hcengineering/view'
|
import { Filter } from '@hcengineering/view'
|
||||||
import { createEventDispatcher, onMount } from 'svelte'
|
import { createEventDispatcher } from 'svelte'
|
||||||
import view from '../../plugin'
|
import view from '../../plugin'
|
||||||
import { FILTER_DEBOUNCE_MS, sortFilterValues } from '../../filter'
|
import { FILTER_DEBOUNCE_MS, sortFilterValues } from '../../filter'
|
||||||
import { buildConfigLookup, getPresenter } from '../../utils'
|
import { buildConfigLookup, getPresenter } from '../../utils'
|
||||||
@ -152,15 +154,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
let search: string = ''
|
let search: string = ''
|
||||||
let phTraslate: string = ''
|
|
||||||
let searchInput: HTMLInputElement
|
|
||||||
$: translate(presentation.string.Search, {}).then((res) => {
|
|
||||||
phTraslate = res
|
|
||||||
})
|
|
||||||
|
|
||||||
onMount(() => {
|
|
||||||
if (searchInput && !$deviceOptionsStore.isMobile) searchInput.focus()
|
|
||||||
})
|
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
$: if (targetClass) getValues(search)
|
$: if (targetClass) getValues(search)
|
||||||
@ -169,16 +162,20 @@
|
|||||||
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}>
|
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}>
|
||||||
{#if clazz.sortingKey}
|
{#if clazz.sortingKey}
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<input
|
<EditWithIcon
|
||||||
bind:this={searchInput}
|
icon={IconSearch}
|
||||||
type="text"
|
size={'large'}
|
||||||
|
width={'100%'}
|
||||||
|
focus={!$deviceOptionsStore.isMobile}
|
||||||
bind:value={search}
|
bind:value={search}
|
||||||
|
placeholder={presentation.string.Search}
|
||||||
on:change={() => {
|
on:change={() => {
|
||||||
getValues(search)
|
getValues(search)
|
||||||
}}
|
}}
|
||||||
placeholder={phTraslate}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
{:else}
|
||||||
|
<div class="menu-space" />
|
||||||
{/if}
|
{/if}
|
||||||
<div class="scroll">
|
<div class="scroll">
|
||||||
<div class="box">
|
<div class="box">
|
||||||
@ -188,7 +185,7 @@
|
|||||||
{:else}
|
{:else}
|
||||||
{#each sortFilterValues(values, (v) => isSelected(v, filter.value)) as value}
|
{#each sortFilterValues(values, (v) => isSelected(v, filter.value)) as value}
|
||||||
<button
|
<button
|
||||||
class="menu-item no-focus"
|
class="menu-item no-focus content-pointer-events-none"
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
handleFilterToggle(value)
|
handleFilterToggle(value)
|
||||||
}}
|
}}
|
||||||
@ -215,4 +212,5 @@
|
|||||||
{/await}
|
{/await}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="menu-space" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -13,10 +13,9 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { translate } from '@hcengineering/platform'
|
import { Button, resizeObserver, deviceOptionsStore, EditWithIcon, IconSearch } from '@hcengineering/ui'
|
||||||
import { Button, resizeObserver, deviceOptionsStore } from '@hcengineering/ui'
|
|
||||||
import { Filter } from '@hcengineering/view'
|
import { Filter } from '@hcengineering/view'
|
||||||
import { onMount, createEventDispatcher } from 'svelte'
|
import { createEventDispatcher } from 'svelte'
|
||||||
import view from '../../plugin'
|
import view from '../../plugin'
|
||||||
|
|
||||||
export let filter: Filter
|
export let filter: Filter
|
||||||
@ -24,9 +23,7 @@
|
|||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
let searchInput: HTMLInputElement
|
|
||||||
let search = filter.value[0] ?? ''
|
let search = filter.value[0] ?? ''
|
||||||
let phTraslate = ''
|
|
||||||
|
|
||||||
filter.modes = [view.filter.FilterContains]
|
filter.modes = [view.filter.FilterContains]
|
||||||
filter.mode ??= filter.modes[0]
|
filter.mode ??= filter.modes[0]
|
||||||
@ -49,19 +46,19 @@
|
|||||||
onChange(filter)
|
onChange(filter)
|
||||||
dispatch('close')
|
dispatch('close')
|
||||||
}
|
}
|
||||||
|
|
||||||
$: translate(filter.key.label, {}).then((res) => {
|
|
||||||
phTraslate = res
|
|
||||||
})
|
|
||||||
|
|
||||||
onMount(() => {
|
|
||||||
if (searchInput && !$deviceOptionsStore.isMobile) searchInput.focus()
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')} on:keydown={onKeyDown}>
|
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')} on:keydown={onKeyDown}>
|
||||||
<div class="header">
|
<div class="header no-border">
|
||||||
<input bind:this={searchInput} bind:value={search} type="text" placeholder={phTraslate} />
|
<EditWithIcon
|
||||||
|
icon={IconSearch}
|
||||||
|
size={'large'}
|
||||||
|
width={'100%'}
|
||||||
|
focus={!$deviceOptionsStore.isMobile}
|
||||||
|
bind:value={search}
|
||||||
|
placeholder={filter.key.label}
|
||||||
|
on:change
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Button shape="filter" label={view.string.Apply} on:click={save} />
|
<Button shape="filter" label={view.string.Apply} on:click={save} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -14,11 +14,19 @@
|
|||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import core, { Class, Doc, FindResult, getObjectValue, Ref, SortingOrder, Space } from '@hcengineering/core'
|
import core, { Class, Doc, FindResult, getObjectValue, Ref, SortingOrder, Space } from '@hcengineering/core'
|
||||||
import { translate } from '@hcengineering/platform'
|
|
||||||
import presentation, { getClient } from '@hcengineering/presentation'
|
import presentation, { getClient } from '@hcengineering/presentation'
|
||||||
import ui, { Icon, IconCheck, Label, Loading, resizeObserver, deviceOptionsStore } from '@hcengineering/ui'
|
import ui, {
|
||||||
|
EditWithIcon,
|
||||||
|
Icon,
|
||||||
|
IconSearch,
|
||||||
|
IconCheck,
|
||||||
|
Label,
|
||||||
|
Loading,
|
||||||
|
resizeObserver,
|
||||||
|
deviceOptionsStore
|
||||||
|
} from '@hcengineering/ui'
|
||||||
import { Filter } from '@hcengineering/view'
|
import { Filter } from '@hcengineering/view'
|
||||||
import { onMount, createEventDispatcher } from 'svelte'
|
import { createEventDispatcher } from 'svelte'
|
||||||
import { getPresenter } from '../../utils'
|
import { getPresenter } from '../../utils'
|
||||||
import { FILTER_DEBOUNCE_MS, sortFilterValues } from '../../filter'
|
import { FILTER_DEBOUNCE_MS, sortFilterValues } from '../../filter'
|
||||||
import view from '../../plugin'
|
import view from '../../plugin'
|
||||||
@ -127,34 +135,29 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
let search: string = ''
|
let search: string = ''
|
||||||
let phTraslate: string = ''
|
|
||||||
let searchInput: HTMLInputElement
|
|
||||||
$: translate(presentation.string.Search, {}).then((res) => {
|
|
||||||
phTraslate = res
|
|
||||||
})
|
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
onMount(() => {
|
|
||||||
if (searchInput && !$deviceOptionsStore.isMobile) searchInput.focus()
|
|
||||||
})
|
|
||||||
|
|
||||||
getValues(search)
|
getValues(search)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}>
|
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}>
|
||||||
{#if isSearchable}
|
{#if isSearchable}
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<input
|
<EditWithIcon
|
||||||
bind:this={searchInput}
|
icon={IconSearch}
|
||||||
type="text"
|
size={'large'}
|
||||||
|
width={'100%'}
|
||||||
|
focus={!$deviceOptionsStore.isMobile}
|
||||||
bind:value={search}
|
bind:value={search}
|
||||||
|
placeholder={presentation.string.Search}
|
||||||
on:change={() => {
|
on:change={() => {
|
||||||
getValues(search)
|
getValues(search)
|
||||||
}}
|
}}
|
||||||
placeholder={phTraslate}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
{:else}
|
||||||
|
<div class="menu-space" />
|
||||||
{/if}
|
{/if}
|
||||||
<div class="scroll">
|
<div class="scroll">
|
||||||
<div class="box">
|
<div class="box">
|
||||||
@ -165,29 +168,27 @@
|
|||||||
{#each sortFilterValues([...values.keys()], (v) => isSelected(v, selectedValues)) as value}
|
{#each sortFilterValues([...values.keys()], (v) => isSelected(v, selectedValues)) as value}
|
||||||
{@const realValue = [...(realValues.get(value) ?? [])][0]}
|
{@const realValue = [...(realValues.get(value) ?? [])][0]}
|
||||||
<button
|
<button
|
||||||
class="menu-item no-focus"
|
class="menu-item no-focus content-pointer-events-none"
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
handleFilterToggle(value)
|
handleFilterToggle(value)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div class="flex-between w-full">
|
{#if value !== undefined}
|
||||||
<div class="flex-row-center">
|
<div class="clear-mins flex-grow">
|
||||||
{#if value !== undefined}
|
<svelte:component
|
||||||
<svelte:component
|
this={attribute.presenter}
|
||||||
this={attribute.presenter}
|
value={typeof value === 'string' ? realValue : value}
|
||||||
value={typeof value === 'string' ? realValue : value}
|
{...attribute.props}
|
||||||
{...attribute.props}
|
oneLine
|
||||||
oneLine
|
/>
|
||||||
/>
|
|
||||||
{:else}
|
|
||||||
<Label label={ui.string.NotSelected} />
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
<div class="pointer-events-none">
|
|
||||||
{#if isSelected(value, selectedValues)}
|
|
||||||
<Icon icon={IconCheck} size={'small'} />
|
|
||||||
{/if}
|
|
||||||
</div>
|
</div>
|
||||||
|
{:else}
|
||||||
|
<span class="overflow-label flex-grow"><Label label={ui.string.NotSelected} /></span>
|
||||||
|
{/if}
|
||||||
|
<div class="check pointer-events-none">
|
||||||
|
{#if isSelected(value, selectedValues)}
|
||||||
|
<Icon icon={IconCheck} size={'small'} />
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
{/each}
|
{/each}
|
||||||
@ -195,4 +196,5 @@
|
|||||||
{/await}
|
{/await}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="menu-space" />
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user