Pleroma-tan apologizing for all the changes See merge request pleroma/pleroma-fe!1581merge-requests/1699/head
commit
346e806153
After Width: | Height: | Size: 396 KiB |
After Width: | Height: | Size: 521 KiB |
@ -0,0 +1,66 @@
|
||||
import Modal from 'src/components/modal/modal.vue'
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import pleromaTan from 'src/assets/pleromatan_apology.png'
|
||||
import pleromaTanFox from 'src/assets/pleromatan_apology_fox.png'
|
||||
|
||||
import {
|
||||
faTimes
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
library.add(
|
||||
faTimes
|
||||
)
|
||||
|
||||
export const CURRENT_UPDATE_COUNTER = 1
|
||||
|
||||
const UpdateNotification = {
|
||||
data () {
|
||||
return {
|
||||
pleromaTanVariant: Math.random() > 0.5 ? pleromaTan : pleromaTanFox,
|
||||
showingMore: false,
|
||||
contentHeight: 0
|
||||
}
|
||||
},
|
||||
components: {
|
||||
Modal
|
||||
},
|
||||
computed: {
|
||||
pleromaTanStyles () {
|
||||
return {
|
||||
'shape-outside': 'url(' + this.pleromaTanVariant + ')'
|
||||
}
|
||||
},
|
||||
dynamicStyles () {
|
||||
return {
|
||||
'--____extraInfoGroupHeight': this.contentHeight + 'px'
|
||||
}
|
||||
},
|
||||
shouldShow () {
|
||||
return !this.$store.state.instance.disableUpdateNotification &&
|
||||
this.$store.state.users.currentUser &&
|
||||
this.$store.state.serverSideStorage.flagStorage.updateCounter < CURRENT_UPDATE_COUNTER &&
|
||||
!this.$store.state.serverSideStorage.flagStorage.dontShowUpdateNotifs
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleShow () {
|
||||
this.showingMore = !this.showingMore
|
||||
},
|
||||
neverShowAgain () {
|
||||
this.toggleShow()
|
||||
this.$store.commit('setFlag', { flag: 'updateCounter', value: CURRENT_UPDATE_COUNTER })
|
||||
this.$store.commit('setFlag', { flag: 'dontShowUpdateNotifs', value: 1 })
|
||||
this.$store.dispatch('pushServerSideStorage')
|
||||
},
|
||||
dismiss () {
|
||||
this.$store.commit('setFlag', { flag: 'updateCounter', value: CURRENT_UPDATE_COUNTER })
|
||||
this.$store.dispatch('pushServerSideStorage')
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
setTimeout(() => {
|
||||
this.contentHeight = this.$refs.animatedText.scrollHeight
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
|
||||
export default UpdateNotification
|
@ -0,0 +1,107 @@
|
||||
@import 'src/_variables.scss';
|
||||
.UpdateNotification {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.UpdateNotificationModal {
|
||||
--__top-fringe: 15em; // how much pleroma-tan should stick her head above
|
||||
--__bottom-fringe: 80em; // just reserving as much as we can, number is mostly irrelevant
|
||||
--__right-fringe: 8em;
|
||||
|
||||
font-size: 15px;
|
||||
position: relative;
|
||||
transition: transform;
|
||||
transition-timing-function: ease-in-out;
|
||||
transition-duration: 500ms;
|
||||
|
||||
.text {
|
||||
max-width: 40em;
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
@media all and (max-width: 800px) {
|
||||
/* For mobile, the modal takes 100% of the available screen.
|
||||
This ensures the minimized modal is always 50px above the browser bottom bar regardless of whether or not it is visible.
|
||||
*/
|
||||
width: 100vw;
|
||||
}
|
||||
|
||||
@media all and (max-height: 600px) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.content {
|
||||
overflow: hidden;
|
||||
margin-top: calc(-1 * var(--__top-fringe));
|
||||
margin-bottom: calc(-1 * var(--__bottom-fringe));
|
||||
margin-right: calc(-1 * var(--__right-fringe));
|
||||
}
|
||||
|
||||
.panel-body {
|
||||
border-width: 0 0 1px 0;
|
||||
border-style: solid;
|
||||
border-color: var(--border, $fallback--border);
|
||||
}
|
||||
|
||||
.panel-footer {
|
||||
z-index: 22;
|
||||
position: relative;
|
||||
border-width: 0;
|
||||
grid-template-columns: auto;
|
||||
}
|
||||
|
||||
.pleroma-tan {
|
||||
object-fit: cover;
|
||||
object-position: top;
|
||||
transition: position, left, right, top, bottom, max-width, max-height;
|
||||
transition-timing-function: ease-in-out;
|
||||
transition-duration: 500ms;
|
||||
width: 25em;
|
||||
float: right;
|
||||
z-index: 20;
|
||||
position: relative;
|
||||
shape-margin: 0.5em;
|
||||
filter: drop-shadow(5px 5px 10px rgba(0,0,0,0.5));
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.spacer-top {
|
||||
min-height: var(--__top-fringe);
|
||||
}
|
||||
|
||||
.spacer-bottom {
|
||||
min-height: var(--__bottom-fringe);
|
||||
}
|
||||
|
||||
.extra-info-group {
|
||||
transition: max-height, padding, height;
|
||||
transition-timing-function: ease-in-out;
|
||||
transition-duration: 500ms;
|
||||
max-height: calc(var(--____extraInfoGroupHeight) + 1em); // include bottom padding
|
||||
mask:
|
||||
linear-gradient(to top, white, transparent) bottom/100% 2px no-repeat,
|
||||
linear-gradient(to top, white, white);
|
||||
}
|
||||
|
||||
.art-credit {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
&.-peek {
|
||||
/* Explanation:
|
||||
* 100vh - 100% = Distance between modal's top+bottom boundaries and screen
|
||||
* (100vh - 100%) / 2 = Distance between bottom (or top) boundary and screen
|
||||
*/
|
||||
transform: translateY(calc(((100vh - 100%) / 2)));
|
||||
|
||||
.pleroma-tan {
|
||||
float: right;
|
||||
z-index: 10;
|
||||
shape-image-threshold: 0.7;
|
||||
}
|
||||
|
||||
.extra-info-group {
|
||||
max-height: 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
<template>
|
||||
<Modal
|
||||
:is-open="!!shouldShow"
|
||||
class="UpdateNotification"
|
||||
:no-background="true"
|
||||
>
|
||||
<div
|
||||
class="UpdateNotificationModal panel"
|
||||
:class="{ '-peek': !showingMore }"
|
||||
:style="dynamicStyles"
|
||||
>
|
||||
<div class="panel-heading">
|
||||
<span class="title">
|
||||
{{ $t('update.big_update_title') }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="content">
|
||||
<img
|
||||
class="pleroma-tan"
|
||||
:src="pleromaTanVariant"
|
||||
:style="pleromaTanStyles"
|
||||
>
|
||||
<div class="spacer-top" />
|
||||
<div class="text">
|
||||
<p>
|
||||
{{ $t('update.big_update_content') }}
|
||||
</p>
|
||||
<div
|
||||
ref="animatedText"
|
||||
class="extra-info-group"
|
||||
>
|
||||
<i18n-t
|
||||
keypath="update.update_bugs"
|
||||
tag="p"
|
||||
>
|
||||
<template #pleromaGitlab>
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://git.pleroma.social/"
|
||||
>{{ $t('update.update_bugs_gitlab') }}</a>
|
||||
</template>
|
||||
</i18n-t>
|
||||
<i18n-t
|
||||
keypath="update.update_changelog"
|
||||
tag="p"
|
||||
>
|
||||
<template #theFullChangelog>
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://pleroma.social/announcements/"
|
||||
>{{ $t('update.update_changelog_here') }}</a>
|
||||
</template>
|
||||
</i18n-t>
|
||||
<p class="art-credit">
|
||||
<i18n-t
|
||||
keypath="update.art_by"
|
||||
tag="small"
|
||||
>
|
||||
<template #linkToArtist>
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://post.ebin.club/pipivovott"
|
||||
>pipivovott</a>
|
||||
</template>
|
||||
</i18n-t>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="spacer-bottom" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-footer">
|
||||
<button
|
||||
class="button-default"
|
||||
@click.prevent="neverShowAgain"
|
||||
>
|
||||
{{ $t("general.never_show_again") }}
|
||||
</button>
|
||||
<button
|
||||
v-if="!showingMore"
|
||||
class="button-default"
|
||||
@click.prevent="toggleShow"
|
||||
>
|
||||
{{ $t("general.show_more") }}
|
||||
</button>
|
||||
<button
|
||||
class="button-default"
|
||||
@click.prevent="dismiss"
|
||||
>
|
||||
{{ $t("general.dismiss") }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script src="./update_notification.js"></script>
|
||||
|
||||
<style src="./update_notification.scss" lang="scss"></style>
|
@ -0,0 +1,230 @@
|
||||
import { toRaw } from 'vue'
|
||||
import { isEqual, cloneDeep } from 'lodash'
|
||||
import { CURRENT_UPDATE_COUNTER } from 'src/components/update_notification/update_notification.js'
|
||||
|
||||
export const VERSION = 1
|
||||
export const NEW_USER_DATE = new Date('2022-08-04') // date of writing this, basically
|
||||
|
||||
export const COMMAND_TRIM_FLAGS = 1000
|
||||
export const COMMAND_TRIM_FLAGS_AND_RESET = 1001
|
||||
|
||||
export const defaultState = {
|
||||
// do we need to update data on server?
|
||||
dirty: false,
|
||||
// storage of flags - stuff that can only be set and incremented
|
||||
flagStorage: {
|
||||
updateCounter: 0, // Counter for most recent update notification seen
|
||||
// TODO move to prefsStorage when that becomes a thing since only way
|
||||
// this can be reset is by complete reset of all flags
|
||||
dontShowUpdateNotifs: 0, // if user chose to not show update notifications ever again
|
||||
reset: 0 // special flag that can be used to force-reset all flags, debug purposes only
|
||||
// special reset codes:
|
||||
// 1000: trim keys to those known by currently running FE
|
||||
// 1001: same as above + reset everything to 0
|
||||
},
|
||||
// raw data
|
||||
raw: null,
|
||||
// local cache
|
||||
cache: null
|
||||
}
|
||||
|
||||
export const newUserFlags = {
|
||||
...defaultState.flagStorage,
|
||||
updateCounter: CURRENT_UPDATE_COUNTER // new users don't need to see update notification
|
||||
}
|
||||
|
||||
const _wrapData = (data) => ({
|
||||
...data,
|
||||
_timestamp: Date.now(),
|
||||
_version: VERSION
|
||||
})
|
||||
|
||||
const _checkValidity = (data) => data._timestamp > 0 && data._version > 0
|
||||
|
||||
export const _getRecentData = (cache, live) => {
|
||||
const result = { recent: null, stale: null, needUpload: false }
|
||||
const cacheValid = _checkValidity(cache || {})
|
||||
const liveValid = _checkValidity(live || {})
|
||||
if (!liveValid && cacheValid) {
|
||||
result.needUpload = true
|
||||
console.debug('Nothing valid stored on server, assuming cache to be source of truth')
|
||||
result.recent = cache
|
||||
result.stale = live
|
||||
} else if (!cacheValid && liveValid) {
|
||||
console.debug('Valid storage on server found, no local cache found, using live as source of truth')
|
||||
result.recent = live
|
||||
result.stale = cache
|
||||
} else if (cacheValid && liveValid) {
|
||||
console.debug('Both sources have valid data, figuring things out...')
|
||||
if (live._timestamp === cache._timestamp && live._version === cache._version) {
|
||||
console.debug('Same version/timestamp on both source, source of truth irrelevant')
|
||||
result.recent = cache
|
||||
result.stale = live
|
||||
} else {
|
||||
console.debug('Different timestamp, figuring out which one is more recent')
|
||||
if (live._timestamp < cache._timestamp) {
|
||||
result.recent = cache
|
||||
result.stale = live
|
||||
} else {
|
||||
result.recent = live
|
||||
result.stale = cache
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.debug('Both sources are invalid, start from scratch')
|
||||
result.needUpload = true
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
export const _getAllFlags = (recent, stale) => {
|
||||
return Array.from(new Set([
|
||||
...Object.keys(toRaw((recent || {}).flagStorage || {})),
|
||||
...Object.keys(toRaw((stale || {}).flagStorage || {}))
|
||||
]))
|
||||
}
|
||||
|
||||
export const _mergeFlags = (recent, stale, allFlagKeys) => {
|
||||
return Object.fromEntries(allFlagKeys.map(flag => {
|
||||
const recentFlag = recent.flagStorage[flag]
|
||||
const staleFlag = stale.flagStorage[flag]
|
||||
// use flag that is of higher value
|
||||
return [flag, Number((recentFlag > staleFlag ? recentFlag : staleFlag) || 0)]
|
||||
}))
|
||||
}
|
||||
|
||||
export const _resetFlags = (totalFlags, knownKeys = defaultState.flagStorage) => {
|
||||
let result = { ...totalFlags }
|
||||
const allFlagKeys = Object.keys(totalFlags)
|
||||
// flag reset functionality
|
||||
if (totalFlags.reset >= COMMAND_TRIM_FLAGS && totalFlags.reset <= COMMAND_TRIM_FLAGS_AND_RESET) {
|
||||
console.debug('Received command to trim the flags')
|
||||
const knownKeysSet = new Set(Object.keys(knownKeys))
|
||||
|
||||
// Trim
|
||||
result = {}
|
||||
allFlagKeys.forEach(flag => {
|
||||
if (knownKeysSet.has(flag)) {
|
||||
result[flag] = totalFlags[flag]
|
||||
}
|
||||
})
|
||||
|
||||
// Reset
|
||||
if (totalFlags.reset === COMMAND_TRIM_FLAGS_AND_RESET) {
|
||||
// 1001 - and reset everything to 0
|
||||
console.debug('Received command to reset the flags')
|
||||
Object.keys(knownKeys).forEach(flag => { result[flag] = 0 })
|
||||
}
|
||||
} else if (totalFlags.reset > 0 && totalFlags.reset < 9000) {
|
||||
console.debug('Received command to reset the flags')
|
||||
allFlagKeys.forEach(flag => { result[flag] = 0 })
|
||||
}
|
||||
result.reset = 0
|
||||
return result
|
||||
}
|
||||
|
||||
export const _doMigrations = (cache) => {
|
||||
if (!cache) return cache
|
||||
|
||||
if (cache._version < VERSION) {
|
||||
console.debug('Local cached data has older version, seeing if there any migrations that can be applied')
|
||||
|
||||
// no migrations right now since we only have one version
|
||||
console.debug('No migrations found')
|
||||
}
|
||||
|
||||
if (cache._version > VERSION) {
|
||||
console.debug('Local cached data has newer version, seeing if there any reverse migrations that can be applied')
|
||||
|
||||
// no reverse migrations right now but we leave a possibility of loading a hotpatch if need be
|
||||
if (window._PLEROMA_HOTPATCH) {
|
||||
if (window._PLEROMA_HOTPATCH.reverseMigrations) {
|
||||
console.debug('Found hotpatch migration, applying')
|
||||
return window._PLEROMA_HOTPATCH.reverseMigrations.call({}, 'serverSideStorage', { from: cache._version, to: VERSION }, cache)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cache
|
||||
}
|
||||
|
||||
export const mutations = {
|
||||
setServerSideStorage (state, userData) {
|
||||
const live = userData.storage
|
||||
state.raw = live
|
||||
let cache = state.cache
|
||||
|
||||
cache = _doMigrations(cache)
|
||||
|
||||
let { recent, stale, needsUpload } = _getRecentData(cache, live)
|
||||
|
||||
const userNew = userData.created_at > NEW_USER_DATE
|
||||
const flagsTemplate = userNew ? newUserFlags : defaultState.flagStorage
|
||||
let dirty = false
|
||||
|
||||
if (recent === null) {
|
||||
console.debug(`Data is empty, initializing for ${userNew ? 'new' : 'existing'} user`)
|
||||
recent = _wrapData({
|
||||
flagStorage: { ...flagsTemplate }
|
||||
})
|
||||
}
|
||||
|
||||
if (!needsUpload && recent && stale) {
|
||||
console.debug('Checking if data needs merging...')
|
||||
// discarding timestamps and versions
|
||||
const { _timestamp: _0, _version: _1, ...recentData } = recent
|
||||
const { _timestamp: _2, _version: _3, ...staleData } = stale
|
||||
dirty = !isEqual(recentData, staleData)
|
||||
console.debug(`Data ${dirty ? 'needs' : 'doesn\'t need'} merging`)
|
||||
}
|
||||
|
||||
const allFlagKeys = _getAllFlags(recent, stale)
|
||||
let totalFlags
|
||||
if (dirty) {
|
||||
// Merge the flags
|
||||
console.debug('Merging the flags...')
|
||||
totalFlags = _mergeFlags(recent, stale, allFlagKeys)
|
||||
} else {
|
||||
totalFlags = recent.flagStorage
|
||||
}
|
||||
|
||||
totalFlags = _resetFlags(totalFlags)
|
||||
|
||||
recent.flagStorage = totalFlags
|
||||
|
||||
state.dirty = dirty || needsUpload
|
||||
state.cache = recent
|
||||
// set local timestamp to smaller one if we don't have any changes
|
||||
if (stale && recent && !state.dirty) {
|
||||
state.cache._timestamp = Math.min(stale._timestamp, recent._timestamp)
|
||||
}
|
||||
state.flagStorage = state.cache.flagStorage
|
||||
},
|
||||
setFlag (state, { flag, value }) {
|
||||
state.flagStorage[flag] = value
|
||||
state.dirty = true
|
||||
}
|
||||
}
|
||||
|
||||
const serverSideStorage = {
|
||||
state: {
|
||||
...cloneDeep(defaultState)
|
||||
},
|
||||
mutations,
|
||||
actions: {
|
||||
pushServerSideStorage ({ state, rootState, commit }, { force = false } = {}) {
|
||||
const needPush = state.dirty || force
|
||||
if (!needPush) return
|
||||
state.cache = _wrapData({
|
||||
flagStorage: toRaw(state.flagStorage)
|
||||
})
|
||||
const params = { pleroma_settings_store: { 'pleroma-fe': state.cache } }
|
||||
rootState.api.backendInteractor
|
||||
.updateProfile({ params })
|
||||
.then((user) => commit('setServerSideStorage', user))
|
||||
state.dirty = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default serverSideStorage
|
@ -0,0 +1,178 @@
|
||||
import { cloneDeep } from 'lodash'
|
||||
|
||||
import {
|
||||
VERSION,
|
||||
COMMAND_TRIM_FLAGS,
|
||||
COMMAND_TRIM_FLAGS_AND_RESET,
|
||||
_getRecentData,
|
||||
_getAllFlags,
|
||||
_mergeFlags,
|
||||
_resetFlags,
|
||||
mutations,
|
||||
defaultState,
|
||||
newUserFlags
|
||||
} from 'src/modules/serverSideStorage.js'
|
||||
|
||||
describe('The serverSideStorage module', () => {
|
||||
describe('mutations', () => {
|
||||
describe('setServerSideStorage', () => {
|
||||
const { setServerSideStorage } = mutations
|
||||
const user = {
|
||||
created_at: new Date('1999-02-09'),
|
||||
storage: {}
|
||||
}
|
||||
|
||||
it('should initialize storage if none present', () => {
|
||||
const state = cloneDeep(defaultState)
|
||||
setServerSideStorage(state, user)
|
||||
expect(state.cache._version).to.eql(VERSION)
|
||||
expect(state.cache._timestamp).to.be.a('number')
|
||||
expect(state.cache.flagStorage).to.eql(defaultState.flagStorage)
|
||||
})
|
||||
|
||||
it('should initialize storage with proper flags for new users if none present', () => {
|
||||
const state = cloneDeep(defaultState)
|
||||
setServerSideStorage(state, { ...user, created_at: new Date() })
|
||||
expect(state.cache._version).to.eql(VERSION)
|
||||
expect(state.cache._timestamp).to.be.a('number')
|
||||
expect(state.cache.flagStorage).to.eql(newUserFlags)
|
||||
})
|
||||
|
||||
it('should merge flags even if remote timestamp is older', () => {
|
||||
const state = {
|
||||
...cloneDeep(defaultState),
|
||||
cache: {
|
||||
_timestamp: Date.now(),
|
||||
_version: VERSION,
|
||||
...cloneDeep(defaultState)
|
||||
}
|
||||
}
|
||||
setServerSideStorage(
|
||||
state,
|
||||
{
|
||||
...user,
|
||||
storage: {
|
||||
_timestamp: 123,
|
||||
_version: VERSION,
|
||||
flagStorage: {
|
||||
...defaultState.flagStorage,
|
||||
updateCounter: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
expect(state.cache.flagStorage).to.eql({
|
||||
...defaultState.flagStorage,
|
||||
updateCounter: 1
|
||||
})
|
||||
})
|
||||
|
||||
it('should reset local timestamp to remote if contents are the same', () => {
|
||||
const state = {
|
||||
...cloneDeep(defaultState),
|
||||
cache: null
|
||||
}
|
||||
setServerSideStorage(
|
||||
state,
|
||||
{
|
||||
...user,
|
||||
storage: {
|
||||
_timestamp: 123,
|
||||
_version: VERSION,
|
||||
flagStorage: {
|
||||
...defaultState.flagStorage,
|
||||
updateCounter: 999
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
expect(state.cache._timestamp).to.eql(123)
|
||||
expect(state.flagStorage.updateCounter).to.eql(999)
|
||||
expect(state.cache.flagStorage.updateCounter).to.eql(999)
|
||||
})
|
||||
|
||||
it('should remote version if local missing', () => {
|
||||
const state = cloneDeep(defaultState)
|
||||
setServerSideStorage(state, user)
|
||||
expect(state.cache._version).to.eql(VERSION)
|
||||
expect(state.cache._timestamp).to.be.a('number')
|
||||
expect(state.cache.flagStorage).to.eql(defaultState.flagStorage)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('helper functions', () => {
|
||||
describe('_getRecentData', () => {
|
||||
it('should handle nulls correctly', () => {
|
||||
expect(_getRecentData(null, null)).to.eql({ recent: null, stale: null, needUpload: true })
|
||||
})
|
||||
|
||||
it('doesn\'t choke on invalid data', () => {
|
||||
expect(_getRecentData({ a: 1 }, { b: 2 })).to.eql({ recent: null, stale: null, needUpload: true })
|
||||
})
|
||||
|
||||
it('should prefer the valid non-null correctly, needUpload works properly', () => {
|
||||
const nonNull = { _version: VERSION, _timestamp: 1 }
|
||||
expect(_getRecentData(nonNull, null)).to.eql({ recent: nonNull, stale: null, needUpload: true })
|
||||
expect(_getRecentData(null, nonNull)).to.eql({ recent: nonNull, stale: null, needUpload: false })
|
||||
})
|
||||
|
||||
it('should prefer the one with higher timestamp', () => {
|
||||
const a = { _version: VERSION, _timestamp: 1 }
|
||||
const b = { _version: VERSION, _timestamp: 2 }
|
||||
|
||||
expect(_getRecentData(a, b)).to.eql({ recent: b, stale: a, needUpload: false })
|
||||
expect(_getRecentData(b, a)).to.eql({ recent: b, stale: a, needUpload: false })
|
||||
})
|
||||
|
||||
it('case where both are same', () => {
|
||||
const a = { _version: VERSION, _timestamp: 3 }
|
||||
const b = { _version: VERSION, _timestamp: 3 }
|
||||
|
||||
expect(_getRecentData(a, b)).to.eql({ recent: b, stale: a, needUpload: false })
|
||||
expect(_getRecentData(b, a)).to.eql({ recent: b, stale: a, needUpload: false })
|
||||
})
|
||||
})
|
||||
|
||||
describe('_getAllFlags', () => {
|
||||
it('should handle nulls properly', () => {
|
||||
expect(_getAllFlags(null, null)).to.eql([])
|
||||
})
|
||||
it('should output list of keys if passed single object', () => {
|
||||
expect(_getAllFlags({ flagStorage: { a: 1, b: 1, c: 1 } }, null)).to.eql(['a', 'b', 'c'])
|
||||
})
|
||||
it('should union keys of both objects', () => {
|
||||
expect(_getAllFlags({ flagStorage: { a: 1, b: 1, c: 1 } }, { flagStorage: { c: 1, d: 1 } })).to.eql(['a', 'b', 'c', 'd'])
|
||||
})
|
||||
})
|
||||
|
||||
describe('_mergeFlags', () => {
|
||||
it('should handle merge two flag sets correctly picking higher numbers', () => {
|
||||
expect(
|
||||
_mergeFlags(
|
||||
{ flagStorage: { a: 0, b: 3 } },
|
||||
{ flagStorage: { b: 1, c: 4, d: 9 } },
|
||||
['a', 'b', 'c', 'd'])
|
||||
).to.eql({ a: 0, b: 3, c: 4, d: 9 })
|
||||
})
|
||||
})
|
||||
|
||||
describe('_resetFlags', () => {
|
||||
it('should reset all known flags to 0 when reset flag is set to > 0 and < 9000', () => {
|
||||
const totalFlags = { a: 0, b: 3, reset: 1 }
|
||||
|
||||
expect(_resetFlags(totalFlags)).to.eql({ a: 0, b: 0, reset: 0 })
|
||||
})
|
||||
it('should trim all flags to known when reset is set to 1000', () => {
|
||||
const totalFlags = { a: 0, b: 3, c: 33, reset: COMMAND_TRIM_FLAGS }
|
||||
|
||||
expect(_resetFlags(totalFlags, { a: 0, b: 0, reset: 0 })).to.eql({ a: 0, b: 3, reset: 0 })
|
||||
})
|
||||
it('should trim all flags to known and reset when reset is set to 1001', () => {
|
||||
const totalFlags = { a: 0, b: 3, c: 33, reset: COMMAND_TRIM_FLAGS_AND_RESET }
|
||||
|
||||
expect(_resetFlags(totalFlags, { a: 0, b: 0, reset: 0 })).to.eql({ a: 0, b: 0, reset: 0 })
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
Loading…
Reference in new issue