Rewrite search view

This commit is contained in:
wvffle 2022-06-30 00:18:39 +00:00 committed by Georg Krause
parent f5bd906110
commit 9e1e2bfa18
5 changed files with 390 additions and 383 deletions

View File

@ -28,10 +28,10 @@
"fomantic-ui-css": "2.8.8",
"howler": "2.2.3",
"js-logger": "1.6.1",
"moment": "2.29.3",
"qs": "6.10.5",
"pinia": "^2.0.13",
"lodash-es": "4.17.21",
"moment": "2.29.3",
"pinia": "^2.0.13",
"qs": "6.11.0",
"register-service-worker": "1.7.2",
"sanitize-html": "2.7.0",
"sass": "1.53.0",
@ -41,7 +41,7 @@
"vue-gettext": "2.1.12",
"vue-plyr": "7.0.0",
"vue-router": "4.0.16",
"vue-tsc": "0.38.1",
"vue-tsc": "0.38.2",
"vue-upload-component": "3.1.2",
"vue3-gettext": "2.3.0",
"vue3-lazyload": "0.3.4",
@ -55,7 +55,7 @@
"@types/jquery": "3.5.14",
"@types/lodash-es": "4.17.6",
"@types/qs": "6.9.7",
"@typescript-eslint/eslint-plugin": "5.29.0",
"@typescript-eslint/eslint-plugin": "5.30.0",
"@vitejs/plugin-vue": "2.3.3",
"@vue/compiler-sfc": "3.2.37",
"@vue/eslint-config-standard": "7.0.0",
@ -70,12 +70,12 @@
"eslint-plugin-node": "11.1.0",
"eslint-plugin-promise": "6.0.0",
"eslint-plugin-vue": "9.1.1",
"jest-cli": "28.1.1",
"jest-cli": "28.1.2",
"moxios": "0.4.0",
"sinon": "14.0.0",
"ts-jest": "28.0.5",
"typescript": "4.7.4",
"vite": "2.9.12",
"vite": "2.9.13",
"vite-plugin-pwa": "0.12.0",
"vue-jest": "3.0.7",
"workbox-core": "6.5.3",

View File

@ -1,3 +1,69 @@
<script setup lang="ts">
import type { ObjectId, RadioConfig } from '~/store/radios'
import { useGettext } from 'vue3-gettext'
import { useStore } from '~/store'
import { computed } from 'vue'
interface Props {
customRadioId?: number | null
type?: string
clientOnly?: boolean
objectId?: ObjectId | null
radioConfig: RadioConfig
}
const props = withDefaults(defineProps<Props>(), {
customRadioId: null,
type: '',
clientOnly: false,
objectId: null
})
const store = useStore()
const running = computed(() => {
if (!store.state.radios.running) {
return false
}
return store.state.radios.current?.type === props.type
&& store.state.radios.current?.customRadioId === props.customRadioId
&& store.state.radios.current?.objectId.fullUsername === props.objectId?.fullUsername
})
const { $pgettext } = useGettext()
const buttonLabel = computed(() => {
switch (props.radioConfig.type) {
case 'tag':
return running.value
? $pgettext('*/Player/Button.Label/Short, Verb', 'Stop tags radio')
: $pgettext('*/Player/Button.Label/Short, Verb', 'Start tags radio')
case 'artist':
return running.value
? $pgettext('*/Player/Button.Label/Short, Verb', 'Stop artists radio')
: $pgettext('*/Player/Button.Label/Short, Verb', 'Start artists radio')
default:
return running.value
? $pgettext('*/Player/Button.Label/Short, Verb', 'Stop radio')
: $pgettext('*/Queue/Button.Label/Short, Verb', 'Play radio')
}
})
const toggleRadio = () => {
if (running.value) {
return store.dispatch('radios/stop')
}
return store.dispatch('radios/start', {
type: props.type,
objectId: props.objectId,
customRadioId: props.customRadioId,
clientOnly: props.clientOnly,
config: props.radioConfig
})
}
</script>
<template>
<button
:class="['ui', 'primary', {'inverted': running}, 'icon', 'labeled', 'button']"
@ -10,62 +76,3 @@
{{ buttonLabel }}
</button>
</template>
<script>
import { isEqual } from 'lodash-es'
export default {
props: {
customRadioId: { type: Number, required: false, default: null },
type: { type: String, required: false, default: '' },
clientOnly: { type: Boolean, default: false },
objectId: { type: [String, Number, Object], default: null },
config: { type: [Array, Object], required: false, default: null }
},
computed: {
running () {
const state = this.$store.state.radios
const current = state.current
if (!state.running) {
return false
} else {
return current.type === this.type && isEqual(current.objectId, this.objectId) && current.customRadioId === this.customRadioId
}
},
label () {
return this.config?.[0]?.type ?? null
},
buttonLabel () {
switch (this.label) {
case 'tag':
return this.running
? this.$pgettext('*/Player/Button.Label/Short, Verb', 'Stop tags radio')
: this.$pgettext('*/Player/Button.Label/Short, Verb', 'Start tags radio')
case 'artist':
return this.running
? this.$pgettext('*/Player/Button.Label/Short, Verb', 'Stop artists radio')
: this.$pgettext('*/Player/Button.Label/Short, Verb', 'Start artists radio')
default:
return this.running
? this.$pgettext('*/Player/Button.Label/Short, Verb', 'Stop radio')
: this.$pgettext('*/Queue/Button.Label/Short, Verb', 'Play radio')
}
}
},
methods: {
toggleRadio () {
if (this.running) {
this.$store.dispatch('radios/stop')
} else {
this.$store.dispatch('radios/start', {
type: this.type,
objectId: this.objectId,
customRadioId: this.customRadioId,
clientOnly: this.clientOnly,
config: this.config
})
}
}
}
}
</script>

