kopia lustrzana https://dev.funkwhale.audio/funkwhale/funkwhale
feat(front): Implement cache composable
rodzic
66d36f26a6
commit
81f1816ebb
|
@ -0,0 +1,20 @@
|
|||
import { expect, test } from 'vitest'
|
||||
import { useCache } from './useCache'
|
||||
|
||||
const wait = (ms: number) => new Promise(resolve => setTimeout(resolve, ms))
|
||||
const retention = 10
|
||||
|
||||
test('Cache sets value synchronously', () => {
|
||||
const cache = useCache({ retention })
|
||||
|
||||
cache('K').value = ('V')
|
||||
expect(cache('K').value).toBe('V')
|
||||
})
|
||||
|
||||
test('Cache forgets value after a set time', async () => {
|
||||
const cache = useCache({ retention })
|
||||
|
||||
cache('K').value = ('V')
|
||||
await wait(retention);
|
||||
expect(cache('K').value).toBe(undefined)
|
||||
})
|
|
@ -0,0 +1,24 @@
|
|||
import { computed, ref } from 'vue'
|
||||
|
||||
export const allCaches = ref<Map<unknown, unknown>[]>([]);
|
||||
|
||||
/**
|
||||
* Forgetful, reactive key-value store.
|
||||
*
|
||||
* @param retention: Milliseconds until a datum expires
|
||||
*/
|
||||
export const useCache = <K, V>({ retention }: { retention: number }) => {
|
||||
const cache = new Map<K, V>()
|
||||
|
||||
allCaches.value.push(cache);
|
||||
|
||||
return (key: K) => computed({
|
||||
get() {
|
||||
return cache.get(key)
|
||||
},
|
||||
set(value: V) {
|
||||
cache.set(key, value);
|
||||
setTimeout(() => cache.delete(key), retention)
|
||||
}
|
||||
})
|
||||
}
|
|
@ -1,16 +1,15 @@
|
|||
<script setup lang="ts">
|
||||
import { ref, onMounted, watch, computed, nextTick } from 'vue'
|
||||
import { ref, onMounted, watch, computed } from 'vue'
|
||||
import { useUploadsStore } from '../stores/upload'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useStore } from '~/store'
|
||||
import { useModal } from '~/ui/composables/useModal.ts'
|
||||
|
||||
import onKeyboardShortcut from '~/composables/onKeyboardShortcut'
|
||||
import { defineAsyncComponent } from 'vue'
|
||||
|
||||
import Logo from '~/components/Logo.vue'
|
||||
import Input from '~/components/ui/Input.vue'
|
||||
import Link from '~/components/ui/Link.vue'
|
||||
import UserMenu from './UserMenu.vue'
|
||||
|
||||
import Link from '~/components/ui/Link.vue'
|
||||
import Popover from '~/components/ui/Popover.vue'
|
||||
import PopoverItem from '~/components/ui/popover/PopoverItem.vue'
|
||||
import Button from '~/components/ui/Button.vue'
|
||||
|
@ -18,6 +17,11 @@ import Layout from '~/components/ui/Layout.vue'
|
|||
import Spacer from '~/components/ui/Spacer.vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
// simple usage
|
||||
const SearchModal = defineAsyncComponent({
|
||||
loader: () => import('~/ui/modals/Search.vue')
|
||||
})
|
||||
|
||||
const isCollapsed = ref(true)
|
||||
|
||||
const route = useRoute()
|
||||
|
@ -29,7 +33,6 @@ onMounted(() => {
|
|||
})
|
||||
|
||||
const { t } = useI18n()
|
||||
const { value: searchParameter } = useModal('search')
|
||||
|
||||
const store = useStore()
|
||||
const uploads = useUploadsStore()
|
||||
|
@ -37,19 +40,6 @@ const logoUrl = computed(() => store.state.auth.authenticated ? 'library.index'
|
|||
|
||||
const isOpen = ref(false)
|
||||
|
||||
// Search bar focus
|
||||
|
||||
const isFocusingSearch = ref<true | undefined>(undefined)
|
||||
const focusSearch = () => {
|
||||
isFocusingSearch.value = undefined
|
||||
nextTick(() => {
|
||||
isFocusingSearch.value = true
|
||||
})
|
||||
}
|
||||
onKeyboardShortcut(['shift', 'f'], focusSearch, true)
|
||||
onKeyboardShortcut(['ctrl', 'k'], focusSearch, true)
|
||||
onKeyboardShortcut(['/'], focusSearch, true)
|
||||
|
||||
// Admin notifications
|
||||
|
||||
const moderationNotifications = computed(() =>
|
||||
|
@ -209,16 +199,18 @@ const moderationNotifications = computed(() =>
|
|||
stack
|
||||
:class="[$style['menu-links'], isCollapsed && 'hide-on-mobile']"
|
||||
>
|
||||
<Input
|
||||
:key="isFocusingSearch ? 1 : 0"
|
||||
<!-- The search input will live next to the search modal. It needs -->
|
||||
<!-- <Input
|
||||
ref="globalSearchInput"
|
||||
v-model="searchParameter"
|
||||
:autofocus="isFocusingSearch"
|
||||
raised
|
||||
autocomplete="search"
|
||||
type="search"
|
||||
icon="bi-search"
|
||||
:placeholder="t('components.audio.SearchBar.placeholder.search')"
|
||||
/>
|
||||
/> -->
|
||||
|
||||
<SearchModal />
|
||||
|
||||
<Spacer />
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue