mirror of
https://github.com/hcengineering/platform.git
synced 2025-06-01 21:31:04 +00:00
UBER-279: Total qfix (#3281)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
parent
c0cb5a87e7
commit
adda89d0c6
@ -416,6 +416,7 @@ export class LiveQuery extends TxProcessor implements Client {
|
||||
|
||||
protected override async txMixin (tx: TxMixin<Doc, Doc>): Promise<TxResult> {
|
||||
const hierarchy = this.client.getHierarchy()
|
||||
|
||||
for (const queries of this.queries) {
|
||||
const isTx = hierarchy.isDerived(queries[0], core.class.Tx)
|
||||
const isMixin = hierarchy.isDerived(tx.mixin, queries[0])
|
||||
@ -433,16 +434,22 @@ export class LiveQuery extends TxProcessor implements Client {
|
||||
// If query contains search we must check use fulltext
|
||||
if (q.query.$search != null && q.query.$search.length > 0) {
|
||||
const searchRefresh = await this.checkSearch(q, tx.objectId)
|
||||
if (searchRefresh) return {}
|
||||
if (searchRefresh) {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
const updatedDoc = q.result[pos]
|
||||
if (updatedDoc.modifiedOn < tx.modifiedOn) {
|
||||
await this.__updateMixinDoc(q, updatedDoc, tx)
|
||||
const updateRefresh = await this.checkUpdatedDocMatch(q, updatedDoc)
|
||||
if (updateRefresh) return {}
|
||||
if (updateRefresh) {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
const currentRefresh = await this.getCurrentDoc(q, updatedDoc._id)
|
||||
if (currentRefresh) return {}
|
||||
if (currentRefresh) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
await this.sort(q, tx)
|
||||
|
@ -15,30 +15,30 @@
|
||||
<script lang="ts">
|
||||
import { CalendarMode } from '@hcengineering/calendar-resources'
|
||||
import calendar from '@hcengineering/calendar-resources/src/plugin'
|
||||
import { EmployeeAccount } from '@hcengineering/contact'
|
||||
import { employeeByIdStore } from '@hcengineering/contact-resources'
|
||||
import { DocumentQuery, getCurrentAccount, Ref } from '@hcengineering/core'
|
||||
import { Department, Staff } from '@hcengineering/hr'
|
||||
import { createQuery, getClient, SpaceSelector } from '@hcengineering/presentation'
|
||||
import {
|
||||
Button,
|
||||
IconBack,
|
||||
IconForward,
|
||||
Label,
|
||||
deviceOptionsStore as deviceInfo,
|
||||
TabList,
|
||||
SearchEdit
|
||||
} from '@hcengineering/ui'
|
||||
import { createQuery, SpaceSelector } from '@hcengineering/presentation'
|
||||
import type { TabItem } from '@hcengineering/ui'
|
||||
import { Button, IconBack, IconForward, Label, SearchEdit, TabList } from '@hcengineering/ui'
|
||||
import view from '@hcengineering/view'
|
||||
import hr from '../plugin'
|
||||
import ScheduleView from './ScheduleView.svelte'
|
||||
import { EmployeeAccount } from '@hcengineering/contact'
|
||||
import { employeeByIdStore } from '@hcengineering/contact-resources'
|
||||
|
||||
const hierarchy = getClient().getHierarchy()
|
||||
const accountEmployee = $employeeByIdStore.get((getCurrentAccount() as EmployeeAccount).employee)
|
||||
const accountStaff = accountEmployee !== undefined ? hierarchy.as(accountEmployee, hr.mixin.Staff) : undefined
|
||||
let accountStaff: Staff | undefined
|
||||
|
||||
const accountStaffQ = createQuery()
|
||||
|
||||
let department = accountStaff !== undefined ? accountStaff.department : hr.ids.Head
|
||||
$: if (accountEmployee !== undefined) {
|
||||
accountStaffQ.query(hr.mixin.Staff, { _id: accountEmployee._id as Ref<Staff> }, (res) => {
|
||||
accountStaff = res[0]
|
||||
department = accountStaff !== undefined ? accountStaff.department : hr.ids.Head
|
||||
})
|
||||
}
|
||||
|
||||
let currentDate: Date = new Date()
|
||||
|
||||
let search = ''
|
||||
@ -89,7 +89,6 @@
|
||||
}).format(date)
|
||||
}
|
||||
|
||||
$: twoRows = $deviceInfo.twoRows
|
||||
const handleSelect = (result: any) => {
|
||||
if (result.type === 'select') {
|
||||
const res = result.detail
|
||||
|
@ -276,42 +276,44 @@
|
||||
}
|
||||
return map
|
||||
}
|
||||
let staffDepartmentMap = new Map()
|
||||
$: getDepartmentsForEmployee(departmentStaff).then((res) => {
|
||||
staffDepartmentMap = res
|
||||
})
|
||||
</script>
|
||||
|
||||
{#if departmentStaff.length}
|
||||
{#await getDepartmentsForEmployee(departmentStaff) then staffDepartmentMap}
|
||||
{#if mode === CalendarMode.Year}
|
||||
<YearView {departmentStaff} {employeeRequests} {types} {currentDate} {holidays} {staffDepartmentMap} />
|
||||
{:else if mode === CalendarMode.Month}
|
||||
{#if display === 'chart'}
|
||||
<MonthView
|
||||
{departmentStaff}
|
||||
{employeeRequests}
|
||||
{types}
|
||||
{startDate}
|
||||
{endDate}
|
||||
{editableList}
|
||||
{currentDate}
|
||||
{timeReports}
|
||||
{holidays}
|
||||
{department}
|
||||
{departments}
|
||||
{staffDepartmentMap}
|
||||
/>
|
||||
{:else if display === 'stats'}
|
||||
<MonthTableView
|
||||
{departmentStaff}
|
||||
{employeeRequests}
|
||||
{types}
|
||||
{currentDate}
|
||||
{timeReports}
|
||||
{holidays}
|
||||
{staffDepartmentMap}
|
||||
{getHolidays}
|
||||
/>
|
||||
{/if}
|
||||
{#if staffDepartmentMap.size > 0}
|
||||
{#if mode === CalendarMode.Year}
|
||||
<YearView {departmentStaff} {employeeRequests} {types} {currentDate} {holidays} {staffDepartmentMap} />
|
||||
{:else if mode === CalendarMode.Month}
|
||||
{#if display === 'chart'}
|
||||
<MonthView
|
||||
{departmentStaff}
|
||||
{employeeRequests}
|
||||
{types}
|
||||
{startDate}
|
||||
{endDate}
|
||||
{editableList}
|
||||
{currentDate}
|
||||
{timeReports}
|
||||
{holidays}
|
||||
{department}
|
||||
{departments}
|
||||
{staffDepartmentMap}
|
||||
/>
|
||||
{:else if display === 'stats'}
|
||||
<MonthTableView
|
||||
{departmentStaff}
|
||||
{employeeRequests}
|
||||
{types}
|
||||
{currentDate}
|
||||
{timeReports}
|
||||
{holidays}
|
||||
{staffDepartmentMap}
|
||||
{getHolidays}
|
||||
/>
|
||||
{/if}
|
||||
{/await}
|
||||
{/if}
|
||||
{:else}
|
||||
<div class="flex-center h-full w-full flex-grow fs-title">
|
||||
<Label label={hr.string.NoEmployeesInDepartment} />
|
||||
|
@ -40,11 +40,16 @@ export async function addMember (client: TxOperations, employee?: Employee, valu
|
||||
undefined,
|
||||
(res?: boolean) => {
|
||||
if (res === true && value !== undefined) {
|
||||
void client.updateMixin(employee._id, employee._class, employee.space, hr.mixin.Staff, {
|
||||
department: value._id
|
||||
})
|
||||
void client
|
||||
.updateMixin(employee._id, employee._class, employee.space, hr.mixin.Staff, {
|
||||
department: value._id
|
||||
})
|
||||
.then(() => {
|
||||
resolve(null)
|
||||
})
|
||||
} else {
|
||||
resolve(null)
|
||||
}
|
||||
resolve(null)
|
||||
}
|
||||
)
|
||||
})
|
||||
|
@ -76,8 +76,8 @@
|
||||
"FilteredViewName": "Filtered view name",
|
||||
"Then": "Then",
|
||||
"ShowPreviewOnClick": "Please click to show document index preview...",
|
||||
"Shown": "Shown",
|
||||
"Total": "Total",
|
||||
"Shown": "showing {len} results {total, plural, =-1 {} other {of filtered # items}}",
|
||||
"Total": "Total: {total, plural, other{#}}",
|
||||
"ShowEmptyGroups": "Show empty groups",
|
||||
"Overdue": "Overdue",
|
||||
"Today": "Today",
|
||||
|
@ -72,8 +72,8 @@
|
||||
"FilteredViewName": "Имя фильтрованного отображения",
|
||||
"Then": "Затем",
|
||||
"ShowPreviewOnClick": "Пожалуйста нажмите чтобы увидеть предпросмотр...",
|
||||
"Shown": "Показано",
|
||||
"Total": "Всего",
|
||||
"Shown": "показано {len} результатов {total, plural, =-1 {} other {из #}}",
|
||||
"Total": "Всего: {total, plural, other{#}}",
|
||||
"ShowEmptyGroups": "Показывать пустые группы",
|
||||
"Overdue": "Overdue",
|
||||
"Today": "Сегодня",
|
||||
|
@ -18,7 +18,8 @@
|
||||
import { getObjectValue, SortingOrder } from '@hcengineering/core'
|
||||
import notification from '@hcengineering/notification'
|
||||
import { createQuery, getClient, updateAttribute } from '@hcengineering/presentation'
|
||||
import {
|
||||
import ui, {
|
||||
Button,
|
||||
CheckBox,
|
||||
Component,
|
||||
getEventPositionElement,
|
||||
@ -49,6 +50,8 @@
|
||||
export let readonly = false
|
||||
export let showFooter = false
|
||||
|
||||
export let totalQuery: DocumentQuery<Doc> | undefined = undefined
|
||||
|
||||
export let prefferedSorting: string = 'modifiedOn'
|
||||
|
||||
export let limit = 200
|
||||
@ -75,7 +78,8 @@
|
||||
let userSorting = false
|
||||
|
||||
let objects: Doc[] = []
|
||||
let total: number
|
||||
let gtotal: number = 0
|
||||
let total: number = 0
|
||||
let objectsRecieved = false
|
||||
const refs: HTMLElement[] = []
|
||||
|
||||
@ -109,6 +113,7 @@
|
||||
(result) => {
|
||||
objects = result
|
||||
total = result.total === -1 ? 0 : result.total
|
||||
|
||||
objectsRecieved = true
|
||||
if (sortingFunction !== undefined) {
|
||||
const sf = sortingFunction
|
||||
@ -215,6 +220,20 @@
|
||||
}
|
||||
|
||||
let width: number
|
||||
|
||||
const totalQueryQ = createQuery()
|
||||
$: totalQueryQ.query(
|
||||
_class,
|
||||
totalQuery ?? query ?? {},
|
||||
(result) => {
|
||||
gtotal = result.total
|
||||
},
|
||||
{
|
||||
lookup,
|
||||
limit: 1,
|
||||
total: true
|
||||
}
|
||||
)
|
||||
</script>
|
||||
|
||||
{#await buildModel({ client, _class, keys: config, lookup })}
|
||||
@ -362,17 +381,26 @@
|
||||
<div class="space" />
|
||||
<div class="footer" style="width: {width}px;">
|
||||
<div class="content" class:padding={showNotification || enableChecking}>
|
||||
<Label label={view.string.Total} />: {total}
|
||||
{#if objects.length > 0 && objects.length < total}
|
||||
<span class="select-text">
|
||||
<Label label={view.string.Total} params={{ total: gtotal }} />
|
||||
</span>
|
||||
{#if objects.length > 0 && objects.length < gtotal}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div
|
||||
class="cursor-pointer ml-2"
|
||||
<span class="select-text ml-2">
|
||||
<Label
|
||||
label={view.string.Shown}
|
||||
params={{ total: objects.length === total ? -1 : total, len: objects.length }}
|
||||
/>
|
||||
</span>
|
||||
|
||||
<Button
|
||||
label={ui.string.ShowMore}
|
||||
kind={'transparent'}
|
||||
size={'small'}
|
||||
on:click={() => {
|
||||
limit = limit + 100
|
||||
}}
|
||||
>
|
||||
<Label label={view.string.Shown} />: {objects.length}
|
||||
</div>
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -26,6 +26,7 @@
|
||||
|
||||
export let _class: Ref<Class<Doc>>
|
||||
export let query: DocumentQuery<Doc>
|
||||
export let totalQuery: DocumentQuery<Doc> | undefined = undefined
|
||||
export let showNotification: boolean = false
|
||||
export let options: FindOptions<Doc> | undefined = undefined
|
||||
export let baseMenuClass: Ref<Class<Doc>> | undefined = undefined
|
||||
@ -91,6 +92,7 @@
|
||||
config={_config}
|
||||
{options}
|
||||
{query}
|
||||
{totalQuery}
|
||||
{showNotification}
|
||||
{baseMenuClass}
|
||||
{loadingProps}
|
||||
|
@ -209,7 +209,8 @@
|
||||
viewOptionsConfig: viewlet.viewOptions?.other,
|
||||
createItemDialog: createComponent,
|
||||
createItemLabel: createLabel,
|
||||
query: resultQuery
|
||||
query: resultQuery,
|
||||
totalQuery: query
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
|
@ -417,7 +417,10 @@ abstract class MongoAdapterBase implements DbAdapter {
|
||||
}
|
||||
})
|
||||
const domain = this.hierarchy.getDomain(clazz)
|
||||
const cursor = this.db.collection(domain).aggregate(pipeline)
|
||||
const cursor = this.db.collection(domain).aggregate(pipeline, {
|
||||
checkKeys: false,
|
||||
enableUtf8Validation: false
|
||||
})
|
||||
cursor.maxTimeMS(30000)
|
||||
const res = (await cursor.toArray())[0]
|
||||
const result = res.results as WithLookup<T>[]
|
||||
|
@ -83,7 +83,7 @@ export function protoDeserialize (data: any, binary: boolean): any {
|
||||
if (!binary) {
|
||||
return JSON.parse(data, receiver)
|
||||
}
|
||||
return packr.unpack(new Uint8Array(data))
|
||||
return packr.unpack(new Uint8Array(replacer('', data)))
|
||||
}
|
||||
|
||||
/**
|
||||
@ -92,6 +92,9 @@ export function protoDeserialize (data: any, binary: boolean): any {
|
||||
* @returns
|
||||
*/
|
||||
export function serialize (object: Request<any> | Response<any>, binary: boolean): any {
|
||||
if ((object as any).result !== undefined) {
|
||||
;(object as any).result = replacer('result', (object as any).result)
|
||||
}
|
||||
return protoSerialize(object, binary)
|
||||
}
|
||||
|
||||
@ -101,7 +104,11 @@ export function serialize (object: Request<any> | Response<any>, binary: boolean
|
||||
* @returns
|
||||
*/
|
||||
export function readResponse<D> (response: any, binary: boolean): Response<D> {
|
||||
return protoDeserialize(response, binary)
|
||||
const data = protoDeserialize(response, binary)
|
||||
if (data.result !== undefined) {
|
||||
data.result = receiver('result', data.result)
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
function replacer (key: string, value: any): any {
|
||||
|
Loading…
Reference in New Issue
Block a user