feat: edit smart view predicate as json (#2012)

This commit is contained in:
Aman Harwara
2022-11-16 18:15:26 +05:30
committed by GitHub
parent 943698d506
commit f3e4ba8779
18 changed files with 391 additions and 106 deletions

View File

@@ -0,0 +1,58 @@
import { MutationType } from '../../Abstract/Item'
import { createSmartViewWithContent, createSmartViewWithTitle } from '../../Utilities/Test/SpecUtils'
import { SmartViewMutator } from './SmartViewMutator'
describe('smart view mutator', () => {
it('should set predicate', () => {
const smartView = createSmartViewWithContent({
title: 'foo',
predicate: {
keypath: 'title',
operator: '=',
value: 'foo',
},
})
const mutator = new SmartViewMutator(smartView, MutationType.UpdateUserTimestamps)
mutator.predicate = {
keypath: 'title',
operator: '=',
value: 'bar',
}
const result = mutator.getResult()
expect(result.content.predicate.value).toBe('bar')
})
it('preferences should be undefined if previously undefined', () => {
const smartView = createSmartViewWithTitle()
const mutator = new SmartViewMutator(smartView, MutationType.UpdateUserTimestamps)
const result = mutator.getResult()
expect(result.content.preferences).toBeFalsy()
})
it('preferences should be lazy-created if attempting to set a property', () => {
const smartView = createSmartViewWithTitle()
const mutator = new SmartViewMutator(smartView, MutationType.UpdateUserTimestamps)
mutator.preferences.sortBy = 'content_type'
const result = mutator.getResult()
expect(result.content.preferences?.sortBy).toEqual('content_type')
})
it('preferences should be nulled if client is reseting', () => {
const smartView = createSmartViewWithContent({
title: 'foo',
preferences: {
sortBy: 'content_type',
},
})
const mutator = new SmartViewMutator(smartView, MutationType.UpdateUserTimestamps)
mutator.preferences = undefined
const result = mutator.getResult()
expect(result.content.preferences).toBeFalsy()
})
})

View File

@@ -0,0 +1,13 @@
import { DecryptedItemInterface, MutationType } from '../../Abstract/Item'
import { TagMutator } from '../Tag'
import { SmartViewContent } from './SmartViewContent'
export class SmartViewMutator extends TagMutator<SmartViewContent> {
constructor(item: DecryptedItemInterface<SmartViewContent>, type: MutationType) {
super(item, type)
}
set predicate(predicate: SmartViewContent['predicate']) {
this.mutableContent.predicate = predicate
}
}

View File

@@ -2,3 +2,5 @@ export * from './SmartView'
export * from './SmartViewBuilder'
export * from './SystemViewId'
export * from './SmartViewContent'
export * from './SmartViewMutator'
export * from './SmartViewIcons'

View File

@@ -11,10 +11,10 @@ import { TagToFileReference } from '../../Abstract/Reference/TagToFileReference'
import { TagPreferences } from './TagPreferences'
import { DecryptedItemInterface, MutationType } from '../../Abstract/Item'
export class TagMutator extends DecryptedItemMutator<TagContent> {
export class TagMutator<Content extends TagContent = TagContent> extends DecryptedItemMutator<Content> {
private mutablePreferences?: TagPreferences
constructor(item: DecryptedItemInterface<TagContent>, type: MutationType) {
constructor(item: DecryptedItemInterface<Content>, type: MutationType) {
super(item, type)
this.mutablePreferences = this.mutableContent.preferences

View File

@@ -33,6 +33,7 @@ import {
import { DeletedItem } from '../../Abstract/Item/Implementations/DeletedItem'
import { EncryptedItemInterface } from '../../Abstract/Item/Interfaces/EncryptedItem'
import { DeletedItemInterface } from '../../Abstract/Item/Interfaces/DeletedItem'
import { SmartViewMutator } from '../../Syncable/SmartView'
type ItemClass<C extends ItemContent = ItemContent> = new (payload: DecryptedPayloadInterface<C>) => DecryptedItem<C>
@@ -56,7 +57,7 @@ const ContentTypeClassMapping: Partial<Record<ContentType, MappingEntry>> = {
[ContentType.ExtensionRepo]: { itemClass: SNFeatureRepo },
[ContentType.File]: { itemClass: FileItem, mutatorClass: FileMutator },
[ContentType.Note]: { itemClass: SNNote, mutatorClass: NoteMutator },
[ContentType.SmartView]: { itemClass: SmartView, mutatorClass: TagMutator },
[ContentType.SmartView]: { itemClass: SmartView, mutatorClass: SmartViewMutator },
[ContentType.Tag]: { itemClass: SNTag, mutatorClass: TagMutator },
[ContentType.Theme]: { itemClass: SNTheme, mutatorClass: ThemeMutator },
[ContentType.UserPrefs]: { itemClass: SNUserPrefs, mutatorClass: UserPrefsMutator },

View File

@@ -5,6 +5,7 @@ import { DecryptedPayload, PayloadSource, PayloadTimestampDefaults } from '../..
import { FileContent, FileItem } from '../../Syncable/File'
import { NoteContent, SNNote } from '../../Syncable/Note'
import { SNTag } from '../../Syncable/Tag'
import { SmartView, SmartViewContent } from '../../Syncable/SmartView'
let currentId = 0
@@ -55,6 +56,20 @@ export const createTagWithContent = (content: Partial<TagContent>): SNTag => {
)
}
export const createSmartViewWithContent = (content: Partial<SmartViewContent>): SmartView => {
return new SmartView(
new DecryptedPayload(
{
uuid: mockUuid(),
content_type: ContentType.SmartView,
content: FillItemContent<SmartViewContent>(content),
...PayloadTimestampDefaults(),
},
PayloadSource.Constructor,
),
)
}
export const createTagWithTitle = (title = 'photos') => {
return new SNTag(
new DecryptedPayload(
@@ -69,6 +84,20 @@ export const createTagWithTitle = (title = 'photos') => {
)
}
export const createSmartViewWithTitle = (title = 'photos') => {
return new SmartView(
new DecryptedPayload(
{
uuid: mockUuid(),
content_type: ContentType.SmartView,
content: FillItemContent<SmartViewContent>({ title }),
...PayloadTimestampDefaults(),
},
PayloadSource.Constructor,
),
)
}
export const createFile = (name = 'screenshot.png') => {
return new FileItem(
new DecryptedPayload(