UBERF-10691: Fix user selection component to not miss selection

Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
Andrey Sobolev 2025-05-22 00:56:37 +07:00
parent ee97398277
commit 481924d822
No known key found for this signature in database
GPG Key ID: BD80F68D68D8F7F2
14 changed files with 69 additions and 18 deletions

7
.vscode/launch.json vendored
View File

@ -572,15 +572,14 @@
"request": "launch",
"args": ["src/index.ts"],
"env": {
"MONGO_URL": "mongodb://localhost:27017",
"SERVER_SECRET": "secret",
"ACCOUNTS_URL": "http://localhost:3000",
"ACCOUNTS_URL": "http://localhost:3003",
"APP_ID": "${env:POD_GITHUB_APPID}",
"CLIENT_ID": "${env:POD_GITHUB_CLIENTID}",
"CLIENT_SECRET": "${env:POD_GITHUB_CLIENT_SECRET}",
"PRIVATE_KEY": "${env:POD_GITHUB_PRIVATE_KEY}",
"COLLABORATOR_URL": "ws://huly.local:3078",
"MINIO_ENDPOINT": "localhost",
"COLLABORATOR_URL": "ws://huly.local:3079",
"MINIO_ENDPOINT": "localhost:9002",
"MINIO_ACCESS_KEY": "minioadmin",
"MINIO_SECRET_KEY": "minioadmin",
"PLATFORM_OPERATION_LOGGING": "true",

View File

@ -29,6 +29,7 @@
"MakePrivate": "Zneviditelnit",
"MakePrivateDescription": "Viditelné pouze pro členy",
"Created": "Vytvořeno",
"Selected": "Vybráno",
"NoResults": "Žádné výsledky k zobrazení",
"Next": "Další",
"FailedToPreview": "Náhled se nezdařil",
@ -47,4 +48,4 @@
"status": {
"FileTooLarge": "Soubor je příliš velký"
}
}
}

View File

@ -29,6 +29,7 @@
"MakePrivate": "Privat machen",
"MakePrivateDescription": "Nur Mitglieder können es sehen",
"Created": "Erstellt",
"Selected": "Ausgewählt",
"NoResults": "Keine Ergebnisse gefunden",
"Next": "Weiter",
"FailedToPreview": "Vorschau fehlgeschlagen",

View File

@ -29,6 +29,7 @@
"MakePrivate": "Make private",
"MakePrivateDescription": "Only members can see it",
"Created": "Created",
"Selected": "Selected",
"NoResults": "No results to show",
"Next": "Next",
"FailedToPreview": "Failed to preview",

View File

@ -29,6 +29,7 @@
"MakePrivate": "Hacer privado",
"MakePrivateDescription": "Solo los miembros pueden verlo",
"Created": "Creado",
"Selected": "Seleccionado",
"NoResults": "No hay resultados para mostrar",
"Next": "Siguiente",
"FailedToPreview": "Error al previsualizar",
@ -47,4 +48,4 @@
"status": {
"FileTooLarge": "Archivo demasiado grande"
}
}
}

View File

@ -29,6 +29,7 @@
"MakePrivate": "Rendre privé",
"MakePrivateDescription": "Seuls les membres peuvent le voir",
"Created": "Créé",
"Selected": "Sélectionné",
"NoResults": "Aucun résultat à afficher",
"Next": "Suivant",
"FailedToPreview": "Échec de l'aperçu",
@ -47,4 +48,4 @@
"status": {
"FileTooLarge": "Fichier trop volumineux"
}
}
}

View File

@ -29,6 +29,7 @@
"MakePrivate": "Rendi privato",
"MakePrivateDescription": "Solo i membri possono vederlo",
"Created": "Creato",
"Selected": "Selezionato",
"NoResults": "Nessun risultato da mostrare",
"Next": "Successivo",
"FailedToPreview": "Impossibile mostrare l'anteprima",

View File

@ -29,6 +29,7 @@
"MakePrivate": "非公開にする",
"MakePrivateDescription": "メンバーのみ閲覧可能です",
"Created": "作成済み",
"Selected": "選択中",
"NoResults": "表示する結果がありません",
"Next": "次へ",
"FailedToPreview": "プレビューに失敗しました",
@ -48,4 +49,3 @@
"FileTooLarge": "ファイルサイズが大きすぎます"
}
}

View File

@ -29,6 +29,7 @@
"MakePrivate": "Tornar privado",
"MakePrivateDescription": "Apenas os membros podem ver",
"Created": "Criado",
"Selected": "Selecionado",
"NoResults": "Sem resultados para mostrar",
"Next": "Seguinte",
"FailedToPreview": "Falha ao pré-visualizar",

View File

