Migrate rest of inputs to new v-model

environments/review-front-deve-otr6gc/deployments/13401
Kasper Seweryn 2022-05-02 10:25:37 +02:00 zatwierdzone przez Georg Krause
rodzic bf009440ff
commit 561c1d868c
12 zmienionych plików z 191 dodań i 136 usunięć

Wyświetl plik

@ -14,7 +14,7 @@
<inline-search-bar
v-if="search"
v-model="query"
@search="albums = []; fetchData()"
@search="performSearch"
/>
<div class="ui hidden divider" />
<div class="ui app-cards cards">
@ -69,6 +69,14 @@ export default {
search: { type: Boolean, default: false },
limit: { type: Number, default: 12 }
},
setup () {
const performSearch = () => {
this.albums.length = 0
this.fetchData()
}
return { performSearch }
},
data () {
return {
albums: [],

Wyświetl plik

@ -10,7 +10,7 @@
<inline-search-bar
v-if="search"
v-model="query"
@search="objects = []; fetchData()"
@search="performSearch"
/>
<div class="ui hidden divider" />
<div class="ui five app-cards cards">
@ -64,6 +64,14 @@ export default {
header: { type: Boolean, default: true },
search: { type: Boolean, default: false }
},
setup () {
const performSearch = () => {
this.objects.length = 0
this.fetchData()
}
return { performSearch }
},
data () {
return {
objects: [],

Wyświetl plik

@ -4,11 +4,7 @@
<inline-search-bar
v-if="search"
v-model="query"
@search="
currentPage = 1;
additionalTracks = [];
fetchData('tracks/');
"
@search="performSearch"
/>
<!-- Add a header if needed -->
@ -191,6 +187,16 @@ export default {
paginateBy: { type: Number, required: false, default: 25 }
},
setup () {
const performSearch = () => {
this.currentPage = 1
this.additionalTracks.length = 0
this.fetchData('tracks/')
}
return { performSearch }
},
data () {
return {
fetchDataUrl: this.nextUrl,

Wyświetl plik

@ -1,3 +1,44 @@
<script setup lang="ts">
import axios from 'axios'
import { useVModel } from '@vueuse/core'
import { reactive, ref, watch } from 'vue'
import { Album, Channel } from '~/types'
interface Props {
modelValue: number
channel?: Channel
}
const props = withDefaults(defineProps<Props>(), {
channel: () => ({ id: '' })
})
const emit = defineEmits(['update:modelValue'])
const value = useVModel(props, 'modelValue', emit)
const albums = reactive<Album[]>([])
const isLoading = ref(false)
const fetchData = async () => {
albums.length = 0
if (!props.channel?.artist) return
isLoading.value = true
const response = await axios.get('albums/', {
params: {
artist: props.channel?.artist.id,
include_channels: 'true'
}
})
albums.push(...response.data.results)
isLoading.value = false
}
watch(() => props.channel, fetchData)
fetchData()
</script>
<template>
<div>
<label for="album-dropdown">
@ -14,9 +55,8 @@
</label>
<select
id="album-dropdown"
:value="value"
v-model="value"
class="ui search normal dropdown"
@input="$emit('input', $event.target.value)"
>
<option value="">
<translate translate-context="*/*/*">
@ -40,39 +80,3 @@
</select>
</div>
</template>
<script>
import axios from 'axios'
export default {
props: {
value: { type: Number, default: null },
channel: { type: Object, default: () => ({}) }
},
data () {
return {
albums: [],
isLoading: false
}
},
watch: {
async channel () {
await this.fetchData()
}
},
async created () {
await this.fetchData()
},
methods: {
async fetchData () {
this.albums = []
if (!this.channel || !this.channel.artist) {
return
}
this.isLoading = true
const response = await axios.get('albums/', { params: { artist: this.channel.artist.id, include_channels: 'true' } })
this.albums = response.data.results
this.isLoading = false
}
}
}
</script>

Wyświetl plik

@ -1,3 +1,49 @@
<script setup lang="ts">
import axios from 'axios'
import { useVModel } from '@vueuse/core'
import { computed, reactive, ref } from 'vue'
import { License } from '~/types'
interface Props {
modelValue: string
}
const props = defineProps<Props>()
const emit = defineEmits(['update:modelValue'])
const value = useVModel(props, 'modelValue', emit)
const availableLicenses = reactive<License[]>([])
const featuredLicensesIds = [
'cc0-1.0',
'cc-by-4.0',
'cc-by-sa-4.0',
'cc-by-nc-4.0',
'cc-by-nc-sa-4.0',
'cc-by-nc-nd-4.0',
'cc-by-nd-4.0'
]
const featuredLicenses = computed(() => {
return availableLicenses.filter(({ code }) => featuredLicensesIds.includes(code))
})
const currentLicense = computed(() => {
if (!value.value) return null
return availableLicenses.find(({ code }) => code === value.value) ?? null
})
const isLoading = ref(false)
const fetchLicenses = async () => {
isLoading.value = true
const response = await axios.get('licenses/')
availableLicenses.length = 0
availableLicenses.push(...response.data.results)
isLoading.value = false
}
fetchLicenses()
</script>
<template>
<div>
<label for="license-dropdown">
@ -5,9 +51,8 @@
</label>
<select
id="license-dropdown"
:value="value"
v-model="value"
class="ui search normal dropdown"
@input="$emit('input', $event.target.value)"
>
<option value="">
<translate translate-context="*/*/*">
@ -38,53 +83,3 @@
</p>
</div>
</template>
<script>
import axios from 'axios'
export default {
props: { value: { type: String, default: null } },
data () {
return {
availableLicenses: [],
featuredLicensesIds: [
'cc0-1.0',
'cc-by-4.0',
'cc-by-sa-4.0',
'cc-by-nc-4.0',
'cc-by-nc-sa-4.0',
'cc-by-nc-nd-4.0',
'cc-by-nd-4.0'
],
isLoading: false
}
},
computed: {
featuredLicenses () {
const self = this
return this.availableLicenses.filter((l) => {
return self.featuredLicensesIds.indexOf(l.code) > -1
})
},
currentLicense () {
const self = this
if (this.value) {
return this.availableLicenses.filter((l) => {
return l.code === self.value
})[0]
}
return null
}
},
async created () {
await this.fetchLicenses()
},
methods: {
async fetchLicenses () {
this.isLoading = true
const response = await axios.get('licenses/')
this.availableLicenses = response.data.results
this.isLoading = false
}
}
}
</script>

Wyświetl plik

@ -1,8 +1,9 @@
<script setup lang="ts">
import axios from 'axios'
import { useVModel } from '@vueuse/core'
import {reactive, ref, watch, watchEffect} from 'vue'
import { reactive, ref, watch } from 'vue'
import { BackendError } from '~/types'
import { useStore } from 'vuex'
interface Props {
modelValue: string
@ -86,6 +87,10 @@ watch(value, (to, from) => {
}
})
const store = useStore()
const getAttachmentUrl = (uuid: string) => {
return store.getters['instance/absoluteUrl'](`api/v1/attachments/${uuid}/proxy?next=medium_square_crop`)
}
</script>
<template>
@ -119,13 +124,13 @@ watch(value, (to, from) => {
v-if="value && value === initialValue"
alt=""
:class="['ui', imageClass, 'image']"
:src="$store.getters['instance/absoluteUrl'](`api/v1/attachments/${value}/proxy?next=medium_square_crop`)"
:src="getAttachmentUrl(value)"
>
<img
v-else-if="attachment"
alt=""
:class="['ui', imageClass, 'image']"
:src="$store.getters['instance/absoluteUrl'](`api/v1/attachments/${attachment.uuid}/proxy?next=medium_square_crop`)"
:src="getAttachmentUrl(attachment.uuid)"
>
<div
v-else
@ -141,7 +146,7 @@ watch(value, (to, from) => {
:id="attachmentId"
ref="input"
:name="name"
:required="required || null"
:required="required || undefined"
class="ui input"
type="file"
accept="image/png,image/jpeg"

Wyświetl plik

@ -1,8 +1,8 @@
<script setup lang="ts">
import { useClipboard, useVModel } from '@vueuse/core'
import { toRefs, useClipboard } from '@vueuse/core'
interface Props {
modelValue: string
value: string
buttonClasses?: string
id?: string
}
@ -12,9 +12,7 @@ const props = withDefaults(defineProps<Props>(), {
id: 'copy-input'
})
const emit = defineEmits(['update:modelValue'])
const value = useVModel(props, 'modelValue', emit)
const { value } = toRefs(props)
const { copy, isSupported: canCopy, copied } = useClipboard({ source: value, copiedDuring: 5000 })
</script>
@ -30,7 +28,7 @@ const { copy, isSupported: canCopy, copied } = useClipboard({ source: value, cop
</p>
<input
:id="id"
v-model="value"
:value="value"
:name="id"
type="text"
readonly

Wyświetl plik

@ -1,9 +1,38 @@
<script setup lang="ts">
import { useVModel } from '@vueuse/core'
import { computed } from 'vue'
import { useGettext } from 'vue3-gettext'
interface Props {
modelValue: string
placeholder?: string
}
const props = withDefaults(defineProps<Props>(), {
placeholder: ''
})
const emit = defineEmits(['update:modelValue', 'search'])
const value = useVModel(props, 'modelValue', emit)
const { $pgettext } = useGettext()
const labels = computed(() => ({
searchPlaceholder: $pgettext('Content/Search/Input.Placeholder', 'Search…'),
clear: $pgettext('Content/Library/Button.Label', 'Clear')
}))
const search = () => {
value.value = ''
emit('search', value.value)
}
</script>
<template>
<form
class="ui inline form"
@submit.stop.prevent="$emit('search', value)"
@submit.stop.prevent="emit('search', value)"
>
<div :class="['ui', 'action', {icon: isClearable}, 'input']">
<div :class="['ui', 'action', {icon: value}, 'input']">
<label
for="search-query"
class="hidden"
@ -12,17 +41,16 @@
</label>
<input
id="search-query"
v-model="value"
name="search-query"
type="text"
:placeholder="placeholder || labels.searchPlaceholder"
:value="value"
@input="$emit('input', $event.target.value)"
>
<i
v-if="isClearable"
v-if="value"
class="x link icon"
:title="labels.clear"
@click.stop.prevent="$emit('input', ''); $emit('search', value)"
@click.stop.prevent="search"
/>
<button
type="submit"
@ -33,22 +61,3 @@
</div>
</form>
</template>
<script>
export default {
props: {
value: { type: String, required: true },
placeholder: { type: String, required: false, default: '' }
},
computed: {
labels () {
return {
searchPlaceholder: this.$pgettext('Content/Search/Input.Placeholder', 'Search…'),
clear: this.$pgettext('Content/Library/Button.Label', 'Clear')
}
},
isClearable () {
return !!this.value
}
}
}
</script>

Wyświetl plik

@ -59,7 +59,7 @@ const allCategories = computed(() => {
<select
v-model="value"
class="ui dropdown"
:required="required || null"
:required="required || undefined"
>
<option
v-if="empty"

Wyświetl plik

@ -55,7 +55,7 @@ Promise.all(modules).finally(() => {
// TODO (wvffle): Replace $set and $delete with reactive()
// TODO (wvffle): Check for mixin merging: https://v3-migration.vuejs.org/breaking-changes/data-option.html#mixin-merge-behavior-change=
// TODO (wvffle): Use emits options: https://v3-migration.vuejs.org/breaking-changes/emits-option.html
// TODO (wvffle): Migrate to new v-model: https://v3-migration.vuejs.org/breaking-changes/v-model.html
// TODO (wvffle): Find all array watchers and make them deep
// TODO (wvffle): Migrate to <script setup>
// TODO (wvffle): Replace `from '(../)+` with `from '~/`
// TODO (wvffle): Remove `allowJs` from tsconfig.json

Wyświetl plik

@ -1,7 +1,7 @@
import type { App } from 'vue'
import type { Store } from 'vuex'
import { Router } from 'vue-router'
import {AxiosError} from "axios";
import { AxiosError } from 'axios'
declare global {
interface Window {
@ -29,20 +29,33 @@ export interface ThemeEntry {
}
// Track stuff
export type ContentCategory = 'podcast'
export interface Artist {
id: string
name: string
content_category: ContentCategory
}
export interface Album {
id: string
artist: Artist
tracks_count: number
title: string
}
export interface Track {
id: string
title: string
album?: Album
artist?: Artist
}
export interface Channel {
id: string
artist?: Artist
}
// API stuff
export interface APIErrorResponse {
[key: string]: APIErrorResponse | string[]
@ -122,3 +135,9 @@ export interface Actor {
is_local: boolean
domain: string
}
export interface License {
code: string
name: string
url: string
}

Wyświetl plik

@ -138,7 +138,10 @@
If you're using Mastodon or other fediverse applications, you can subscribe to this account:
</translate>
</p>
<copy-input :value="`@${object.actor.full_username}`" />
<copy-input
id="copy-tag"
:value="`@${object.actor.full_username}`"
/>
</template>
</div>
</div>