Skip to content
This repository has been archived by the owner on Jul 6, 2022. It is now read-only.

feat: display controllers #743

Merged
merged 21 commits into from
May 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ import { DecryptedItemMutator, ItemsKeyMutatorInterface, ItemsKeyContent } from

export class ItemsKeyMutator extends DecryptedItemMutator<ItemsKeyContent> implements ItemsKeyMutatorInterface {
set isDefault(isDefault: boolean) {
this.content.isDefault = isDefault
this.mutableContent.isDefault = isDefault
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export class ItemsEncryptionService extends Services.AbstractService {
}

public getItemsKeys() {
return this.itemManager.itemsKeys()
return this.itemManager.getDisplayableItemsKeys()
}

public itemsKeyForPayload(payload: Models.EncryptedPayloadInterface): Models.ItemsKeyInterface | undefined {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,7 @@ export class RootKeyEncryptionService extends Services.AbstractService<RootKeySe
}

private getItemsKeys() {
return this.itemManager.itemsKeys()
return this.itemManager.getDisplayableItemsKeys()
}

public async encrypPayloadWithKeyLookup(payload: Models.DecryptedPayloadInterface): Promise<EncryptedParameters> {
Expand Down
2 changes: 1 addition & 1 deletion packages/files/src/Domain/Backups/BackupService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ export class FilesBackupService extends AbstractService {
},
})

const itemsKey = this.items.itemsKeys().find((k) => k.uuid === encryptedFile.items_key_id)
const itemsKey = this.items.getDisplayableItemsKeys().find((k) => k.uuid === encryptedFile.items_key_id)

if (!itemsKey) {
return 'failed'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,8 @@ export class DecryptedItem<C extends ItemContent = ItemContent>
return this.payload.content.references || []
}

public hasRelationshipWithItem(item: DecryptedItemInterface): boolean {
const target = this.references?.find((r) => {
return r.uuid === item.uuid
})
return !!target
public isReferencingItem(item: DecryptedItemInterface): boolean {
return this.references.find((r) => r.uuid === item.uuid) != undefined
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ import { DecryptedPayloadInterface } from '../../Payload/Interfaces/DecryptedPay
import { ItemInterface } from './ItemInterface'
import { SortableItem } from '../../../Runtime/Collection/CollectionSort'
import { DecryptedTransferPayload } from '../../TransferPayload/Interfaces/DecryptedTransferPayload'
import { SearchableItem } from '../../../Runtime/Display'

export interface DecryptedItemInterface<C extends ItemContent = ItemContent>
extends ItemInterface<DecryptedPayloadInterface<C>>,
SortableItem {
SortableItem,
SearchableItem {
readonly content: C
readonly conflictOf?: Uuid
readonly duplicateOf?: Uuid
Expand All @@ -31,7 +33,7 @@ export interface DecryptedItemInterface<C extends ItemContent = ItemContent>

payloadRepresentation(override?: Partial<DecryptedTransferPayload<C>>): DecryptedPayloadInterface<C>

hasRelationshipWithItem(item: DecryptedItemInterface): boolean
isReferencingItem(item: DecryptedItemInterface): boolean

getDomainData(domain: typeof ComponentDataDomain | typeof DefaultAppDomain): undefined | Record<string, unknown>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,33 +15,33 @@ export class DecryptedItemMutator<C extends ItemContent = ItemContent> extends I
DecryptedPayloadInterface<C>,
DecryptedItemInterface<C>
> {
protected content: C
protected mutableContent: C

constructor(item: DecryptedItemInterface<C>, type: MutationType) {
super(item, type)

const mutableCopy = Copy(this.payload.content)
this.content = mutableCopy
const mutableCopy = Copy(this.immutablePayload.content)
this.mutableContent = mutableCopy
}

public override getResult() {
if (this.type === MutationType.NonDirtying) {
return this.payload.copy({
content: this.content,
return this.immutablePayload.copy({
content: this.mutableContent,
})
}

if (this.type === MutationType.UpdateUserTimestamps) {
this.userModifiedDate = new Date()
} else {
const currentValue = this.item.userModifiedDate
const currentValue = this.immutableItem.userModifiedDate
if (!currentValue) {
this.userModifiedDate = new Date(this.item.serverUpdatedAt)
this.userModifiedDate = new Date(this.immutableItem.serverUpdatedAt)
}
}

const result = this.payload.copy({
content: this.content,
const result = this.immutablePayload.copy({
content: this.mutableContent,
dirty: true,
dirtyIndex: getIncrementedDirtyIndex(),
})
Expand All @@ -50,32 +50,32 @@ export class DecryptedItemMutator<C extends ItemContent = ItemContent> extends I
}

public override setBeginSync(began: Date, globalDirtyIndex: number) {
this.payload = this.payload.copy({
content: this.content,
this.immutablePayload = this.immutablePayload.copy({
content: this.mutableContent,
lastSyncBegan: began,
globalDirtyIndexAtLastSync: globalDirtyIndex,
})
}

/** Not recommended to use as this might break item schema if used incorrectly */
public setCustomContent(content: C): void {
this.content = Copy(content)
this.mutableContent = Copy(content)
}

public set userModifiedDate(date: Date) {
this.setAppDataItem(AppDataField.UserModifiedDate, date)
}

public set conflictOf(conflictOf: Uuid | undefined) {
this.content.conflict_of = conflictOf
this.mutableContent.conflict_of = conflictOf
}

public set protected(isProtected: boolean) {
this.content.protected = isProtected
this.mutableContent.protected = isProtected
}

public set trashed(trashed: boolean) {
this.content.trashed = trashed
this.mutableContent.trashed = trashed
}

public set pinned(pinned: boolean) {
Expand All @@ -94,52 +94,52 @@ export class DecryptedItemMutator<C extends ItemContent = ItemContent> extends I
* Overwrites the entirety of this domain's data with the data arg.
*/
public setDomainData(data: DomainDataValueType, domain: ItemDomainKey): void {
if (!this.content.appData) {
this.content.appData = {
if (!this.mutableContent.appData) {
this.mutableContent.appData = {
[DefaultAppDomain]: {},
}
}

this.content.appData[domain] = data
this.mutableContent.appData[domain] = data
}

/**
* First gets the domain data for the input domain.
* Then sets data[key] = value
*/
public setDomainDataKey(key: keyof DomainDataValueType, value: unknown, domain: ItemDomainKey): void {
if (!this.content.appData) {
this.content.appData = {
if (!this.mutableContent.appData) {
this.mutableContent.appData = {
[DefaultAppDomain]: {},
}
}

if (!this.content.appData[domain]) {
this.content.appData[domain] = {}
if (!this.mutableContent.appData[domain]) {
this.mutableContent.appData[domain] = {}
}

const domainData = this.content.appData[domain] as DomainDataValueType
const domainData = this.mutableContent.appData[domain] as DomainDataValueType
domainData[key] = value
}

public setAppDataItem(key: AppDataField | PrefKey, value: unknown) {
this.setDomainDataKey(key, value, DefaultAppDomain)
}

public addItemAsRelationship(item: DecryptedItemInterface) {
const references = this.content.references || []
public e2ePendingRefactor_addItemAsRelationship(item: DecryptedItemInterface) {
const references = this.mutableContent.references || []
if (!references.find((r) => r.uuid === item.uuid)) {
references.push({
uuid: item.uuid,
content_type: item.content_type,
})
}
this.content.references = references
this.mutableContent.references = references
}

public removeItemAsRelationship(item: ItemInterface) {
let references = this.content.references || []
let references = this.mutableContent.references || []
references = references.filter((r) => r.uuid !== item.uuid)
this.content.references = references
this.mutableContent.references = references
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ export class DeleteItemMutator<
const dirtying = this.type !== MutationType.NonDirtying
const result = new DeletedPayload(
{
...this.payload.ejected(),
...this.immutablePayload.ejected(),
deleted: true,
content: undefined,
dirty: dirtying ? true : this.payload.dirty,
dirtyIndex: dirtying ? getIncrementedDirtyIndex() : this.payload.dirtyIndex,
dirty: dirtying ? true : this.immutablePayload.dirty,
dirtyIndex: dirtying ? getIncrementedDirtyIndex() : this.immutablePayload.dirtyIndex,
},
this.payload.source,
this.immutablePayload.source,
)

return result
Expand Down
18 changes: 9 additions & 9 deletions packages/models/src/Domain/Abstract/Item/Mutator/ItemMutator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,30 +13,30 @@ export class ItemMutator<
P extends PayloadInterface<TransferPayload> = PayloadInterface<TransferPayload>,
I extends ItemInterface<P> = ItemInterface<P>,
> {
public readonly item: I
protected payload: P
public readonly immutableItem: I
protected immutablePayload: P
protected readonly type: MutationType

constructor(item: I, type: MutationType) {
this.item = item
this.immutableItem = item
this.type = type
this.payload = item.payload
this.immutablePayload = item.payload
}

public getUuid() {
return this.payload.uuid
return this.immutablePayload.uuid
}

public getItem(): I {
return this.item
return this.immutableItem
}

public getResult(): P {
if (this.type === MutationType.NonDirtying) {
return this.payload.copy()
return this.immutablePayload.copy()
}

const result = this.payload.copy({
const result = this.immutablePayload.copy({
dirty: true,
dirtyIndex: getIncrementedDirtyIndex(),
})
Expand All @@ -45,7 +45,7 @@ export class ItemMutator<
}

public setBeginSync(began: Date, globalDirtyIndex: number) {
this.payload = this.payload.copy({
this.immutablePayload = this.immutablePayload.copy({
lastSyncBegan: began,
globalDirtyIndexAtLastSync: globalDirtyIndex,
})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export enum ContenteReferenceType {
TagToParentTag = 'TagToParentTag',
FileToNote = 'FileToNote',
TagToFile = 'TagToFile',
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { ContentType } from '@standardnotes/common'
import { AnonymousReference } from './AnonymousReference'
import { ContenteReferenceType } from './ContenteReferenceType'

export interface TagToFileReference extends AnonymousReference {
content_type: ContentType.File
reference_type: ContenteReferenceType.TagToFile
}
4 changes: 4 additions & 0 deletions packages/models/src/Domain/Runtime/Collection/Collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,10 @@ export abstract class Collection<
return this.map[uuid]
}

public has(uuid: Uuid): boolean {
return this.find(uuid) != undefined
}

/**
* If an item is not found, an `undefined` element
* will be inserted into the array.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,11 @@
import { NoteContent } from './../../../Syncable/Note/NoteContent'
import { ContentType } from '@standardnotes/common'
import { DecryptedItem, EncryptedItem } from '../../../Abstract/Item'
import { DecryptedPayload, EncryptedPayload, PayloadTimestampDefaults } from '../../../Abstract/Payload'
import { DecryptedItem } from '../../../Abstract/Item'
import { DecryptedPayload, PayloadTimestampDefaults } from '../../../Abstract/Payload'
import { ItemCollection } from './ItemCollection'
import { FillItemContent } from '../../../Abstract/Content/ItemContent'
import { FillItemContent, ItemContent } from '../../../Abstract/Content/ItemContent'

describe('item collection', () => {
const createEncryptedPayload = (uuid?: string) => {
return new EncryptedPayload({
uuid: uuid || String(Math.random()),
content_type: ContentType.Note,
content: '004:...',
enc_item_key: '004:...',
items_key_id: '123',
waitingForKey: true,
errorDecrypting: true,
...PayloadTimestampDefaults(),
})
}

const createDecryptedPayload = (uuid?: string): DecryptedPayload => {
return new DecryptedPayload({
uuid: uuid || String(Math.random()),
Expand All @@ -30,31 +17,20 @@ describe('item collection', () => {
})
}

it('should not include encrypted items as displayable', () => {
const payload = createEncryptedPayload()
const item = new EncryptedItem(payload)

it('setting same item twice should not result in doubles', () => {
const collection = new ItemCollection()
collection.setDisplayOptions(ContentType.Note, 'title')
collection.set(item)

const results = collection.displayElements(ContentType.Note)

expect(results).toHaveLength(0)
})

it('should remove item from map if previously decrypted but now encrypted', () => {
const collection = new ItemCollection()
collection.setDisplayOptions(ContentType.Note, 'title')

const decryptedItem = new DecryptedItem(createDecryptedPayload())
collection.set(decryptedItem)

const encryptedItem = new EncryptedItem(createEncryptedPayload(decryptedItem.uuid))
collection.set(encryptedItem)
const updatedItem = new DecryptedItem(
decryptedItem.payload.copy({
content: { foo: 'bar' } as unknown as jest.Mocked<ItemContent>,
}),
)

const results = collection.displayElements(ContentType.Note)
collection.set(updatedItem)

expect(results).toHaveLength(0)
expect(collection.all()).toHaveLength(1)
})
})
Loading