Skip to content

Commit

Permalink
187178550 v3 Improve Item Sort (#1396)
Browse files Browse the repository at this point in the history
* Improve removeCases efficiency.

* Use moveItem function for itemOrder requests.
  • Loading branch information
tealefristoe authored Aug 14, 2024
1 parent 9cba3ce commit 0ec29df
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 20 deletions.
9 changes: 4 additions & 5 deletions v3/src/data-interactive/handlers/item-search-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,11 @@ export const diItemSearchHandler: DIHandler = {
})
} else {
// Otherwise, move all the items to the beginning or end
const items = itemIds.map(id => dataContext.getItem(id)) as ICase[]
dataContext.removeCases(itemIds)
const options = itemOrder === "first" && dataContext.itemIds.length > 0
? { before: dataContext.itemIds[0] }
const movingItemIds = new Set(itemIds)
const before = itemOrder === "first"
? dataContext.itemIds.find(id => !movingItemIds.has(id))
: undefined
dataContext.addCases(items, options)
dataContext.moveItems(itemIds, { before })
}
dataContext.validateCases()
})
Expand Down
7 changes: 7 additions & 0 deletions v3/src/models/data/data-set-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@ export interface IAddCasesOptions {
canonicalize?: boolean;
}

export interface IMoveItemsOptions {
// id of item before/after which to move items
// if not specified, items are moved to end
before?: string;
after?: string;
}

export interface IAddAttributeOptions {
// id of attribute before which to insert new cases
// if not specified, new attribute is appended
Expand Down
72 changes: 57 additions & 15 deletions v3/src/models/data/data-set.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ import {
import {
CaseInfo, IAddAttributeOptions, IAddCasesOptions, IAddCollectionOptions, IAttributeChangeResult, ICase,
ICaseCreation, IDerivationSpec, IGetCaseOptions, IGetCasesOptions, IItem, IMoveAttributeCollectionOptions,
ItemInfo
IMoveItemsOptions, ItemInfo
} from "./data-set-types"
// eslint-disable-next-line import/no-cycle
import { isLegacyDataSetSnap, isOriginalDataSetSnap, isTempDataSetSnap } from "./data-set-conversion"
Expand Down Expand Up @@ -919,22 +919,64 @@ export const DataSet = V2Model.named("DataSet").props({
},

removeCases(caseIDs: string[]) {
caseIDs.forEach((caseID) => {
const index = self.getItemIndex(caseID)
if (index != null) {
self.itemIds.splice(index, 1)
self.attributes.forEach((attr) => {
attr.removeValues(index)
})
self.selection.delete(caseID)
self.itemInfoMap.delete(caseID)
for (let i = index; i < self.items.length; ++i) {
const itemId = self.items[i].__id__
const itemInfo = self.itemInfoMap.get(itemId)
if (itemInfo) itemInfo.index = i
}
// Remove the items last -> first, so we only have to update itemInfo once
const items = caseIDs.map(id => ({ id, index: self.getItemIndex(id) }))
.filter(info => info.index != null) as { id: string, index: number }[]
items.sort((a, b) => b.index - a.index)
const firstIndex = items[items.length - 1]?.index ?? -1
items.forEach(({ id: caseID, index }) => {
self.itemIds.splice(index, 1)
self.attributes.forEach((attr) => {
attr.removeValues(index)
})
self.selection.delete(caseID)
self.itemInfoMap.delete(caseID)
})
if (firstIndex >= 0) {
for (let i = firstIndex; i < self.itemIds.length; ++i) {
const itemId = self.itemIds[i]
const itemInfo = self.itemInfoMap.get(itemId)
if (itemInfo) itemInfo.index = i
}
}
},

moveItems(itemIds: string[], options?: IMoveItemsOptions) {
const indices = itemIds.map(itemId => self.getItemIndex(itemId)).filter(index => index != null)
.sort((a: number, b: number) => b - a) // Reverse order
const items = indices.map(index => {
const item = { index, item: self.items[index], values: [] as { strValue: string, numValue: number }[] }
self.attributes.forEach(attr => item.values.push({
strValue: attr.strValues[index],
numValue: attr.numValues[index]
}))
return item
}).reverse() // Normal order

// Remove from ordered arrays
indices.forEach(index => {
self.itemIds.splice(index, 1)
self.attributes.forEach(attr => attr.removeValues(index))
})

// Determine position to re-insert items
const beforeIndex = options?.before ? self.itemIds.indexOf(options.before) : undefined
const afterIndex = options?.after ? self.itemIds.indexOf(options.after) + 1 : undefined
const insertIndex = afterIndex ?? beforeIndex ?? self.itemIds.length

// Add back to ordered arrays
self.itemIds.splice(insertIndex, 0, ...items.map(({ item }) => item.__id__))
self.attributes.forEach((attr, index) => {
attr.strValues.splice(insertIndex, 0, ...items.map(({ values }) => values[index].strValue))
attr.numValues.splice(insertIndex, 0, ...items.map(({ values }) => values[index].numValue))
})

// Fix indices
for (let i = 0; i < self.itemIds.length; ++i) {
const itemId = self.itemIds[i]
const itemInfo = self.itemInfoMap.get(itemId)
if (itemInfo) itemInfo.index = i
}
},

selectAll(select = true) {
Expand Down

0 comments on commit 0ec29df

Please sign in to comment.