From 57a925b038940642d371a293a5096d64c640538d Mon Sep 17 00:00:00 2001 From: Andrey Sobolev <haiodo@users.noreply.github.com> Date: Mon, 27 Mar 2023 22:33:23 +0700 Subject: [PATCH] TSK-955: Fix status display (#2840) Signed-off-by: Andrey Sobolev <haiodo@gmail.com> --- packages/kanban/src/utils.ts | 3 ++ packages/presentation/src/utils.ts | 36 +++++++++++++++++-- packages/query/src/index.ts | 22 ++++++++++-- plugins/client-resources/src/connection.ts | 11 ++++-- plugins/contact-resources/src/utils.ts | 4 +-- plugins/task/src/utils.ts | 4 ++- .../src/components/icons/StatusIcon.svelte | 1 + .../issues/IssueStatusActivity.svelte | 4 +-- .../components/issues/IssueStatusIcon.svelte | 2 +- .../src/components/issues/StatusEditor.svelte | 2 +- .../components/issues/StatusPresenter.svelte | 4 +-- .../issues/StatusRefPresenter.svelte | 4 +-- .../components/issues/TitlePresenter.svelte | 18 +++++----- .../issues/edit/SubIssuesSelector.svelte | 6 ++-- .../related/RelatedIssueSelector.svelte | 6 ++-- .../components/sprints/IssueStatistics.svelte | 6 ++-- .../src/components/workflow/Statuses.svelte | 28 ++++++++------- plugins/tracker-resources/src/utils.ts | 19 +++++++--- plugins/tracker/src/utils.ts | 4 ++- plugins/workbench-resources/src/connect.ts | 14 +++++++- tests/sanity/package.json | 4 +-- tests/sanity/tests/tracker.spec.ts | 4 +-- 22 files changed, 145 insertions(+), 61 deletions(-) diff --git a/packages/kanban/src/utils.ts b/packages/kanban/src/utils.ts index ae91f408bb..0961261f6e 100644 --- a/packages/kanban/src/utils.ts +++ b/packages/kanban/src/utils.ts @@ -40,5 +40,8 @@ export const calcRank = (prev?: { rank: string }, next?: { rank: string }): stri const a = prev?.rank !== undefined ? LexoRank.parse(prev.rank) : LexoRank.min() const b = next?.rank !== undefined ? LexoRank.parse(next.rank) : LexoRank.max() + if (a.equals(b)) { + return a.genNext().toString() + } return a.between(b).toString() } diff --git a/packages/presentation/src/utils.ts b/packages/presentation/src/utils.ts index 35381225bf..e7dbec7130 100644 --- a/packages/presentation/src/utils.ts +++ b/packages/presentation/src/utils.ts @@ -104,6 +104,10 @@ export function getClient (): TxOperations { * @public */ export function setClient (_client: Client): void { + if (liveQuery !== undefined) { + void liveQuery.close() + } + const needRefresh = liveQuery !== undefined liveQuery = new LQ(_client) client = new UIClient(_client, liveQuery) _client.notify = (tx: Tx) => { @@ -111,17 +115,23 @@ export function setClient (_client: Client): void { txListeners.forEach((it) => it(tx)) } + if (needRefresh) { + refreshClient() + } } /** * @public */ export function refreshClient (): void { - if (liveQuery !== undefined) { - void liveQuery.refreshConnect() + void liveQuery?.refreshConnect() + for (const q of globalQueries) { + q.refreshClient() } } +const globalQueries: LiveQuery[] = [] + /** * @public */ @@ -137,6 +147,8 @@ export class LiveQuery { onDestroy(() => { this.unsubscribe() }) + } else { + globalQueries.push(this) } } @@ -149,11 +161,21 @@ export class LiveQuery { if (!this.needUpdate(_class, query, callback, options)) { return false } + return this.doQuery<T>(_class, query, callback, options) + } + + private doQuery<T extends Doc>( + _class: Ref<Class<T>>, + query: DocumentQuery<T>, + callback: (result: FindResult<T>) => void, + options: FindOptions<T> | undefined + ): boolean { this.unsubscribe() this.oldCallback = callback this.oldClass = _class this.oldOptions = options this.oldQuery = query + const unsub = liveQuery.query(_class, query, callback, options) this.unsubscribe = () => { unsub() @@ -166,6 +188,16 @@ export class LiveQuery { return true } + refreshClient (): void { + if (this.oldClass !== undefined && this.oldQuery !== undefined && this.oldCallback !== undefined) { + const _class = this.oldClass + const query = this.oldQuery + const callback = this.oldCallback + const options = this.oldOptions + this.doQuery(_class, query, callback, options) + } + } + private needUpdate<T extends Doc>( _class: Ref<Class<T>>, query: DocumentQuery<T>, diff --git a/packages/query/src/index.ts b/packages/query/src/index.ts index 3e927fa418..9afe9c002b 100644 --- a/packages/query/src/index.ts +++ b/packages/query/src/index.ts @@ -64,7 +64,7 @@ interface Query { * @public */ export class LiveQuery extends TxProcessor implements Client { - private readonly client: Client + private client: Client private readonly queries: Map<Ref<Class<Doc>>, Query[]> = new Map<Ref<Class<Doc>>, Query[]>() private readonly queue: Query[] = [] @@ -73,6 +73,11 @@ export class LiveQuery extends TxProcessor implements Client { this.client = client } + async updateClient (client: Client): Promise<void> { + this.client = client + await this.refreshConnect() + } + async close (): Promise<void> { return await this.client.close() } @@ -89,7 +94,20 @@ export class LiveQuery extends TxProcessor implements Client { async refreshConnect (): Promise<void> { for (const q of [...this.queue]) { if (!(await this.removeFromQueue(q))) { - await this.refresh(q) + try { + await this.refresh(q) + } catch (err) { + console.error(err) + } + } + } + for (const v of this.queries.values()) { + for (const q of v) { + try { + await this.refresh(q) + } catch (err) { + console.error(err) + } } } } diff --git a/plugins/client-resources/src/connection.ts b/plugins/client-resources/src/connection.ts index 279ced9efd..ddd11fa0d2 100644 --- a/plugins/client-resources/src/connection.ts +++ b/plugins/client-resources/src/connection.ts @@ -50,7 +50,7 @@ class RequestPromise { resolve!: (value?: any) => void reject!: (reason?: any) => void reconnect?: () => void - constructor () { + constructor (readonly method: string, readonly params: any[]) { this.promise = new Promise((resolve, reject) => { this.resolve = resolve this.reject = reject @@ -64,6 +64,7 @@ class Connection implements ClientConnection { private lastId = 0 private readonly interval: number private readonly sessionId = generateId() as string + private closed = false constructor ( private readonly url: string, @@ -80,6 +81,7 @@ class Connection implements ClientConnection { } async close (): Promise<void> { + this.closed = true clearInterval(this.interval) if (this.websocket !== null) { if (this.websocket instanceof Promise) { @@ -158,7 +160,7 @@ class Connection implements ClientConnection { } this.requests.delete(resp.id) if (resp.error !== undefined) { - console.log('ERROR', resp.id) + console.log('ERROR', promise, resp.id) promise.reject(new PlatformError(resp.error)) } else { promise.resolve(resp.result) @@ -212,8 +214,11 @@ class Connection implements ClientConnection { // If not defined, on reconnect with timeout, will retry automatically. retry?: () => Promise<boolean> }): Promise<any> { + if (this.closed) { + throw new PlatformError(unknownError('connection closed')) + } const id = this.lastId++ - const promise = new RequestPromise() + const promise = new RequestPromise(data.method, data.params) const sendData = async (): Promise<void> => { if (this.websocket instanceof Promise) { diff --git a/plugins/contact-resources/src/utils.ts b/plugins/contact-resources/src/utils.ts index dcc0bae994..5e9dab32e6 100644 --- a/plugins/contact-resources/src/utils.ts +++ b/plugins/contact-resources/src/utils.ts @@ -34,10 +34,8 @@ import { FilterQuery } from '@hcengineering/view-resources' import { get, writable } from 'svelte/store' import contact from './plugin' -const client = getClient() - export async function getChannelProviders (): Promise<Map<Ref<ChannelProvider>, ChannelProvider>> { - const cp = await client.findAll(contact.class.ChannelProvider, {}) + const cp = await getClient().findAll(contact.class.ChannelProvider, {}) const map = new Map<Ref<ChannelProvider>, ChannelProvider>() for (const provider of cp) { map.set(provider._id, provider) diff --git a/plugins/task/src/utils.ts b/plugins/task/src/utils.ts index ae91f408bb..f8b573e900 100644 --- a/plugins/task/src/utils.ts +++ b/plugins/task/src/utils.ts @@ -39,6 +39,8 @@ export const genRanks = (count: number): Generator<string, void, unknown> => export const calcRank = (prev?: { rank: string }, next?: { rank: string }): string => { const a = prev?.rank !== undefined ? LexoRank.parse(prev.rank) : LexoRank.min() const b = next?.rank !== undefined ? LexoRank.parse(next.rank) : LexoRank.max() - + if (a.equals(b)) { + return a.genNext().toString() + } return a.between(b).toString() } diff --git a/plugins/tracker-resources/src/components/icons/StatusIcon.svelte b/plugins/tracker-resources/src/components/icons/StatusIcon.svelte index eec51029c5..7a05b9fdcd 100644 --- a/plugins/tracker-resources/src/components/icons/StatusIcon.svelte +++ b/plugins/tracker-resources/src/components/icons/StatusIcon.svelte @@ -15,6 +15,7 @@ <svg class="svg-{size}" {fill} + id={category._id} style:transform={category._id === tracker.issueStatusCategory.Started ? 'rotate(-90deg)' : ''} viewBox="0 0 14 14" xmlns="http://www.w3.org/2000/svg" diff --git a/plugins/tracker-resources/src/components/issues/IssueStatusActivity.svelte b/plugins/tracker-resources/src/components/issues/IssueStatusActivity.svelte index 02b8d1e67c..c55701ba04 100644 --- a/plugins/tracker-resources/src/components/issues/IssueStatusActivity.svelte +++ b/plugins/tracker-resources/src/components/issues/IssueStatusActivity.svelte @@ -4,7 +4,7 @@ import { Issue, IssueStatus } from '@hcengineering/tracker' import { Label, ticker } from '@hcengineering/ui' import tracker from '../../plugin' - import { statusByIdStore } from '../../utils' + import { statusStore } from '../../utils' import Duration from './Duration.svelte' import StatusPresenter from './StatusPresenter.svelte' @@ -83,7 +83,7 @@ displaySt = result } - $: updateStatus(txes, $statusByIdStore, $ticker) + $: updateStatus(txes, $statusStore.byId, $ticker) </script> <div class="flex-row mt-4 mb-4"> diff --git a/plugins/tracker-resources/src/components/issues/IssueStatusIcon.svelte b/plugins/tracker-resources/src/components/issues/IssueStatusIcon.svelte index 62f858b444..2ce96483e2 100644 --- a/plugins/tracker-resources/src/components/issues/IssueStatusIcon.svelte +++ b/plugins/tracker-resources/src/components/issues/IssueStatusIcon.svelte @@ -40,7 +40,7 @@ $: if (value.category === tracker.issueStatusCategory.Started) { const _s = [ - ...$statusStore.filter( + ...$statusStore.statuses.filter( (it) => it.attachedTo === value.attachedTo && it.category === tracker.issueStatusCategory.Started ) ] diff --git a/plugins/tracker-resources/src/components/issues/StatusEditor.svelte b/plugins/tracker-resources/src/components/issues/StatusEditor.svelte index 2da4231146..18be26864d 100644 --- a/plugins/tracker-resources/src/components/issues/StatusEditor.svelte +++ b/plugins/tracker-resources/src/components/issues/StatusEditor.svelte @@ -65,7 +65,7 @@ ) } - $: statuses = $statusStore.filter((it) => it.attachedTo === value?.space) + $: statuses = $statusStore.statuses.filter((it) => it.attachedTo === value?.space) $: selectedStatus = statuses?.find((status) => status._id === value.status) ?? statuses?.[0] $: selectedStatusLabel = shouldShowLabel ? selectedStatus?.name : undefined diff --git a/plugins/tracker-resources/src/components/issues/StatusPresenter.svelte b/plugins/tracker-resources/src/components/issues/StatusPresenter.svelte index 369ccf9c36..846159bfca 100644 --- a/plugins/tracker-resources/src/components/issues/StatusPresenter.svelte +++ b/plugins/tracker-resources/src/components/issues/StatusPresenter.svelte @@ -14,7 +14,7 @@ --> <script lang="ts"> import { IssueStatus } from '@hcengineering/tracker' - import { statusByIdStore } from '../../utils' + import { statusStore } from '../../utils' import IssueStatusIcon from './IssueStatusIcon.svelte' export let value: IssueStatus | undefined @@ -22,7 +22,7 @@ </script> {#if value} - {@const icon = $statusByIdStore.get(value._id)?.$lookup?.category?.icon} + {@const icon = $statusStore.byId.get(value._id)?.$lookup?.category?.icon} <div class="flex-presenter"> {#if icon} <IssueStatusIcon {value} {size} /> diff --git a/plugins/tracker-resources/src/components/issues/StatusRefPresenter.svelte b/plugins/tracker-resources/src/components/issues/StatusRefPresenter.svelte index a23248560a..2f98d49d8f 100644 --- a/plugins/tracker-resources/src/components/issues/StatusRefPresenter.svelte +++ b/plugins/tracker-resources/src/components/issues/StatusRefPresenter.svelte @@ -15,7 +15,7 @@ <script lang="ts"> import { Ref } from '@hcengineering/core' import { IssueStatus } from '@hcengineering/tracker' - import { statusByIdStore } from '../../utils' + import { statusStore } from '../../utils' import StatusPresenter from './StatusPresenter.svelte' export let value: Ref<IssueStatus> | undefined @@ -23,5 +23,5 @@ </script> {#if value} - <StatusPresenter value={$statusByIdStore.get(value)} {size} /> + <StatusPresenter value={$statusStore.byId.get(value)} {size} /> {/if} diff --git a/plugins/tracker-resources/src/components/issues/TitlePresenter.svelte b/plugins/tracker-resources/src/components/issues/TitlePresenter.svelte index be1a409f5b..5bfaec4fb8 100644 --- a/plugins/tracker-resources/src/components/issues/TitlePresenter.svelte +++ b/plugins/tracker-resources/src/components/issues/TitlePresenter.svelte @@ -26,16 +26,16 @@ </script> {#if value} - <DocNavLink object={value} {onClick} component={tracker.component.EditIssue} inline shrink={1}> - <span - class="name overflow-label select-text" - class:with-margin={shouldUseMargin} - style:max-width={showParent ? `${value.parents.length !== 0 ? 95 : 100}%` : '100%'} - title={value.title} - > + <span + class="name overflow-label select-text" + class:with-margin={shouldUseMargin} + style:max-width={showParent ? `${value.parents.length !== 0 ? 95 : 100}%` : '100%'} + title={value.title} + > + <DocNavLink object={value} {onClick} component={tracker.component.EditIssue} inline shrink={1}> {value.title} - </span> - </DocNavLink> + </DocNavLink> + </span> {#if showParent} <ParentNamesPresenter {value} /> {/if} diff --git a/plugins/tracker-resources/src/components/issues/edit/SubIssuesSelector.svelte b/plugins/tracker-resources/src/components/issues/edit/SubIssuesSelector.svelte index 64f1b651e8..c04d377dee 100644 --- a/plugins/tracker-resources/src/components/issues/edit/SubIssuesSelector.svelte +++ b/plugins/tracker-resources/src/components/issues/edit/SubIssuesSelector.svelte @@ -29,7 +29,7 @@ } from '@hcengineering/ui' import { getIssueId } from '../../../issues' import tracker from '../../../plugin' - import { statusByIdStore, statusStore, subIssueListProvider } from '../../../utils' + import { statusStore, subIssueListProvider } from '../../../utils' export let value: WithLookup<Issue> export let currentProject: Project | undefined = undefined @@ -77,7 +77,7 @@ } $: if (subIssues) { - const doneStatuses = $statusStore + const doneStatuses = $statusStore.statuses .filter((s) => s.category === tracker.issueStatusCategory.Completed) .map((p) => p._id) countComplete = subIssues.filter((si) => doneStatuses.includes(si.status)).length @@ -115,7 +115,7 @@ id: iss._id, text, isSelected: iss._id === value._id, - ...getIssueStatusIcon(iss, $statusByIdStore) + ...getIssueStatusIcon(iss, $statusStore.byId) } }), width: 'large' diff --git a/plugins/tracker-resources/src/components/issues/related/RelatedIssueSelector.svelte b/plugins/tracker-resources/src/components/issues/related/RelatedIssueSelector.svelte index ce049b01c1..d8d2e48f7e 100644 --- a/plugins/tracker-resources/src/components/issues/related/RelatedIssueSelector.svelte +++ b/plugins/tracker-resources/src/components/issues/related/RelatedIssueSelector.svelte @@ -29,7 +29,7 @@ } from '@hcengineering/ui' import { getIssueId } from '../../../issues' import tracker from '../../../plugin' - import { statusByIdStore, statusStore, subIssueListProvider } from '../../../utils' + import { statusStore, subIssueListProvider } from '../../../utils' export let object: WithLookup<Doc & { related: number }> | undefined export let value: WithLookup<Doc & { related: number }> | undefined @@ -69,7 +69,7 @@ } $: if (subIssues) { - const doneStatuses = $statusStore + const doneStatuses = $statusStore.statuses .filter((s) => s.category === tracker.issueStatusCategory.Completed) .map((p) => p._id) countComplete = subIssues.filter((si) => doneStatuses.includes(si.status)).length @@ -101,7 +101,7 @@ value: subIssues.map((iss) => { const text = currentProject ? `${getIssueId(currentProject, iss)} ${iss.title}` : iss.title - return { id: iss._id, text, isSelected: false, ...getIssueStatusIcon(iss, $statusByIdStore) } + return { id: iss._id, text, isSelected: false, ...getIssueStatusIcon(iss, $statusStore.byId) } }), width: 'large' }, diff --git a/plugins/tracker-resources/src/components/sprints/IssueStatistics.svelte b/plugins/tracker-resources/src/components/sprints/IssueStatistics.svelte index 24fdd1b168..fb141de7fc 100644 --- a/plugins/tracker-resources/src/components/sprints/IssueStatistics.svelte +++ b/plugins/tracker-resources/src/components/sprints/IssueStatistics.svelte @@ -17,7 +17,7 @@ import { Issue } from '@hcengineering/tracker' import { floorFractionDigits, Label } from '@hcengineering/ui' import tracker from '../../plugin' - import { statusByIdStore } from '../../utils' + import { statusStore } from '../../utils' import EstimationProgressCircle from '../issues/timereport/EstimationProgressCircle.svelte' import TimePresenter from '../issues/timereport/TimePresenter.svelte' export let docs: Issue[] | undefined = undefined @@ -28,13 +28,13 @@ $: noParents = docs?.filter((it) => !ids.has(it.attachedTo as Ref<Issue>)) $: rootNoBacklogIssues = noParents?.filter( - (it) => $statusByIdStore.get(it.status)?.category !== tracker.issueStatusCategory.Backlog + (it) => $statusStore.byId.get(it.status)?.category !== tracker.issueStatusCategory.Backlog ) $: totalEstimation = floorFractionDigits( (rootNoBacklogIssues ?? [{ estimation: 0, childInfo: [] } as unknown as Issue]) .map((it) => { - const cat = $statusByIdStore.get(it.status)?.category + const cat = $statusStore.byId.get(it.status)?.category let retEst = it.estimation if (it.childInfo?.length > 0) { diff --git a/plugins/tracker-resources/src/components/workflow/Statuses.svelte b/plugins/tracker-resources/src/components/workflow/Statuses.svelte index 1562b79812..8a06529888 100644 --- a/plugins/tracker-resources/src/components/workflow/Statuses.svelte +++ b/plugins/tracker-resources/src/components/workflow/Statuses.svelte @@ -66,10 +66,10 @@ } async function addStatus () { - if (editingStatus?.name && editingStatus?.category && $statusStore) { - const categoryStatuses = $statusStore.filter((s) => s.category === editingStatus!.category) + if (editingStatus?.name && editingStatus?.category) { + const categoryStatuses = $statusStore.statuses.filter((s) => s.category === editingStatus!.category) const prevStatus = categoryStatuses[categoryStatuses.length - 1] - const nextStatus = $statusStore[$statusStore.findIndex(({ _id }) => _id === prevStatus._id) + 1] + const nextStatus = $statusStore.statuses[$statusStore.statuses.findIndex(({ _id }) => _id === prevStatus._id) + 1] isSaving = true await client.addCollection( @@ -93,9 +93,9 @@ } async function editStatus () { - if ($statusStore && statusCategories && editingStatus?.name && editingStatus?.category && '_id' in editingStatus) { + if (statusCategories && editingStatus?.name && editingStatus?.category && '_id' in editingStatus) { const statusId = '_id' in editingStatus ? editingStatus._id : undefined - const status = statusId && $statusStore.find(({ _id }) => _id === statusId) + const status = statusId && $statusStore.byId.get(statusId) if (!status) { return @@ -157,12 +157,14 @@ }, undefined, async (result) => { - if (result && project && $statusStore) { + if (result && project) { isSaving = true await client.removeDoc(status._class, status.space, status._id) if (project.defaultIssueStatus === status._id) { - const newDefaultStatus = $statusStore.find((s) => s._id !== status._id && s.category === status.category) + const newDefaultStatus = $statusStore.statuses.find( + (s) => s._id !== status._id && s.category === status.category && s.space === status.space + ) if (newDefaultStatus?._id) { await updateProjectDefaultStatus(newDefaultStatus._id) } @@ -196,12 +198,12 @@ } async function handleDrop (toItem: IssueStatus) { - if ($statusStore && draggingStatus?._id !== toItem._id && draggingStatus?.category === toItem.category) { + if (draggingStatus?._id !== toItem._id && draggingStatus?.category === toItem.category) { const fromIndex = getStatusIndex(draggingStatus) const toIndex = getStatusIndex(toItem) const [prev, next] = [ - $statusStore[fromIndex < toIndex ? toIndex : toIndex - 1], - $statusStore[fromIndex < toIndex ? toIndex + 1 : toIndex] + $statusStore.statuses[fromIndex < toIndex ? toIndex : toIndex - 1], + $statusStore.statuses[fromIndex < toIndex ? toIndex + 1 : toIndex] ] isSaving = true @@ -213,7 +215,7 @@ } function getStatusIndex (status: IssueStatus) { - return $statusStore?.findIndex(({ _id }) => _id === status._id) ?? -1 + return $statusStore.statuses.findIndex(({ _id }) => _id === status._id) ?? -1 } function resetDrag () { @@ -242,14 +244,14 @@ </div> </svelte:fragment> - {#if project === undefined || statusCategories === undefined || $statusStore === undefined} + {#if project === undefined || statusCategories === undefined || $statusStore.statuses.length === 0} <Loading /> {:else} <Scroller> <div class="popupPanel-body__main-content py-10 clear-mins"> {#each statusCategories as category} {@const statuses = - $statusStore?.filter((s) => s.attachedTo === projectId && s.category === category._id) ?? []} + $statusStore.statuses.filter((s) => s.attachedTo === projectId && s.category === category._id) ?? []} {@const isSingle = statuses.length === 1} <div class="flex-between category-name"> <Label label={category.label} /> diff --git a/plugins/tracker-resources/src/utils.ts b/plugins/tracker-resources/src/utils.ts index 425fdd1520..adebb9c964 100644 --- a/plugins/tracker-resources/src/utils.ts +++ b/plugins/tracker-resources/src/utils.ts @@ -677,16 +677,27 @@ export async function removeProject (project: Project): Promise<void> { await client.removeDoc(tracker.class.Project, core.space.Space, project._id) } +/** + * @public + */ +export interface StatusStore { + statuses: Array<WithLookup<IssueStatus>> + byId: IdMap<WithLookup<IssueStatus>> + version: number +} // Issue status live query -export const statusByIdStore = writable<IdMap<WithLookup<IssueStatus>>>(new Map()) -export const statusStore = writable<Array<WithLookup<IssueStatus>>>([]) +export const statusStore = writable<StatusStore>({ statuses: [], byId: new Map(), version: 0 }) + const query = createQuery(true) query.query( tracker.class.IssueStatus, {}, (res) => { - statusStore.set(res) - statusByIdStore.set(toIdMap(res)) + statusStore.update((old) => ({ + version: old.version + 1, + statuses: res, + byId: toIdMap(res) + })) }, { lookup: { diff --git a/plugins/tracker/src/utils.ts b/plugins/tracker/src/utils.ts index 00efb0d0c1..e56292153c 100644 --- a/plugins/tracker/src/utils.ts +++ b/plugins/tracker/src/utils.ts @@ -39,6 +39,8 @@ export const genRanks = (count: number): Generator<string, void, unknown> => export const calcRank = (prev?: { rank: string }, next?: { rank: string }): string => { const a = prev?.rank !== undefined ? LexoRank.parse(prev.rank) : LexoRank.min() const b = next?.rank !== undefined ? LexoRank.parse(next.rank) : LexoRank.max() - + if (a.equals(b)) { + return a.genNext().toString() + } return a.between(b).toString() } diff --git a/plugins/workbench-resources/src/connect.ts b/plugins/workbench-resources/src/connect.ts index 205a34c1d2..4988bbe2a9 100644 --- a/plugins/workbench-resources/src/connect.ts +++ b/plugins/workbench-resources/src/connect.ts @@ -39,6 +39,8 @@ export async function connect (title: string): Promise<Client | undefined> { } _token = token + let clientSet = false + const clientFactory = await getResource(client.function.GetClient) _client = await clientFactory( token, @@ -54,7 +56,15 @@ export async function connect (title: string): Promise<Client | undefined> { }) }, // We need to refresh all active live queries and clear old queries. - refreshClient + () => { + try { + if (clientSet) { + refreshClient() + } + } catch (err) { + console.error(err) + } + } ) console.log('logging in as', email) @@ -72,6 +82,7 @@ export async function connect (title: string): Promise<Client | undefined> { // Update on connect, so it will be triggered setClient(_client) + clientSet = true return } @@ -105,6 +116,7 @@ export async function connect (title: string): Promise<Client | undefined> { return _client } + function clearMetadata (ws: string): void { const tokens = fetchMetadataLocalStorage(login.metadata.LoginTokens) if (tokens !== null) { diff --git a/tests/sanity/package.json b/tests/sanity/package.json index bb362d7ab9..a4b7256b6e 100644 --- a/tests/sanity/package.json +++ b/tests/sanity/package.json @@ -16,8 +16,8 @@ "dev-uitest": "cross-env PLATFORM_URI=http://localhost:8080 PLATFORM_TRANSACTOR=ws://localhost:3333 SETTING=storage-dev.json playwright test --browser chromium --reporter list,html -c ./tests/playwright.config.ts", "debug": "playwright test --browser chromium -c ./tests/playwright.config.ts --debug --headed", "dev-debug": "cross-env PLATFORM_URI=http://localhost:8080 PLATFORM_TRANSACTOR=ws://localhost:3333 SETTING=storage-dev.json playwright test --browser chromium -c ./tests/playwright.config.ts --debug --headed", - "codegen": "playwright codegen --load-storage storage.json http://localhost:8083/workbench", - "dev-codegen": "cross-env playwright codegen --load-storage storage-dev.json http://localhost:8080/workbench" + "codegen": "playwright codegen --load-storage storage.json http://localhost:8083/workbench/sanity-ws/", + "dev-codegen": "cross-env playwright codegen --load-storage storage-dev.json http://localhost:8080/workbench/sanity-ws/" }, "devDependencies": { "@hcengineering/platform-rig": "^0.6.0", diff --git a/tests/sanity/tests/tracker.spec.ts b/tests/sanity/tests/tracker.spec.ts index 4a0e900efc..aff9fd0627 100644 --- a/tests/sanity/tests/tracker.spec.ts +++ b/tests/sanity/tests/tracker.spec.ts @@ -205,9 +205,7 @@ test('create-issue-draft', async ({ page }) => { // Click text=Issues >> nth=1 await page.locator('text=Issues').nth(1).click() - await expect(page).toHaveURL( - 'http://localhost:8083/workbench/sanity-ws/tracker/tracker%3Aproject%3ADefaultProject/issues' - ) + await expect(page).toHaveURL(/.*\/workbench\/sanity-ws\/tracker\/tracker%3Aproject%3ADefaultProject\/issues/) await expect(page.locator('#new-issue')).toHaveText('New issue') // Click button:has-text("New issue") await page.locator('#new-issue').click()