View File

@ -9,16 +9,24 @@ export interface State {
running: boolean
}
export interface ObjectId {
username: string
fullUsername: string
}
export interface CurrentRadio {
clientOnly: boolean
session: null
type: 'account'
objectId: {
username: string
fullUsername: string
}
// TODO (wvffle): Find correct type
customRadioId: unknown
config: RadioConfig
objectId: ObjectId
}
// TODO (wvffle): Find correct type
export type RadioConfig = { type: 'tag', names: string[] } | { type: 'artist', ids: string[] }
export interface PopulateQueuePayload {
current: CurrentRadio
playNow: boolean
@ -79,12 +87,14 @@ const store: Module<State, RootState> = {
custom_radio: customRadioId,
config: config
}
if (clientOnly) {
commit('current', { type, objectId, customRadioId, clientOnly, config })
commit('running', true)
dispatch('populateQueue', true)
return
}
return axios.post('radios/sessions/', params).then((response) => {
logger.info('Successfully started radio ', type)
commit('current', { type, objectId, session: response.data.id, customRadioId })

View File

@ -1,3 +1,221 @@
<script setup lang="ts">
import type { RadioConfig } from '~/store/radios'
import RemoteSearchForm from '~/components/RemoteSearchForm.vue'
import ArtistCard from '~/components/audio/artist/Card.vue'
import AlbumCard from '~/components/audio/album/Card.vue'
import TrackTable from '~/components/audio/track/Table.vue'
import Pagination from '~/components/vui/Pagination.vue'
import PlaylistCardList from '~/components/playlists/CardList.vue'
import RadioCard from '~/components/radios/Card.vue'
import TagsList from '~/components/tags/List.vue'
import { ref, reactive, computed, watch } from 'vue'
import { useRouter, onBeforeRouteUpdate } from 'vue-router'
import { useGettext } from 'vue3-gettext'
import axios from 'axios'
type QueryType = 'artists' | 'albums' | 'tracks' | 'playlists' | 'tags' | 'radios' | 'podcasts' | 'series' | 'rss'
interface Props {
initialId?: string
initialType?: QueryType
initialQuery?: string
initialPage?: number
}
const props = withDefaults(defineProps<Props>(), {
initialId: '',
initialType: 'artists',
initialQuery: '',
initialPage: 1
})
const query = ref(props.initialQuery)
const type = ref(props.initialType)
const page = ref(props.initialPage)
type ResponseType = { count: number, results: any[] }
const results = reactive({
artists: null,
albums: null,
tracks: null,
playlists: null,
radios: null,
tags: null,
podcasts: null,
series: null
} as Record<QueryType, null | ResponseType>)
const paginateBy = ref(25)
const { $pgettext } = useGettext()
// TODO (wvffle): Check if can rename to Category
interface SearchType {
id: QueryType
label: string
includeChannels?: boolean
contentCategory?: string
endpoint?: string
}
const types = computed(() => [
{
id: 'artists',
label: $pgettext('*/*/*/Noun', 'Artists'),
includeChannels: true,
contentCategory: 'music'
},
{
id: 'albums',
label: $pgettext('*/*/*', 'Albums'),
includeChannels: true,
contentCategory: 'music'
},
{
id: 'tracks',
label: $pgettext('*/*/*', 'Tracks')
},
{
id: 'playlists',
label: $pgettext('*/*/*', 'Playlists')
},
{
id: 'radios',
label: $pgettext('*/*/*', 'Radios'),
endpoint: 'radios/radios'
},
{
id: 'tags',
label: $pgettext('*/*/*', 'Tags')
},
{
id: 'podcasts',
label: $pgettext('*/*/*', 'Podcasts'),
endpoint: '/artists',
contentCategory: 'podcast',
includeChannels: true
},
{
id: 'series',
label: $pgettext('*/*/*', 'Series'),
endpoint: '/albums',
includeChannels: true,
contentCategory: 'podcast'
}
] as SearchType[])
const currentType = computed(() => types.value.find(({ id }) => id === type.value)!)
const axiosParams = computed(() => {
const params = new URLSearchParams({
q: query.value,
page: page.value as unknown as string,
page_size: paginateBy.value as unknown as string
})
if (currentType.value.contentCategory) params.append('content_category', currentType.value.contentCategory)
if (currentType.value.includeChannels) params.append('include_channels', currentType.value.includeChannels as unknown as string)
return params
})
const currentResults = computed(() => results[currentType.value.id ?? 'artists'])
const router = useRouter()
const updateQueryString = () => router.replace({
query: {
q: query.value,
page: page.value,
type: type.value
}
})
// TODO (wvffle): Debounce all `fetchData` functions
const isLoading = ref(false)
const search = async () => {
if (!query.value) {
for (const type of types.value) {
results[type.id] = null
}
return
}
isLoading.value = true
const response = await axios.get(currentType.value.endpoint ?? currentType.value.id, {
params: axiosParams.value
})
results[currentType.value.id] = response.data
isLoading.value = false
// TODO (wvffle): Resolve race condition
for (const type of types.value) {
if (type.id !== currentType.value.id) {
axios.get(type.endpoint ?? type.id, {
params: {
q: query.value,
page_size: 1,
content_category: type.contentCategory,
include_channels: type.includeChannels
}
}).then(response => {
results[type.id] = response.data
})
}
}
}
watch(type, () => (page.value = 1))
watch(page, updateQueryString)
onBeforeRouteUpdate(search)
// TODO: (wvffle): Check if it's needed
// watch: {
// '$route.query.q': async function (v) {
// this.query = v
// }
// },
const labels = computed(() => ({
title: props.initialId
? (
type.value === 'rss'
? $pgettext('Head/Fetch/Title', 'Subscribe to a podcast RSS feed')
: $pgettext('Head/Fetch/Title', 'Search a remote object')
)
: $pgettext('Content/Search/Input.Label/Noun', 'Search'),
submitSearch: $pgettext('Content/Search/Button.Label/Verb', 'Submit Search Query')
}))
const radioConfig = computed(() => {
const results = Object.values(currentResults.value?.results ?? {})
if (results.length) {
if (currentType.value.id === 'tags') {
return {
type: 'tag',
names: results.map(({ name }) => name)
} as RadioConfig
}
if (currentType.value.id === 'artists') {
return {
type: 'artist',
ids: results.map(({ id }) => id)
} as RadioConfig
}
// TODO (wvffle): Use logger
console.info('This type is not yet supported for radio')
}
return null
})
</script>
<template>
<main
v-title="labels.title"
@ -51,10 +269,10 @@
</div>
<div class="column">
<radio-button
v-if="currentResults && currentConfigValidated && ( type === 'tags' || type === 'artists' ) "
v-if="radioConfig"
class="ui right floated medium button"
type="custom_multiple"
:config="currentConfig"
:radio-config="radioConfig"
/>
</div>
</div>
@ -147,231 +365,3 @@
</section>
</main>
</template>
<script>
import RemoteSearchForm from '~/components/RemoteSearchForm.vue'
import ArtistCard from '~/components/audio/artist/Card.vue'
import AlbumCard from '~/components/audio/album/Card.vue'
import TrackTable from '~/components/audio/track/Table.vue'
import Pagination from '~/components/vui/Pagination.vue'
import PlaylistCardList from '~/components/playlists/CardList.vue'
import RadioCard from '~/components/radios/Card.vue'
import TagsList from '~/components/tags/List.vue'
import axios from 'axios'
export default {
components: {
RemoteSearchForm,
ArtistCard,
AlbumCard,
TrackTable,
Pagination,
PlaylistCardList,
RadioCard,
RadioButton,
TagsList
},
props: {
initialId: { type: String, required: false, default: '' },
initialType: { type: String, required: false, default: '' },
initialQuery: { type: String, required: false, default: '' },
initialPage: { type: Number, required: false, default: 0 }
},
data () {
return {
query: this.initialQuery,
type: this.initialType,
page: this.initialPage,
results: {
artists: null,
albums: null,
tracks: null,
playlists: null,
radios: null,
tags: null,
podcasts: null,
series: null
},
isLoading: false,
paginateBy: 25,
config: null
}
},
computed: {
labels () {
const submitSearch = this.$pgettext('Content/Search/Button.Label/Verb', 'Submit Search Query')
let title = this.$pgettext('Content/Search/Input.Label/Noun', 'Search')
if (this.initialId) {
title = this.$pgettext('Head/Fetch/Title', 'Search a remote object')
if (this.type === 'rss') {
title = this.$pgettext('Head/Fetch/Title', 'Subscribe to a podcast RSS feed')
}
}
return {
title,
submitSearch
}
},
axiosParams () {
const params = new URLSearchParams()
params.append('q', this.query)
params.append('page', this.page)
params.append('page_size', this.paginateBy)
if (this.currentType.contentCategory !== undefined) { params.append('content_category', this.currentType.contentCategory) }
if (this.currentType.includeChannels !== undefined) { params.append('include_channels', this.currentType.includeChannels) }
return params
},
types () {
return [
{
id: 'artists',
label: this.$pgettext('*/*/*/Noun', 'Artists'),
includeChannels: true,
contentCategory: 'music'
},
{
id: 'albums',
label: this.$pgettext('*/*/*', 'Albums'),
includeChannels: true,
contentCategory: 'music'
},
{
id: 'tracks',
label: this.$pgettext('*/*/*', 'Tracks')
},
{
id: 'playlists',
label: this.$pgettext('*/*/*', 'Playlists')
},
{
id: 'radios',
label: this.$pgettext('*/*/*', 'Radios'),
endpoint: 'radios/radios'
},
{
id: 'tags',
label: this.$pgettext('*/*/*', 'Tags')
},
{
id: 'podcasts',
label: this.$pgettext('*/*/*', 'Podcasts'),
endpoint: '/artists',
contentCategory: 'podcast',
includeChannels: true
},
{
id: 'series',
label: this.$pgettext('*/*/*', 'Series'),
endpoint: '/albums',
includeChannels: true,
contentCategory: 'podcast'
}
]
},
currentType () {
return this.types.filter(t => {
return t.id === this.type
})[0]
},
currentResults () {
return this.results[this.currentType.id]
},
currentConfig () {
const resultDict = this.currentResults.results
return this.generateConfig(this.currentType.id, resultDict)
},
currentConfigValidated () {
const configValidate = this.currentConfig
const array = configValidate[0][Object.keys(configValidate[0])[1]]
return array.length >= 1
}
},
watch: {
async type () {
this.page = 1
this.updateQueryString()
await this.search()
},
async page () {
this.updateQueryString()
await this.search()
},
'$route.query.q': async function (v) {
this.query = v
this.updateQueryString()
await this.search()
}
},
created () {
this.search()
},
methods: {
async search () {
this.updateQueryString()
if (!this.query) {
this.types.forEach(t => {
this.results[t.id] = null
})
return
}
this.isLoading = true
const response = await axios.get(
this.currentType.endpoint || this.currentType.id,
{ params: this.axiosParams }
)
this.results[this.currentType.id] = response.data
this.isLoading = false
this.types.forEach(t => {
if (t.id !== this.currentType.id) {
axios.get(t.endpoint || t.id, {
params: {
q: this.query,
page_size: 1,
content_category: t.contentCategory,
include_channels: t.includeChannels
}
}).then(response => {
this.results[t.id] = response.data
})
}
})
},
updateQueryString: function () {
history.pushState(
{},
null,
this.$route.path + '?' + new URLSearchParams(
{
q: this.query,
page: this.page,
type: this.type
}).toString()
)
},
generateConfig: function (type, resultDict) {
const obj = {
type: type.slice(0, -1)
}
switch (type) {
case 'tags':
obj.names = this.generateTagConfig(resultDict, type)
break
case 'artists':
obj.ids = this.generateArtistConfig(resultDict, type)
break
default:
console.info('This type is not yet supported for radio')
obj.ids = 0
}
return [obj]
},
generateTagConfig: function (resultDict, type) {
return Object.values(resultDict).map(({ name }) => name)
},
generateArtistConfig: function (resultDict, type) {
return Object.values(resultDict).map(({ id }) => id)
}
}
}
</script>

View File

@ -1000,7 +1000,7 @@
jest-util "^28.1.3"
slash "^3.0.0"
"@jest/core@^28.1.1":
"@jest/core@^28.1.2":
version "28.1.3"
resolved "https://registry.yarnpkg.com/@jest/core/-/core-28.1.3.tgz#0ebf2bd39840f1233cd5f2d1e6fc8b71bd5a1ac7"
integrity sha512-CIKBrlaKOzA7YG19BEqCw3SLIsEwjZkeJzf5bdooVnW4bH5cktqe3JX+G2YV1aK5vP8N9na1IGWFzYaTp6k6NA==
@ -1518,14 +1518,14 @@
dependencies:
"@types/yargs-parser" "*"
"@typescript-eslint/eslint-plugin@5.29.0":
version "5.29.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.29.0.tgz#c67794d2b0fd0b4a47f50266088acdc52a08aab6"
integrity sha512-kgTsISt9pM53yRFQmLZ4npj99yGl3x3Pl7z4eA66OuTzAGC4bQB5H5fuLwPnqTKU3yyrrg4MIhjF17UYnL4c0w==
"@typescript-eslint/eslint-plugin@5.30.0":
version "5.30.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.30.0.tgz#524a11e15c09701733033c96943ecf33f55d9ca1"
integrity sha512-lvhRJ2pGe2V9MEU46ELTdiHgiAFZPKtLhiU5wlnaYpMc2+c1R8fh8i80ZAa665drvjHKUJyRRGg3gEm1If54ow==
dependencies:
"@typescript-eslint/scope-manager" "5.29.0"
"@typescript-eslint/type-utils" "5.29.0"
"@typescript-eslint/utils" "5.29.0"
"@typescript-eslint/scope-manager" "5.30.0"
"@typescript-eslint/type-utils" "5.30.0"
"@typescript-eslint/utils" "5.30.0"
debug "^4.3.4"
functional-red-black-tree "^1.0.1"
ignore "^5.2.0"
@ -1558,13 +1558,13 @@
"@typescript-eslint/typescript-estree" "5.36.2"
debug "^4.3.4"
"@typescript-eslint/scope-manager@5.29.0":
version "5.29.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.29.0.tgz#2a6a32e3416cb133e9af8dcf54bf077a916aeed3"
integrity sha512-etbXUT0FygFi2ihcxDZjz21LtC+Eps9V2xVx09zFoN44RRHPrkMflidGMI+2dUs821zR1tDS6Oc9IXxIjOUZwA==
"@typescript-eslint/scope-manager@5.30.0":
version "5.30.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.30.0.tgz#bf585ee801ab4ad84db2f840174e171a6bb002c7"
integrity sha512-3TZxvlQcK5fhTBw5solQucWSJvonXf5yua5nx8OqK94hxdrT7/6W3/CS42MLd/f1BmlmmbGEgQcTHHCktUX5bQ==
dependencies:
"@typescript-eslint/types" "5.29.0"
"@typescript-eslint/visitor-keys" "5.29.0"
"@typescript-eslint/types" "5.30.0"
"@typescript-eslint/visitor-keys" "5.30.0"
"@typescript-eslint/scope-manager@5.36.2":
version "5.36.2"
@ -1574,12 +1574,12 @@
"@typescript-eslint/types" "5.36.2"
"@typescript-eslint/visitor-keys" "5.36.2"
"@typescript-eslint/type-utils@5.29.0":
version "5.29.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.29.0.tgz#241918001d164044020b37d26d5b9f4e37cc3d5d"
integrity sha512-JK6bAaaiJozbox3K220VRfCzLa9n0ib/J+FHIwnaV3Enw/TO267qe0pM1b1QrrEuy6xun374XEAsRlA86JJnyg==
"@typescript-eslint/type-utils@5.30.0":
version "5.30.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.30.0.tgz#98f3af926a5099153f092d4dad87148df21fbaae"
integrity sha512-GF8JZbZqSS+azehzlv/lmQQ3EU3VfWYzCczdZjJRxSEeXDQkqFhCBgFhallLDbPwQOEQ4MHpiPfkjKk7zlmeNg==
dependencies:
"@typescript-eslint/utils" "5.29.0"
"@typescript-eslint/utils" "5.30.0"
debug "^4.3.4"
tsutils "^3.21.0"
@ -1593,23 +1593,23 @@
debug "^4.3.4"
tsutils "^3.21.0"
"@typescript-eslint/types@5.29.0":
version "5.29.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.29.0.tgz#7861d3d288c031703b2d97bc113696b4d8c19aab"
integrity sha512-X99VbqvAXOMdVyfFmksMy3u8p8yoRGITgU1joBJPzeYa0rhdf5ok9S56/itRoUSh99fiDoMtarSIJXo7H/SnOg==
"@typescript-eslint/types@5.30.0":
version "5.30.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.30.0.tgz#db7d81d585a3da3801432a9c1d2fafbff125e110"
integrity sha512-vfqcBrsRNWw/LBXyncMF/KrUTYYzzygCSsVqlZ1qGu1QtGs6vMkt3US0VNSQ05grXi5Yadp3qv5XZdYLjpp8ag==
"@typescript-eslint/types@5.36.2":
version "5.36.2"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.36.2.tgz#a5066e500ebcfcee36694186ccc57b955c05faf9"
integrity sha512-9OJSvvwuF1L5eS2EQgFUbECb99F0mwq501w0H0EkYULkhFa19Qq7WFbycdw1PexAc929asupbZcgjVIe6OK/XQ==
"@typescript-eslint/typescript-estree@5.29.0":
version "5.29.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.29.0.tgz#e83d19aa7fd2e74616aab2f25dfbe4de4f0b5577"
integrity sha512-mQvSUJ/JjGBdvo+1LwC+GY2XmSYjK1nAaVw2emp/E61wEVYEyibRHCqm1I1vEKbXCpUKuW4G7u9ZCaZhJbLoNQ==
"@typescript-eslint/typescript-estree@5.30.0":
version "5.30.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.0.tgz#4565ee8a6d2ac368996e20b2344ea0eab1a8f0bb"
integrity sha512-hDEawogreZB4n1zoqcrrtg/wPyyiCxmhPLpZ6kmWfKF5M5G0clRLaEexpuWr31fZ42F96SlD/5xCt1bT5Qm4Nw==
dependencies:
"@typescript-eslint/types" "5.29.0"
"@typescript-eslint/visitor-keys" "5.29.0"
"@typescript-eslint/types" "5.30.0"
"@typescript-eslint/visitor-keys" "5.30.0"
debug "^4.3.4"
globby "^11.1.0"
is-glob "^4.0.3"
@ -1629,15 +1629,15 @@
semver "^7.3.7"
tsutils "^3.21.0"
"@typescript-eslint/utils@5.29.0":
version "5.29.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.29.0.tgz#775046effd5019667bd086bcf326acbe32cd0082"
integrity sha512-3Eos6uP1nyLOBayc/VUdKZikV90HahXE5Dx9L5YlSd/7ylQPXhLk1BYb29SDgnBnTp+jmSZUU0QxUiyHgW4p7A==
"@typescript-eslint/utils@5.30.0":
version "5.30.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.30.0.tgz#1dac771fead5eab40d31860716de219356f5f754"
integrity sha512-0bIgOgZflLKIcZsWvfklsaQTM3ZUbmtH0rJ1hKyV3raoUYyeZwcjQ8ZUJTzS7KnhNcsVT1Rxs7zeeMHEhGlltw==
dependencies:
"@types/json-schema" "^7.0.9"
"@typescript-eslint/scope-manager" "5.29.0"
"@typescript-eslint/types" "5.29.0"
"@typescript-eslint/typescript-estree" "5.29.0"
"@typescript-eslint/scope-manager" "5.30.0"
"@typescript-eslint/types" "5.30.0"
"@typescript-eslint/typescript-estree" "5.30.0"
eslint-scope "^5.1.1"
eslint-utils "^3.0.0"
@ -1653,12 +1653,12 @@
eslint-scope "^5.1.1"
eslint-utils "^3.0.0"
"@typescript-eslint/visitor-keys@5.29.0":
version "5.29.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.29.0.tgz#7a4749fa7ef5160c44a451bf060ac1dc6dfb77ee"
integrity sha512-Hpb/mCWsjILvikMQoZIE3voc9wtQcS0A9FUw3h8bhr9UxBdtI/tw1ZDZUOXHXLOVMedKCH5NxyzATwnU78bWCQ==
"@typescript-eslint/visitor-keys@5.30.0":
version "5.30.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.0.tgz#07721d23daca2ec4c2da7f1e660d41cd78bacac3"
integrity sha512-6WcIeRk2DQ3pHKxU1Ni0qMXJkjO/zLjBymlYBy/53qxe7yjEFSvzKLDToJjURUhSl2Fzhkl4SMXQoETauF74cw==
dependencies:
"@typescript-eslint/types" "5.29.0"
"@typescript-eslint/types" "5.30.0"
eslint-visitor-keys "^3.3.0"
"@typescript-eslint/visitor-keys@5.36.2":
@ -1674,37 +1674,37 @@
resolved "https://registry.yarnpkg.com/@vitejs/plugin-vue/-/plugin-vue-2.3.3.tgz#fbf80cc039b82ac21a1acb0f0478de8f61fbf600"
integrity sha512-SmQLDyhz+6lGJhPELsBdzXGc+AcaT8stgkbiTFGpXPe8Tl1tJaBw1A6pxDqDuRsVkD8uscrkx3hA7QDOoKYtyw==
"@volar/code-gen@0.38.1":
version "0.38.1"
resolved "https://registry.yarnpkg.com/@volar/code-gen/-/code-gen-0.38.1.tgz#0f2957057c92a7f209b5c333d68c80e2a09adf23"
integrity sha512-QnEJfCPhPqzhQY/iN7euGoUWphyv4TmN1xK/HEpnXwgqgvIyLk/Ih3rvAFqlP6I5fTaCu6TGf9kZmjw9AlEeMA==
"@volar/code-gen@0.38.2":
version "0.38.2"
resolved "https://registry.yarnpkg.com/@volar/code-gen/-/code-gen-0.38.2.tgz#1eedaba3a12b9d1954dd99d6745f3f2ede0aca58"
integrity sha512-H81I6d7rZB7teqL+zhK/Xz1v0/kKkUwkB0Aq6b4+BTCqcJeiZkoWxd0gFhrhWTnUoqiM83lhoTGo2vkvx5YagQ==
dependencies:
"@volar/source-map" "0.38.1"
"@volar/source-map" "0.38.2"
"@volar/source-map@0.38.1":
version "0.38.1"
resolved "https://registry.yarnpkg.com/@volar/source-map/-/source-map-0.38.1.tgz#2ddc906e29b488ab48687872ff33196e4bddf05f"
integrity sha512-1DoB8BYTle81DdLChnurYteN208qvsfz4IgwjH6T2YcnBtUvtscxMOwg0bfQJskfoLrJ5gESBvEpU8tWsEVyrQ==
"@volar/source-map@0.38.2":
version "0.38.2"
resolved "https://registry.yarnpkg.com/@volar/source-map/-/source-map-0.38.2.tgz#72ccaaa224646da69097abe8360391acd7f042b9"
integrity sha512-DWcYbYt9SPwk0r4VmXk1F0v4X5+hCqH1JRkAWSeJymQyXCQ2OQDEbY2PF12a7y2qn4FUBD2gOba2TynAqI8ZFQ==
"@volar/vue-code-gen@0.38.1":
version "0.38.1"
resolved "https://registry.yarnpkg.com/@volar/vue-code-gen/-/vue-code-gen-0.38.1.tgz#be6854c06a529e9e4357b64a06aad5e051b390d6"
integrity sha512-tgJ2uySZKZqiq6HFKmjeVmUhJttd2LMhqtlqSukdqGx2Xw/OWnL0Di7+q6AScC6tu9/Bw570HKMHbhhLIrQm2Q==
"@volar/vue-code-gen@0.38.2":
version "0.38.2"
resolved "https://registry.yarnpkg.com/@volar/vue-code-gen/-/vue-code-gen-0.38.2.tgz#10b467936cb79edb21e6f91ed25ec3fbe055a4cd"
integrity sha512-whLunD6phSGWBUHZKdTxeglrpzQu26ii8CRVapFdjfyMaVhQ7ESNeIAhkTVyg2ovOPc0PiDYPQEPzfWAADIWog==
dependencies:
"@volar/code-gen" "0.38.1"
"@volar/source-map" "0.38.1"
"@volar/code-gen" "0.38.2"
"@volar/source-map" "0.38.2"
"@vue/compiler-core" "^3.2.37"
"@vue/compiler-dom" "^3.2.37"
"@vue/shared" "^3.2.37"
"@volar/vue-typescript@0.38.1":
version "0.38.1"
resolved "https://registry.yarnpkg.com/@volar/vue-typescript/-/vue-typescript-0.38.1.tgz#edc5739c6e6193a5d5779758c86026acb06cbc24"
integrity sha512-D4bTuiJ2WiRppJuZ34r3pstFLTwpweke3haszJwp0ioUI9BqKgh02TFqM+qhPezH6fF0NrWCxXMMQVxZL6d7gA==
"@volar/vue-typescript@0.38.2":
version "0.38.2"
resolved "https://registry.yarnpkg.com/@volar/vue-typescript/-/vue-typescript-0.38.2.tgz#e9bf7d178755fe2619f43dda499ab1e2a6240a5b"
integrity sha512-5IKvSK2m5yUmH6iu/tNScVlvJGuiHawTfSmjxaMs+/tod25WeK37LEdf+pdKtlJ30bYTQmmkAuEfG01QvvBRGQ==
dependencies:
"@volar/code-gen" "0.38.1"
"@volar/source-map" "0.38.1"
"@volar/vue-code-gen" "0.38.1"
"@volar/code-gen" "0.38.2"
"@volar/source-map" "0.38.2"
"@volar/vue-code-gen" "0.38.2"
"@vue/compiler-sfc" "^3.2.37"
"@vue/reactivity" "^3.2.37"
@ -4227,25 +4227,25 @@ jest-circus@^28.1.3:
slash "^3.0.0"
stack-utils "^2.0.3"
jest-cli@28.1.1:
version "28.1.1"
resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-28.1.1.tgz#23ddfde8940e1818585ae4a568877b33b0e51cfe"
integrity sha512-+sUfVbJqb1OjBZ0OdBbI6OWfYM1i7bSfzYy6gze1F1w3OKWq8ZTEKkZ8a7ZQPq6G/G1qMh/uKqpdWhgl11NFQQ==
jest-cli@28.1.2:
version "28.1.2"
resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-28.1.2.tgz#b89012e5bad14135e71b1628b85475d3773a1bbc"
integrity sha512-l6eoi5Do/IJUXAFL9qRmDiFpBeEJAnjJb1dcd9i/VWfVWbp3mJhuH50dNtX67Ali4Ecvt4eBkWb4hXhPHkAZTw==
dependencies:
"@jest/core" "^28.1.1"
"@jest/core" "^28.1.2"
"@jest/test-result" "^28.1.1"
"@jest/types" "^28.1.1"
chalk "^4.0.0"
exit "^0.1.2"
graceful-fs "^4.2.9"
import-local "^3.0.2"
jest-config "^28.1.1"
jest-config "^28.1.2"
jest-util "^28.1.1"
jest-validate "^28.1.1"
prompts "^2.0.1"
yargs "^17.3.1"
jest-config@^28.1.1, jest-config@^28.1.3:
jest-config@^28.1.2, jest-config@^28.1.3:
version "28.1.3"
resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-28.1.3.tgz#e315e1f73df3cac31447eed8b8740a477392ec60"
integrity sha512-MG3INjByJ0J4AsNBm7T3hsuxKQqFIiRo/AUqb1q9LRKI5UU6Aar9JHbr9Ivn1TVwfUD9KirRoM/T6u8XlcQPHQ==
@ -5379,10 +5379,10 @@ punycode@^2.1.0:
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
qs@6.10.5:
version "6.10.5"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.5.tgz#974715920a80ff6a262264acd2c7e6c2a53282b4"
integrity sha512-O5RlPh0VFtR78y79rgcgKK4wbAI0C5zGVLztOIdpWX6ep368q5Hv6XRxDvXuZ9q3C6v+e3n8UfZZJw7IIG27eQ==
qs@6.11.0:
version "6.11.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a"
integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==
dependencies:
side-channel "^1.0.4"
@ -6206,10 +6206,10 @@ vite-plugin-pwa@0.12.0:
workbox-build "^6.5.3"
workbox-window "^6.5.3"
vite@2.9.12:
version "2.9.12"
resolved "https://registry.yarnpkg.com/vite/-/vite-2.9.12.tgz#b1d636b0a8ac636afe9d83e3792d4895509a941b"
integrity sha512-suxC36dQo9Rq1qMB2qiRorNJtJAdxguu5TMvBHOc/F370KvqAe9t48vYp+/TbPKRNrMh/J55tOUmkuIqstZaew==
vite@2.9.13:
version "2.9.13"
resolved "https://registry.yarnpkg.com/vite/-/vite-2.9.13.tgz#859cb5d4c316c0d8c6ec9866045c0f7858ca6abc"
integrity sha512-AsOBAaT0AD7Mhe8DuK+/kE4aWYFMx/i0ZNi98hJclxb4e0OhQcZYUrvLjIaQ8e59Ui7txcvKMiJC1yftqpQoDw==
dependencies:
esbuild "^0.14.27"
postcss "^8.4.13"
@ -6293,12 +6293,12 @@ vue-template-es2015-compiler@^1.6.0:
resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz#1ee3bc9a16ecbf5118be334bb15f9c46f82f5825"
integrity sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==
vue-tsc@0.38.1:
version "0.38.1"
resolved "https://registry.yarnpkg.com/vue-tsc/-/vue-tsc-0.38.1.tgz#3520f7640b315f7aafd50ca2e9972af7c4c696e1"
integrity sha512-jwR4uwTkjsYhAW8o/BvnkeZsariNoi2Y53XSqWIbjtj7X9Laob+qwC2iVuQyRymYdqbbiqqX+CxfPWtwLACXfg==
vue-tsc@0.38.2:
version "0.38.2"
resolved "https://registry.yarnpkg.com/vue-tsc/-/vue-tsc-0.38.2.tgz#89175a6bb9a8b5724e84ab5d63dc5113041c5bfa"
integrity sha512-+OMmpw9BZC9khul3I1HGtWchv7BCiaM7NvfdilVAiOFkjnivIoaW6jJm6YPQJaEPouePtpkDUWovyzgNxWdDsw==
dependencies:
"@volar/vue-typescript" "0.38.1"
"@volar/vue-typescript" "0.38.2"
vue-upload-component@3.1.2:
version "3.1.2"