diff --git a/models/test-management/src/index.ts b/models/test-management/src/index.ts
index 811a4a3c52..ea33cd4020 100644
--- a/models/test-management/src/index.ts
+++ b/models/test-management/src/index.ts
@@ -115,6 +115,7 @@ function defineApplication (builder: Builder): void {
navigationComponentIcon: testManagement.icon.TestRuns,
mainComponentLabel: testManagement.string.TestResults,
mainComponentIcon: testManagement.icon.TestResult,
+ mainHeaderComponent: testManagement.component.TestRunHeader,
navigationComponentProps: {
_class: testManagement.class.TestRun,
icon: testManagement.icon.TestRuns,
diff --git a/models/test-management/src/plugin.ts b/models/test-management/src/plugin.ts
index fcfbf07a0c..0d9bc59c18 100644
--- a/models/test-management/src/plugin.ts
+++ b/models/test-management/src/plugin.ts
@@ -41,6 +41,7 @@ export default mergeIds(testManagementId, testManganement, {
RunButton: '' as AnyComponent,
TestResultPresenter: '' as AnyComponent,
EditTestResult: '' as AnyComponent,
- TestResultFooter: '' as AnyComponent
+ TestResultFooter: '' as AnyComponent,
+ TestRunHeader: '' as AnyComponent
}
})
diff --git a/plugins/test-management-assets/assets/icons.svg b/plugins/test-management-assets/assets/icons.svg
index 7a4cde62a4..98e4b0fc78 100644
--- a/plugins/test-management-assets/assets/icons.svg
+++ b/plugins/test-management-assets/assets/icons.svg
@@ -64,4 +64,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/plugins/test-management-assets/lang/cs.json b/plugins/test-management-assets/lang/cs.json
index 154069f81f..7875b88197 100644
--- a/plugins/test-management-assets/lang/cs.json
+++ b/plugins/test-management-assets/lang/cs.json
@@ -79,6 +79,9 @@
"TestCaseDescription": "Popis testovacího případu",
"TestResultAttributes": "Výsledek",
"GoToNextTest": "Další",
- "GoToNextTestTooltip": "Přejít na další test"
+ "GoToNextTestTooltip": "Přejít na další test",
+ "AllTests": "Všechny testy",
+ "MyTests": "Moje testy",
+ "Comments": "Komentáře"
}
}
diff --git a/plugins/test-management-assets/lang/en.json b/plugins/test-management-assets/lang/en.json
index d318793798..71b15fd6e5 100644
--- a/plugins/test-management-assets/lang/en.json
+++ b/plugins/test-management-assets/lang/en.json
@@ -79,6 +79,9 @@
"TestCaseDescription": "Test case description",
"TestResultAttributes": "Result",
"GoToNextTest": "Next",
- "GoToNextTestTooltip": "Go to next test"
+ "GoToNextTestTooltip": "Go to next test",
+ "AllTests": "All tests",
+ "MyTests": "My tests",
+ "Comments": "Comments"
}
}
diff --git a/plugins/test-management-assets/lang/es.json b/plugins/test-management-assets/lang/es.json
index 8a0a249378..7bc3f6bda6 100644
--- a/plugins/test-management-assets/lang/es.json
+++ b/plugins/test-management-assets/lang/es.json
@@ -79,6 +79,9 @@
"TestCaseDescription": "Descripción del caso de prueba",
"TestResultAttributes": "Resultado",
"GoToNextTest": "Siguiente",
- "GoToNextTestTooltip": "Ir al siguiente test"
+ "GoToNextTestTooltip": "Ir al siguiente test",
+ "AllTests": "Todas las pruebas",
+ "MyTests": "Mis pruebas",
+ "Comments": "Comentarios"
}
}
diff --git a/plugins/test-management-assets/lang/fr.json b/plugins/test-management-assets/lang/fr.json
index 8ab2c8135f..2062c84863 100644
--- a/plugins/test-management-assets/lang/fr.json
+++ b/plugins/test-management-assets/lang/fr.json
@@ -79,6 +79,9 @@
"TestCaseDescription": "Description du cas de test",
"TestResultAttributes": "Résultat",
"GoToNextTest": "Suivant",
- "GoToNextTestTooltip": "Aller au test suivant"
+ "GoToNextTestTooltip": "Aller au test suivant",
+ "AllTests": "Tous les tests",
+ "MyTests": "Mes tests",
+ "Comments": "Commentaires"
}
}
diff --git a/plugins/test-management-assets/lang/it.json b/plugins/test-management-assets/lang/it.json
index 195bfb66f9..73d6a76f5e 100644
--- a/plugins/test-management-assets/lang/it.json
+++ b/plugins/test-management-assets/lang/it.json
@@ -79,6 +79,9 @@
"TestCaseDescription": "Descrizione del caso di test",
"TestResultAttributes": "Risultato",
"GoToNextTest": "Successivo",
- "GoToNextTestTooltip": "Vai al test successivo"
+ "GoToNextTestTooltip": "Vai al test successivo",
+ "AllTests": "Tutte le test",
+ "MyTests": "Le mie test",
+ "Comments": "Commenti"
}
}
diff --git a/plugins/test-management-assets/lang/pt.json b/plugins/test-management-assets/lang/pt.json
index a470584a46..440218488b 100644
--- a/plugins/test-management-assets/lang/pt.json
+++ b/plugins/test-management-assets/lang/pt.json
@@ -79,6 +79,9 @@
"TestCaseDescription": "Descrição do caso de teste",
"TestResultAttributes": "Resultado",
"GoToNextTest": "Próximo",
- "GoToNextTestTooltip": "Ir para o próximo teste"
+ "GoToNextTestTooltip": "Ir para o próximo teste",
+ "AllTests": "Todos os testes",
+ "MyTests": "Meus testes",
+ "Comments": "Comentários"
}
}
diff --git a/plugins/test-management-assets/lang/ru.json b/plugins/test-management-assets/lang/ru.json
index aace7962d2..2e461d37d6 100644
--- a/plugins/test-management-assets/lang/ru.json
+++ b/plugins/test-management-assets/lang/ru.json
@@ -79,6 +79,9 @@
"TestCaseDescription": "Описание тест-кейса",
"TestResultAttributes": "Результат",
"GoToNextTest": "Следующий",
- "GoToNextTestTooltip": "Перейти к следующему тесту"
+ "GoToNextTestTooltip": "Перейти к следующему тесту",
+ "AllTests": "Все тесты",
+ "MyTests": "Мои тесты",
+ "Comments": "Комментарии"
}
}
diff --git a/plugins/test-management-assets/lang/zh.json b/plugins/test-management-assets/lang/zh.json
index 5eb4833e29..0dacf7a4cf 100644
--- a/plugins/test-management-assets/lang/zh.json
+++ b/plugins/test-management-assets/lang/zh.json
@@ -79,6 +79,9 @@
"TestCaseDescription": "測試用例描述",
"TestResultAttributes": "結果",
"GoToNextTest": "下一個",
- "GoToNextTestTooltip": "轉到下一個測試"
+ "GoToNextTestTooltip": "轉到下一個測試",
+ "AllTests": "所有測試",
+ "MyTests": "我的測試",
+ "Comments": "評論"
}
}
diff --git a/plugins/test-management-assets/src/index.ts b/plugins/test-management-assets/src/index.ts
index d88f48d5e0..707e40f610 100644
--- a/plugins/test-management-assets/src/index.ts
+++ b/plugins/test-management-assets/src/index.ts
@@ -38,9 +38,9 @@ loadMetadata(testManagement.icon, {
StatusRejected: `${icons}#status-canceled`,
TestLibrary: `${icons}#test-library`,
TestResult: `${icons}#testResult`,
- StatusNonTested: `${icons}#status-draft`,
- StatusBlocked: `${icons}#status-review-comments`,
- StatusPassed: `${icons}#status-approved`,
- StatusFailed: `${icons}#status-canceled`,
+ StatusNonTested: `${icons}#status-untested`,
+ StatusBlocked: `${icons}#status-blocked`,
+ StatusPassed: `${icons}#status-passed`,
+ StatusFailed: `${icons}#status-failed`,
Run: `${icons}#run`
})
diff --git a/plugins/test-management-resources/src/components/test-result/EditTestResult.svelte b/plugins/test-management-resources/src/components/test-result/EditTestResult.svelte
index bd1f2ca52f..58ebd61e7d 100644
--- a/plugins/test-management-resources/src/components/test-result/EditTestResult.svelte
+++ b/plugins/test-management-resources/src/components/test-result/EditTestResult.svelte
@@ -15,16 +15,12 @@
@@ -77,34 +62,15 @@
isAside={true}
isSub={false}
adaptive={'default'}
+ withoutActivity={true}
on:open
on:close={() => dispatch('close')}
>
-
-
-
-
-
+
-
-
-
-
-
-
-
+
{/if}
diff --git a/plugins/test-management-resources/src/components/test-result/NextButton.svelte b/plugins/test-management-resources/src/components/test-result/NextButton.svelte
deleted file mode 100644
index 288527e3a5..0000000000
--- a/plugins/test-management-resources/src/components/test-result/NextButton.svelte
+++ /dev/null
@@ -1,81 +0,0 @@
-
-
-
-{#if isLoading}
-
-{:else}
-
-{/if}
diff --git a/plugins/test-management-resources/src/components/test-result/TestResultAside.svelte b/plugins/test-management-resources/src/components/test-result/TestResultAside.svelte
new file mode 100644
index 0000000000..77c27d9591
--- /dev/null
+++ b/plugins/test-management-resources/src/components/test-result/TestResultAside.svelte
@@ -0,0 +1,76 @@
+
+
+
+{#if object}
+
+
+
+
+
+ {#if !withoutActivity}
+
+
+
+ {/if}
+{/if}
diff --git a/plugins/test-management-resources/src/components/test-result/TestRunner.svelte b/plugins/test-management-resources/src/components/test-result/TestRunner.svelte
new file mode 100644
index 0000000000..e23c4cb2fb
--- /dev/null
+++ b/plugins/test-management-resources/src/components/test-result/TestRunner.svelte
@@ -0,0 +1,82 @@
+
+
+
+
+{#if object !== undefined}
+ dispatch('close')}
+ >
+
+
+
+
+
+
+
+
+
+{/if}
diff --git a/plugins/test-management-resources/src/components/test-result/store/testIteratorStore.ts b/plugins/test-management-resources/src/components/test-result/store/testIteratorStore.ts
index 49de2bdae5..52b620416a 100644
--- a/plugins/test-management-resources/src/components/test-result/store/testIteratorStore.ts
+++ b/plugins/test-management-resources/src/components/test-result/store/testIteratorStore.ts
@@ -17,11 +17,11 @@ import { writable, get } from 'svelte/store'
import {
type IteratorState,
type StoreAdapter,
+ type IteratorParams,
ObjectIteratorProvider,
getDefaultIteratorState
} from '@hcengineering/view-resources'
import testManagement, { type TestResult } from '@hcengineering/test-management'
-import type { DocumentQuery, Ref } from '@hcengineering/core'
export const testIteratorStore = writable>(getDefaultIteratorState({}))
@@ -39,11 +39,8 @@ const adapter: StoreAdapter = {
export const testResultIteratorProvider = new ObjectIteratorProvider(adapter)
-export async function initializeIterator (
- query: DocumentQuery,
- currentObject: Ref | undefined
-): Promise {
- await testResultIteratorProvider.initialize(testManagement.class.TestResult, query, currentObject)
+export async function initializeIterator (options: IteratorParams): Promise {
+ await testResultIteratorProvider.initialize(testManagement.class.TestResult, options)
}
export function resetTestObjectIterator (): void {
diff --git a/plugins/test-management-resources/src/components/test-run/TestResultModeSelector.svelte b/plugins/test-management-resources/src/components/test-run/TestResultModeSelector.svelte
new file mode 100644
index 0000000000..96c86334c8
--- /dev/null
+++ b/plugins/test-management-resources/src/components/test-run/TestResultModeSelector.svelte
@@ -0,0 +1,41 @@
+
+
+
+{#if modeSelectorProps !== undefined}
+
+{/if}
diff --git a/plugins/test-management-resources/src/components/test-run/TestRunButton.svelte b/plugins/test-management-resources/src/components/test-run/TestRunButton.svelte
new file mode 100644
index 0000000000..d2918461f4
--- /dev/null
+++ b/plugins/test-management-resources/src/components/test-run/TestRunButton.svelte
@@ -0,0 +1,45 @@
+
+
+
+
diff --git a/plugins/test-management-resources/src/components/test-run/TestRunHeader.svelte b/plugins/test-management-resources/src/components/test-run/TestRunHeader.svelte
new file mode 100644
index 0000000000..d54f17ddb4
--- /dev/null
+++ b/plugins/test-management-resources/src/components/test-run/TestRunHeader.svelte
@@ -0,0 +1,35 @@
+
+
+
+{#if modes !== undefined}
+
+
+{/if}
diff --git a/plugins/test-management-resources/src/index.ts b/plugins/test-management-resources/src/index.ts
index 7ee0a6ff9b..5ff8975208 100644
--- a/plugins/test-management-resources/src/index.ts
+++ b/plugins/test-management-resources/src/index.ts
@@ -36,6 +36,8 @@ import TestResultPresenter from './components/test-result/TestResultPresenter.sv
import EditTestResult from './components/test-result/EditTestResult.svelte'
import TestResultHeader from './components/test-result/TestResultHeader.svelte'
import TestResultFooter from './components/test-result/TestResultFooter.svelte'
+import TestRunHeader from './components/test-run/TestRunHeader.svelte'
+import TestRunner from './components/test-result/TestRunner.svelte'
import { CreateChildTestSuiteAction, EditTestSuiteAction, RunSelectedTestsAction } from './utils'
import { resolveLocation, getAttachedObjectLink } from './navigation'
@@ -63,7 +65,9 @@ export default async (): Promise => ({
TestResultPresenter,
EditTestResult,
TestResultHeader,
- TestResultFooter
+ TestResultFooter,
+ TestRunHeader,
+ TestRunner
},
function: {
GetTestSuiteLink: getAttachedObjectLink,
diff --git a/plugins/test-management-resources/src/navigation.ts b/plugins/test-management-resources/src/navigation.ts
index 00ba0f82b0..bf164eef67 100644
--- a/plugins/test-management-resources/src/navigation.ts
+++ b/plugins/test-management-resources/src/navigation.ts
@@ -11,15 +11,21 @@
//
// See the License for the specific language governing permissions and
// limitations under the License.
-import testManagement, { testManagementId, type TestSuite, type TestProject } from '@hcengineering/test-management'
-import { type Doc, type Ref } from '@hcengineering/core'
+import testManagement, {
+ testManagementId,
+ type TestSuite,
+ type TestProject,
+ type TestRun
+} from '@hcengineering/test-management'
+import { type Doc, type Ref, getCurrentAccount } from '@hcengineering/core'
import { getClient } from '@hcengineering/presentation'
import {
getCurrentResolvedLocation,
getLocation,
getPanelURI,
type Location,
- type ResolvedLocation
+ type ResolvedLocation,
+ navigate
} from '@hcengineering/ui'
import view, { type ObjectPanel } from '@hcengineering/view'
import { accessDeniedStore } from '@hcengineering/view-resources'
@@ -63,7 +69,7 @@ async function generateProjectLocation (
export function getAttachedObjectLink (parentDoc: Ref): Location {
const loc = getCurrentResolvedLocation()
- loc.query = parentDoc === undefined ? undefined : { attachedTo: parentDoc }
+ loc.query = parentDoc === undefined ? undefined : { ...loc.query, attachedTo: parentDoc }
return loc
}
@@ -79,6 +85,11 @@ export function getTestSuiteIdFromLocation (): Ref {
return (location?.query?.[SUITE_KEY] as Ref) ?? testManagement.ids.NoParent
}
+export function getTestRunIdFromLocation (): Ref {
+ const location = getLocation()
+ return (location?.query?.[SUITE_KEY] as Ref) ?? testManagement.ids.NoTestRun
+}
+
export function getTestRunsLink (space: Ref, parentDoc: Ref): Location {
const loc = getCurrentResolvedLocation()
loc.path.length = 5
@@ -91,6 +102,29 @@ export function getTestRunsLink (space: Ref, parentDoc: Ref):
return loc
}
+export function onModeChanged (newMode: string): void {
+ const loc = getCurrentResolvedLocation()
+ const { assignee, ...baseQuery } = loc.query ?? {}
+ const currentUser = getCurrentAccount()?.person
+ if (currentUser === undefined) {
+ console.error('Current user is not defined')
+ return
+ }
+ switch (newMode) {
+ case testManagement.mode.AllTests:
+ loc.query = baseQuery
+ break
+ case testManagement.mode.MyTests:
+ loc.query = { ...baseQuery, assignee: currentUser }
+ }
+ navigate(loc)
+}
+
+export function getCurrentMode (loc: Location): string {
+ const { assignee } = loc.query ?? {}
+ return assignee === getCurrentAccount()?.person ? testManagement.mode.MyTests : testManagement.mode.AllTests
+}
+
export async function resolveLocation (loc: Location): Promise {
if (loc.path[2] !== testManagementId) {
return undefined
diff --git a/plugins/test-management-resources/src/utils.ts b/plugins/test-management-resources/src/utils.ts
index 6b4b81c2f5..49b1fe8511 100644
--- a/plugins/test-management-resources/src/utils.ts
+++ b/plugins/test-management-resources/src/utils.ts
@@ -13,15 +13,19 @@
// limitations under the License.
//
+import { Analytics } from '@hcengineering/analytics'
import type { Doc, DocumentQuery, Ref } from '@hcengineering/core'
-import { showPopup } from '@hcengineering/ui'
-import { type TestProject, type TestCase, type TestSuite } from '@hcengineering/test-management'
+import { showPopup, showPanel } from '@hcengineering/ui'
+import { type TestProject, type TestCase, type TestSuite, type TestResult } from '@hcengineering/test-management'
+import testManagement from '@hcengineering/test-management'
import CreateTestSuiteComponent from './components/test-suite/CreateTestSuite.svelte'
import EditTestSuiteComponent from './components/test-suite/EditTestSuite.svelte'
import CreateTestCase from './components/test-case/CreateTestCase.svelte'
import CreateProject from './components/project/CreateProject.svelte'
import CreateTestRun from './components/test-run/CreateTestRun.svelte'
+import { getTestRunIdFromLocation } from './navigation'
+import { initializeIterator } from './components/test-result/store/testIteratorStore'
export async function showCreateTestSuitePopup (
space: Ref | undefined,
@@ -50,6 +54,30 @@ export async function showCreateTestRunPopup (options: {
showPopup(CreateTestRun, options, 'top')
}
+export async function showTestRunnerPanel (options: {
+ query?: DocumentQuery
+ space: Ref
+ selectedDocs?: TestResult[]
+}): Promise {
+ try {
+ const { query, space, selectedDocs } = options
+ await initializeIterator({
+ query: { ...query, space },
+ options: {
+ lookup: {
+ testCase: testManagement.class.TestCase
+ }
+ },
+ docs: selectedDocs
+ })
+ const testRunId = getTestRunIdFromLocation()
+ showPanel(testManagement.component.TestRunner, testRunId, testManagement.class.TestRun, 'content')
+ } catch (err: any) {
+ Analytics.handleError(err)
+ console.error('Failed to initialize test runner', err)
+ }
+}
+
export async function CreateChildTestSuiteAction (doc: TestSuite): Promise {
await showCreateTestSuitePopup(doc.space, doc._id)
}
diff --git a/plugins/test-management/src/plugin.ts b/plugins/test-management/src/plugin.ts
index 1ebfde133d..863f5663b9 100644
--- a/plugins/test-management/src/plugin.ts
+++ b/plugins/test-management/src/plugin.ts
@@ -187,7 +187,10 @@ export const testManagementPlugin = plugin(testManagementId, {
TestCaseDescription: '' as IntlString,
TestResultAttributes: '' as IntlString,
GoToNextTest: '' as IntlString,
- GoToNextTestTooltip: '' as IntlString
+ GoToNextTestTooltip: '' as IntlString,
+ AllTests: '' as IntlString,
+ MyTests: '' as IntlString,
+ Comments: '' as IntlString
},
category: {
TestManagement: '' as Ref
@@ -206,11 +209,17 @@ export const testManagementPlugin = plugin(testManagementId, {
TestResultStatusPresenter: '' as AnyComponent,
TestResultStatusEditor: '' as AnyComponent,
TestRunResult: '' as AnyComponent,
- TestResultHeader: '' as AnyComponent
+ TestResultHeader: '' as AnyComponent,
+ TestRunner: '' as AnyComponent
},
ids: {
NoParent: '' as Ref,
- TestCaseUpdatedActivityViewlet: '' as Ref
+ TestCaseUpdatedActivityViewlet: '' as Ref,
+ NoTestRun: '' as Ref
+ },
+ mode: {
+ AllTests: '' as IntlString,
+ MyTests: '' as IntlString
},
spaceType: {
TestCaseType: '' as Ref,
diff --git a/plugins/view-resources/src/__tests__/objectIterator.test.ts b/plugins/view-resources/src/__tests__/objectIterator.test.ts
index 94d62c39a1..5d59223a73 100644
--- a/plugins/view-resources/src/__tests__/objectIterator.test.ts
+++ b/plugins/view-resources/src/__tests__/objectIterator.test.ts
@@ -49,7 +49,7 @@ describe('ObjectIterator', () => {
const _class: Ref> = { id: 'class1' } as any
// eslint-disable-next-line no-new
- new ObjectIterator(_class, query, storeAdapter)
+ new ObjectIterator(_class, storeAdapter, { query })
expect(storeAdapter.set).toHaveBeenCalledWith({
query,
currentObjects: [],
@@ -64,7 +64,7 @@ describe('ObjectIterator', () => {
const query: DocumentQuery = { key: 'value' }
const _class: Ref> = { id: 'class1' } as any
- const iterator = new ObjectIterator(_class, query, storeAdapter)
+ const iterator = new ObjectIterator(_class, storeAdapter, { query })
await iterator.loadObjects(undefined)
expect(findAll).toHaveBeenCalledWith(_class, query, {
@@ -81,7 +81,7 @@ describe('ObjectIterator', () => {
mockObjects = [{ id: '1' }, { id: '2' }, { id: '3' }] as any
const query: DocumentQuery = { key: 'value' }
const _class: Ref> = { id: 'class1' } as any
- const iterator = new ObjectIterator(_class, query, storeAdapter)
+ const iterator = new ObjectIterator(_class, storeAdapter, { query })
await iterator.loadObjects(undefined)
let nextObject = iterator.next()
@@ -102,7 +102,7 @@ describe('ObjectIterator', () => {
mockObjects = [] as any
const query: DocumentQuery = { key: 'value' }
const _class: Ref> = { id: 'class1' } as any
- const iterator = new ObjectIterator(_class, query, storeAdapter)
+ const iterator = new ObjectIterator(_class, storeAdapter, { query })
await iterator.loadObjects(undefined)
const nextObject = iterator.next()
@@ -114,10 +114,10 @@ describe('ObjectIterator', () => {
const _class: Ref> = { id: 'class1' } as any
const provider = new ObjectIteratorProvider(storeAdapter)
- await provider.initialize(_class, query, undefined)
+ await provider.initialize(_class, { query })
const firstIterator = provider.getIterator()
- await provider.initialize(_class, query, undefined)
+ await provider.initialize(_class, { query })
const secondIterator = provider.getIterator()
expect(firstIterator).toBe(secondIterator)
@@ -129,7 +129,7 @@ describe('ObjectIterator', () => {
const _class: Ref> = { id: 'class1' } as any
const provider = new ObjectIteratorProvider(storeAdapter)
- await provider.initialize(_class, query, undefined)
+ await provider.initialize(_class, { query })
provider.reset()
expect(storeAdapter.set).toHaveBeenCalledWith({
diff --git a/plugins/view-resources/src/objectIterator.ts b/plugins/view-resources/src/objectIterator.ts
index 6ede0fbf2d..ebb683c878 100644
--- a/plugins/view-resources/src/objectIterator.ts
+++ b/plugins/view-resources/src/objectIterator.ts
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-import type { DocumentQuery, Doc, Ref, Class } from '@hcengineering/core'
+import type { DocumentQuery, Doc, Ref, Class, FindOptions } from '@hcengineering/core'
import { getClient } from '@hcengineering/presentation'
export interface IteratorState {
@@ -28,10 +28,16 @@ export interface StoreAdapter {
get: () => IteratorState
}
-export function getDefaultIteratorState (query: DocumentQuery): IteratorState {
+export interface IteratorParams {
+ docs?: T[]
+ query?: DocumentQuery
+ options?: FindOptions | undefined
+}
+
+export function getDefaultIteratorState (params: IteratorParams): IteratorState {
return {
- query,
- currentObjects: [],
+ query: params.query ?? {},
+ currentObjects: params.docs ?? [],
iteratorIndex: 0,
limit: 100
}
@@ -41,25 +47,23 @@ export class ObjectIterator {
private readonly storeAdapter: StoreAdapter
private readonly class: Ref>
- constructor (_class: Ref>, query: DocumentQuery, storeAdapter: StoreAdapter) {
+ constructor (_class: Ref>, storeAdapter: StoreAdapter, params: IteratorParams) {
this.class = _class
this.storeAdapter = storeAdapter
- this.storeAdapter.set(getDefaultIteratorState(query))
+ this.storeAdapter.set(getDefaultIteratorState(params))
}
- async loadObjects (currentObject: Ref | undefined): Promise {
+ async loadObjects (options?: FindOptions | undefined): Promise {
const client = getClient()
const { query, limit } = this.storeAdapter.get()
const testResults = await client.findAll(this.class, query, {
+ ...options,
limit,
total: true
})
this.storeAdapter.update((store) => {
store.currentObjects = [...store.currentObjects, ...testResults]
store.limit = testResults.total
- if (currentObject !== undefined) {
- store.iteratorIndex = store.currentObjects.findIndex((obj) => obj._id === currentObject) ?? 0
- }
return store
})
}
@@ -68,8 +72,8 @@ export class ObjectIterator {
let nextObject
this.storeAdapter.update((store) => {
if (store.iteratorIndex < store.currentObjects.length) {
- store.iteratorIndex += 1
nextObject = store.currentObjects[store.iteratorIndex]
+ store.iteratorIndex += 1
}
return store
})
@@ -78,7 +82,7 @@ export class ObjectIterator {
hasNext (): boolean {
const { currentObjects, iteratorIndex } = this.storeAdapter.get()
- return iteratorIndex < currentObjects.length - 1
+ return iteratorIndex < currentObjects.length
}
}
@@ -87,10 +91,12 @@ export class ObjectIteratorProvider {
constructor (private readonly storeAdapter: StoreAdapter) {}
- async initialize (_class: Ref>, query: DocumentQuery, currentObject: Ref | undefined): Promise {
+ async initialize (_class: Ref>, params: IteratorParams): Promise {
if (this.objectIterator === undefined) {
- this.objectIterator = new ObjectIterator(_class, query, this.storeAdapter)
- await this.objectIterator.loadObjects(currentObject)
+ this.objectIterator = new ObjectIterator(_class, this.storeAdapter, params)
+ if (params.docs === undefined || params.docs.length === 0) {
+ await this.objectIterator.loadObjects(params.options)
+ }
}
}
diff --git a/server/postgres/src/storage.ts b/server/postgres/src/storage.ts
index 5d56814511..87f5d87d5d 100644
--- a/server/postgres/src/storage.ts
+++ b/server/postgres/src/storage.ts
@@ -85,6 +85,7 @@ import {
isDataField,
isOwner,
type JoinProps,
+ NumericTypes,
parseDoc,
parseDocWithProjection,
parseUpdate,
@@ -920,7 +921,12 @@ abstract class PostgresAdapterBase implements DbAdapter {
continue
}
if (typeof val === 'number') {
- res.push(`${this.getKey(_class, baseDomain, key, joins)} ${val === 1 ? 'ASC' : 'DESC'}`)
+ const attr = this.hierarchy.findAttribute(_class, key)
+ if (attr !== undefined && NumericTypes.includes(attr.type._class)) {
+ res.push(`(${this.getKey(_class, baseDomain, key, joins)})::numeric ${val === 1 ? 'ASC' : 'DESC'}`)
+ } else {
+ res.push(`${this.getKey(_class, baseDomain, key, joins)} ${val === 1 ? 'ASC' : 'DESC'}`)
+ }
} else {
// todo handle custom sorting
}
diff --git a/server/postgres/src/utils.ts b/server/postgres/src/utils.ts
index 1d1e9cc70f..67fef5ba32 100644
--- a/server/postgres/src/utils.ts
+++ b/server/postgres/src/utils.ts
@@ -64,6 +64,13 @@ export async function retryTxn (
})
}
+export const NumericTypes = [
+ core.class.TypeNumber,
+ core.class.TypeTimestamp,
+ core.class.TypeDate,
+ core.class.Collection
+]
+
export async function createTables (client: postgres.Sql, domains: string[]): Promise {
const filtered = domains.filter((d) => !loadedDomains.has(d))
if (filtered.length === 0) {