@ -14,7 +14,7 @@
"AddSocialLinks": "Добавить контактную информацию",
"EditSocialLinks": "Редактировать контактную информацию",
"Change": "Изменить",
"Remove": "Удалить",
"Remove": "Удалить",
"Search": "Поиск...",
"Spaces": "Пространства",
"NumberSpaces": "{count, plural, =0 {В} one {В # месте} other {В # местах}}",
@ -24,11 +24,12 @@
"NotInThis": "Не в этом {space}",
"Match": "Совпадение",
"Add": "Добавить",
"Edit": "Редактировать",
"Edit": "Редактировать",
"DocumentPreview": "Предпросмотр",
"MakePrivate": "Сделать личным",
"MakePrivateDescription": "Только пользователи могут видеть это",
"Created": "Созданные",
"Selected": "Выбрано",
"NoResults": "Нет результатов",
"Next": "Далее",
"FailedToPreview": "Ошибка предпросмотра",

View File

@ -29,6 +29,7 @@
"MakePrivate": "设为私有",
"MakePrivateDescription": "只有成员可以查看",
"Created": "已创建",
"Selected": "已选",
"NoResults": "没有可显示结果",
"Next": "下一步",
"FailedToPreview": "预览失败",

View File

@ -71,7 +71,8 @@
$: showCategories =
created.length > 0 ||
objects.map((it) => getObjectValue(groupBy, it)).filter((it, index, arr) => arr.indexOf(it) === index).length > 1
objects.map((it) => getObjectValue(groupBy, it)).filter((it, index, arr) => arr.indexOf(it) === index).length > 1 ||
selectedObjects.length > 0
let presenter: AnySvelteComponent | undefined = undefined
$: if (type === 'presenter') {
@ -160,6 +161,9 @@
if (created.find((it) => it._id === doc._id) !== undefined) {
return '_created'
}
if ((selectedObjects ?? []).find((it) => it === doc._id) !== undefined) {
return '_selected'
}
return getObjectValue(groupBy, toAny(doc))
}

View File

@ -74,10 +74,13 @@
let noSearchField: boolean = false
let search: string = ''
let objects: Doc[] = []
let selObjects: Doc[] = []
let resObjects: Doc[] = []
let extraItems: Ref<Doc>[] = []
const query = createQuery()
const sQuery = createQuery() // Query for selected objects
$: noSearchField = searchMode === 'disabled'
$: _idExtra = typeof docQuery?._id === 'object' ? docQuery?._id : {}
@ -88,6 +91,7 @@
} else {
extraItems = []
}
$: fquery = {
...(docQuery ?? {}),
...(() => {
@ -109,21 +113,46 @@
}
})()
}
$: query.query<Doc>(
_class,
fquery,
(result) => {
result.sort(sort)
if (created.length > 0) {
const cmap = new Set(created.map((it) => it._id))
objects = [...created, ...result.filter((d) => !cmap.has(d._id))].filter(filter)
} else {
objects = result.filter(filter)
}
resObjects = result
},
{ ...(options ?? {}), limit: 200 }
)
$: if (selectedObjects.length > 0) {
sQuery.query<Doc>(
_class,
search !== ''
? { [searchField]: { $like: '%' + search + '%' }, _id: { $in: selectedObjects } }
: { _id: { $in: selectedObjects } },
(result) => {
result.sort(sort)
selObjects = result
},
{}
)
} else {
sQuery.unsubscribe()
}
$: {
if (created.length > 0 || selObjects.length > 0) {
const cmap = new Set(created.map((it) => it._id))
const smap = new Set(selObjects.map((it) => it._id))
objects = [...created, ...selObjects, ...resObjects.filter((d) => !cmap.has(d._id) && !smap.has(d._id))].filter(
filter
)
} else {
objects = resObjects.filter(filter)
}
}
async function searchSpotlight (search: string): Promise<SearchItem[]> {
return (await searchFor('spotlight', search, category, 50)).items
}
@ -150,7 +179,10 @@
{embedded}
{loading}
{type}
on:update
on:update={(e) => {
selectedObjects = e.detail
dispatch('update', e.detail)
}}
on:close
on:changeContent
on:search={(e) => (search = e.detail)}
@ -172,6 +204,12 @@
<Label label={presentation.string.Created} />
</span>
</div>
{:else if selectedObjects.length > 0 && selectedObjects.find((it) => it === item._id) !== undefined}
<div class="menu-group__header">
<span class="overflow-label">
<Label label={presentation.string.Selected} />
</span>
</div>
{:else if $$slots.category}
<slot name="category" {item} />
{/if}

View File

@ -119,6 +119,7 @@ export default plugin(presentationId, {
MakePrivateDescription: '' as IntlString,
OpenInANewTab: '' as IntlString,
Created: '' as IntlString,
Selected: '' as IntlString,
NoResults: '' as IntlString,
Next: '' as IntlString,
FailedToPreview: '' as IntlString,