[TSK-1333] Separate filter for TypeString (#3171)

Signed-off-by: Sergei Ogorelkov <sergei.ogorelkov@icloud.com>
This commit is contained in:
Sergei Ogorelkov 2023-05-12 09:43:58 +04:00 committed by GitHub
parent bd3c683cde
commit 0473d9eaf9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 104 additions and 8 deletions

View File

@ -671,7 +671,7 @@ export function createModel (builder: Builder): void {
})
builder.mixin(core.class.TypeString, core.class.Class, view.mixin.AttributeFilter, {
component: view.component.ValueFilter
component: view.component.StringFilter
})
builder.mixin(core.class.TypeHyperlink, core.class.Class, view.mixin.AttributeFilter, {
@ -762,6 +762,16 @@ export function createModel (builder: Builder): void {
view.filter.FilterAfter
)
builder.createDoc(
view.class.FilterMode,
core.space.Model,
{
label: view.string.Contains,
result: view.function.FilterContainsResult
},
view.filter.FilterContains
)
builder.createDoc(
view.class.FilterMode,
core.space.Model,

View File

@ -103,6 +103,7 @@ export default mergeIds(viewId, view, {
FilterValueNinResult: '' as FilterFunction,
FilterBeforeResult: '' as FilterFunction,
FilterAfterResult: '' as FilterFunction,
FilterContainsResult: '' as FilterFunction,
FilterNestedMatchResult: '' as FilterFunction,
FilterNestedDontMatchResult: '' as FilterFunction,
FilterDateOutdated: '' as FilterFunction,

View File

@ -1,5 +1,6 @@
{
"string": {
"Contains": "contains",
"MoveClass": "Move {class}",
"SelectToMove": "Select the {classLabel} you want to move {class} to.",
"Delete": "Delete",

View File

@ -1,5 +1,6 @@
{
"string": {
"Contains": "содержит",
"MoveClass": "Переместить {class}",
"SelectToMove": "Выберите {classLabel}, в который вы хотите переместить {class}.",
"Delete": "Удалить",

View File

@ -0,0 +1,67 @@
<!--
// Copyright © 2023 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.
-->
<script lang="ts">
import { translate } from '@hcengineering/platform'
import { Button, resizeObserver, deviceOptionsStore } from '@hcengineering/ui'
import { Filter } from '@hcengineering/view'
import { onMount, createEventDispatcher } from 'svelte'
import view from '../../plugin'
export let filter: Filter
export let onChange: (e: Filter) => void
const dispatch = createEventDispatcher()
let searchInput: HTMLInputElement
let search = filter.value[0] ?? ''
let phTraslate = ''
filter.modes = [view.filter.FilterContains]
filter.mode ??= filter.modes[0]
export function onKeyDown (event: KeyboardEvent): boolean {
if (event.key === 'Enter') {
event.preventDefault()
event.stopPropagation()
save()
return true
}
return false
}
function save () {
filter.value = search ? [search] : []
onChange(filter)
dispatch('close')
}
$: translate(filter.key.label, {}).then((res) => {
phTraslate = res
})
onMount(() => {
if (searchInput && !$deviceOptionsStore.isMobile) searchInput.focus()
})
</script>
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')} on:keydown={onKeyDown}>
<div class="header">
<input bind:this={searchInput} bind:value={search} type="text" placeholder={phTraslate} />
</div>
<Button shape="filter" label={view.string.Apply} on:click={save} />
</div>

View File

@ -57,6 +57,7 @@
<div class="scroll">
<div class="box">
{#each values as value, i}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div
class="menu-item"
on:click={() => {

View File

@ -18,10 +18,9 @@
import presentation, { getClient } from '@hcengineering/presentation'
import ui, { Icon, IconCheck, Label, Loading, resizeObserver, deviceOptionsStore } from '@hcengineering/ui'
import { Filter } from '@hcengineering/view'
import { onMount } from 'svelte'
import { onMount, createEventDispatcher } from 'svelte'
import { getPresenter } from '../../utils'
import view from '../../plugin'
import { createEventDispatcher } from 'svelte'
export let _class: Ref<Class<Doc>>
export let space: Ref<Space> | undefined = undefined
@ -31,11 +30,7 @@
filter.modes = [view.filter.FilterValueIn, view.filter.FilterValueNin]
filter.mode = filter.mode === undefined ? filter.modes[0] : filter.mode
// TODO: remove "TypeString" from search types after
// a separate filter for strings is implemented
$: isSearchable = [core.class.TypeNumber, core.class.TypeString, core.class.EnumOf].includes(
filter.key.attribute.type._class
)
$: isSearchable = [core.class.TypeNumber, core.class.EnumOf].includes(filter.key.attribute.type._class)
const client = getClient()
const key = { key: filter.key.key }

View File

@ -62,6 +62,7 @@
<div class="mb-1"><a class="fs-title" {href}>{data.title}</a></div>
<div class="mb-1"><a href={data.authorUrl}>{data.author}</a></div>
{#if !played}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div
class="container"
on:click={() => {

View File

@ -70,6 +70,12 @@ export async function afterResult (filter: Filter): Promise<ObjQueryType<any>> {
return { $gt: filter.value[0] }
}
export async function containsResult (filter: Filter): Promise<ObjQueryType<any>> {
const [value] = filter.value
return typeof value === 'string' ? { $like: `%${value}%` } : {}
}
export async function nestedMatchResult (filter: Filter, onUpdate: () => void): Promise<ObjQueryType<any>> {
if (filter.nested === undefined) return {}
const result = await getRefs(filter.nested, onUpdate)
@ -256,6 +262,12 @@ function getFilterModes (component: AnyComponent): FilterModes | undefined {
mode: view.filter.FilterBefore
}
}
if (component === view.component.StringFilter) {
return {
modes: [view.filter.FilterContains],
mode: view.filter.FilterContains
}
}
}
export function createFilter (_class: Ref<Class<Doc>>, key: string, value: any[]): Filter | undefined {

View File

@ -39,6 +39,7 @@ import ObjectFilter from './components/filter/ObjectFilter.svelte'
import TimestampFilter from './components/filter/TimestampFilter.svelte'
import DateFilter from './components/filter/DateFilter.svelte'
import ValueFilter from './components/filter/ValueFilter.svelte'
import StringFilter from './components/filter/StringFilter.svelte'
import HTMLEditor from './components/HTMLEditor.svelte'
import HTMLPresenter from './components/HTMLPresenter.svelte'
import HyperlinkPresenter from './components/HyperlinkPresenter.svelte'
@ -77,6 +78,7 @@ import ViewletSettingButton from './components/ViewletSettingButton.svelte'
import {
afterResult,
beforeResult,
containsResult,
dateCustom,
dateMonth,
dateNextMonth,
@ -178,6 +180,7 @@ export default async (): Promise<Resources> => ({
ObjectFilter,
DateFilter,
ValueFilter,
StringFilter,
TimestampFilter,
TableBrowser,
SpacePresenter,
@ -229,6 +232,7 @@ export default async (): Promise<Resources> => ({
FilterValueNinResult: valueNinResult,
FilterBeforeResult: beforeResult,
FilterAfterResult: afterResult,
FilterContainsResult: containsResult,
FilterNestedMatchResult: nestedMatchResult,
FilterNestedDontMatchResult: nestedDontMatchResult,
ShowEmptyGroups: showEmptyGroups,

View File

@ -23,12 +23,14 @@ export default mergeIds(viewId, view, {
ObjectFilter: '' as AnyComponent,
DateFilter: '' as AnyComponent,
ValueFilter: '' as AnyComponent,
StringFilter: '' as AnyComponent,
TimestampFilter: '' as AnyComponent,
FilterTypePopup: '' as AnyComponent,
ActionsPopup: '' as AnyComponent,
ProxyPresenter: '' as AnyComponent
},
string: {
Contains: '' as IntlString,
LabelYes: '' as IntlString,
LabelNo: '' as IntlString,
ChooseAColor: '' as IntlString,

View File

@ -742,6 +742,7 @@ const view = plugin(viewId, {
FilterValueNin: '' as Ref<FilterMode>,
FilterBefore: '' as Ref<FilterMode>,
FilterAfter: '' as Ref<FilterMode>,
FilterContains: '' as Ref<FilterMode>,
FilterNestedMatch: '' as Ref<FilterMode>,
FilterNestedDontMatch: '' as Ref<FilterMode>,
FilterDateOutdated: '' as Ref<FilterMode>,