mirror of
https://github.com/VueTorrent/VueTorrent.git
synced 2025-02-18 00:02:02 +03:00
perf(overview): Disable canvas generation on large torrents (#947)
This commit is contained in:
parent
d1fda8155d
commit
b56caef1db
8 changed files with 132 additions and 71 deletions
|
@ -40,18 +40,31 @@
|
|||
<v-checkbox v-model="settings.openSideBarOnStart" hide-details class="ma-0 pa-0" :label="$t('modals.settings.vueTorrent.general.openSideBarOnStart')" />
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item class="mb-3">
|
||||
<v-list-item>
|
||||
<v-checkbox v-model="settings.showShutdownButton" hide-details class="ma-0 pa-0" :label="$t('modals.settings.vueTorrent.general.showShutdownButton')" />
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item class="mb-3">
|
||||
<v-text-field
|
||||
v-model="settings.refreshInterval"
|
||||
type="number"
|
||||
dense
|
||||
outlined
|
||||
:hint="$t('modals.settings.vueTorrent.general.refreshIntervalHint')"
|
||||
:label="$t('modals.settings.vueTorrent.general.refreshInterval')" />
|
||||
<v-list-item class="my-2">
|
||||
<v-row>
|
||||
<v-col cols="12" sm="6" class="mb-n4">
|
||||
<v-text-field
|
||||
v-model="settings.refreshInterval"
|
||||
type="number"
|
||||
dense
|
||||
outlined
|
||||
:hint="$t('modals.settings.vueTorrent.general.refreshIntervalHint')"
|
||||
:label="$t('modals.settings.vueTorrent.general.refreshInterval')" />
|
||||
</v-col>
|
||||
<v-col cols="12" sm="6">
|
||||
<v-text-field
|
||||
v-model="settings.torrentPieceCountRenderThreshold"
|
||||
type="number"
|
||||
dense
|
||||
outlined
|
||||
:hint="$t('modals.settings.vueTorrent.general.torrentPieceCountRenderThresholdHint')"
|
||||
:label="$t('modals.settings.vueTorrent.general.torrentPieceCountRenderThreshold')" />
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item class="mb-3">
|
||||
|
@ -140,14 +153,14 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import { mapState, mapGetters } from 'vuex'
|
||||
import { Qbit } from '@/services/qbit'
|
||||
import { LOCALES } from '@/lang/locales'
|
||||
import { General } from '@/mixins'
|
||||
import { TitleOptions } from '@/enums/vuetorrent'
|
||||
import {defineComponent} from 'vue'
|
||||
import {mapGetters, mapState} from 'vuex'
|
||||
import {Qbit} from '@/services/qbit'
|
||||
import {LOCALES} from '@/lang/locales'
|
||||
import {General} from '@/mixins'
|
||||
import {TitleOptions} from '@/enums/vuetorrent'
|
||||
import Ajv from 'ajv'
|
||||
import { StoreStateSchema } from '@/schemas'
|
||||
import {StoreStateSchema} from '@/schemas'
|
||||
import WebUISettings from '@/types/vuetorrent/WebUISettings'
|
||||
|
||||
export default defineComponent({
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<v-row>
|
||||
<v-col cols="12" md="6">
|
||||
<v-card flat>
|
||||
<v-card-title>{{ torrent.name }}</v-card-title>
|
||||
<v-card-title class="overflow-wrap">{{ torrent.name }}</v-card-title>
|
||||
<v-card-subtitle>
|
||||
<div v-for="commentPart in splitString(comment)" :key="commentPart">
|
||||
<a v-if="stringContainsUrl(commentPart)" target="_blank" :href="commentPart">{{ commentPart }}</a>
|
||||
|
@ -15,25 +15,31 @@
|
|||
<v-card-text>
|
||||
<v-row>
|
||||
<v-col cols="4" md="3">
|
||||
<v-progress-circular v-if="torrent?.state === TorrentState.METADATA" indeterminate :size="100" color="torrent-metadata">{{ $t('modals.detail.pageOverview.fetchingMetadata') }}</v-progress-circular>
|
||||
<v-progress-circular v-if="isFetchingMetadata" indeterminate :size="100" color="torrent-metadata">{{ $t('modals.detail.pageOverview.fetchingMetadata') }}</v-progress-circular>
|
||||
<v-progress-circular v-else-if="torrent?.progress === 100" :size="100" :width="15" :value="100" color="torrent-seeding">
|
||||
<v-icon color="torrent-seeding">{{ mdiCheck }}</v-icon>
|
||||
</v-progress-circular>
|
||||
<v-progress-circular v-else :rotate="-90" :size="100" :width="15" :value="torrent?.progress ?? 0" color="accent">{{ torrent.progress ?? 0 }} %</v-progress-circular>
|
||||
</v-col>
|
||||
<v-col cols="8" md="9" class="d-flex align-center justify-center flex-column">
|
||||
<div>
|
||||
<div v-if="shouldRenderPieceStates">
|
||||
<canvas id="pieceStates" width="0" height="1" />
|
||||
</div>
|
||||
<div>
|
||||
<div v-else-if="isFetchingMetadata">
|
||||
<span>
|
||||
{{ torrentPieceOwned }} / {{ torrentPieceCount }}
|
||||
({{ torrentPieceSize | getDataValue }} {{ torrentPieceSize | getDataUnit }})
|
||||
{{ $t('modals.detail.pageOverview.waitingForMetadata') }}
|
||||
</span>
|
||||
</div>
|
||||
<div v-else>
|
||||
<span>{{ $t('modals.detail.pageOverview.disabledCanvas') }}</span>
|
||||
</div>
|
||||
<div v-if="torrentPieceCount !== -1">
|
||||
<span>{{ torrentPieceOwned }} / {{ torrentPieceCount }} ({{ torrentPieceSize | getData }})</span>
|
||||
</div>
|
||||
<div>
|
||||
<v-icon>{{ mdiArrowDown }}</v-icon>
|
||||
{{ torrent?.dlspeed | networkSpeed }}
|
||||
|
||||
<v-icon>{{ mdiArrowUp }}</v-icon>
|
||||
{{ torrent?.upspeed | networkSpeed }}
|
||||
</div>
|
||||
|
@ -41,13 +47,15 @@
|
|||
</v-row>
|
||||
<v-row>
|
||||
<v-col cols="6">
|
||||
{{ $t('torrent.properties.save_path') }}:<br/>
|
||||
{{ torrent.savePath }}
|
||||
<div>{{ $t('torrent.properties.save_path') }}:</div>
|
||||
<div>{{ torrent.savePath }}</div>
|
||||
</v-col>
|
||||
<v-col cols="6">
|
||||
{{ $t('modals.detail.pageOverview.fileCount') }}:<br/>
|
||||
{{ selectedFileCount }} / {{ torrentFileCount }}
|
||||
<span v-if="selectedFileCount === 1">({{ torrentFileName }})</span>
|
||||
<div>{{ $t('modals.detail.pageOverview.fileCount') }}:</div>
|
||||
<div>
|
||||
{{ selectedFileCount }} / {{torrentFileCount }}
|
||||
<span v-if="selectedFileCount === 1">({{ torrentFileName }})</span>
|
||||
</div>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-card-text>
|
||||
|
@ -58,62 +66,67 @@
|
|||
<v-card-text>
|
||||
<v-row>
|
||||
<v-col cols="6">
|
||||
{{ $t('torrent.properties.status') }}:
|
||||
<v-chip small :class="`${torrentStateClass} white--text caption ml-2`">{{ torrent.state }}</v-chip>
|
||||
<div>
|
||||
{{ $t('torrent.properties.status') }}:
|
||||
</div>
|
||||
<v-chip small :class="torrentStateClass" class="white--text caption">{{ torrent.state }}</v-chip>
|
||||
</v-col>
|
||||
<v-col cols="6">
|
||||
{{ $t('torrent.properties.category') }}:
|
||||
<v-chip small class="upload white--text caption ml-2">
|
||||
<div>
|
||||
{{ $t('torrent.properties.category') }}:
|
||||
</div>
|
||||
<v-chip small class="upload white--text caption">
|
||||
{{ torrent.category.length ? torrent.category : $t('navbar.filters.uncategorized') }}
|
||||
</v-chip>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row>
|
||||
<v-col cols="6">
|
||||
{{ $t('torrent.properties.tracker') }}:
|
||||
<v-chip small class="moving white--text caption ml-2">
|
||||
{{ this.torrent?.tracker ? getDomainBody(this.torrent?.tracker) : $t('navbar.filters.untracked') }}
|
||||
</v-chip>
|
||||
<div>
|
||||
{{ $t('torrent.properties.tracker') }}:
|
||||
</div>
|
||||
<v-chip small class="moving white--text caption">{{ this.torrent?.tracker ? getDomainBody(this.torrent?.tracker) : $t('navbar.filters.untracked') }}</v-chip>
|
||||
</v-col>
|
||||
<v-col cols="6">
|
||||
{{ $t('torrent.properties.tags') }}:
|
||||
<v-chip v-if="torrent?.tags" v-for="tag in torrent.tags" :key="tag" small
|
||||
class="tags white--text caption ml-2">{{ tag }}
|
||||
<div class="d-flex flex-wrap chipgap">
|
||||
{{ $t('torrent.properties.tags') }}:
|
||||
</div>
|
||||
<v-chip v-if="torrent?.tags" v-for="tag in torrent.tags" :key="tag" small class="tags white--text caption">
|
||||
{{ tag }}
|
||||
</v-chip>
|
||||
<v-chip v-if="!torrent?.tags || torrent.tags.length === 0" small class="tags white--text caption ml-2">
|
||||
<v-chip v-if="!torrent?.tags || torrent.tags.length === 0" small class="tags white--text caption">
|
||||
{{ $t('navbar.filters.untagged') }}
|
||||
</v-chip>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row>
|
||||
<v-col cols="6">
|
||||
{{ $t('modals.detail.pageOverview.selectedFileSize') }}:<br/>
|
||||
{{ torrent?.size | getDataValue }} {{ torrent?.size | getDataUnit }} /
|
||||
{{ torrent?.total_size | getDataValue }} {{ torrent?.total_size | getDataUnit }}
|
||||
<div>{{ $t('modals.detail.pageOverview.selectedFileSize') }}:</div>
|
||||
<div>{{ torrent?.size | getData }} / {{ torrent?.total_size | getData }}</div>
|
||||
</v-col>
|
||||
<v-col cols="6">
|
||||
{{ $t('ratio') }}:<br/>
|
||||
{{ torrent?.ratio }}
|
||||
<div>{{ $t('ratio') }}:</div>
|
||||
<div>{{ torrent?.ratio }}</div>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row>
|
||||
<v-col cols="6">
|
||||
{{ $t('downloaded') }}:<br/>
|
||||
{{ torrent?.downloaded | getDataValue }} {{ torrent?.downloaded | getDataUnit }}
|
||||
<div>{{ $t('downloaded') }}:</div>
|
||||
<div>{{ torrent?.downloaded | getData }}</div>
|
||||
</v-col>
|
||||
<v-col cols="6">
|
||||
{{ $t('uploaded') }}:<br/>
|
||||
{{ torrent?.uploaded | getDataValue }} {{ torrent?.uploaded | getDataUnit }}
|
||||
<div>{{ $t('uploaded') }}:</div>
|
||||
<div>{{ torrent?.uploaded | getData }}</div>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row>
|
||||
<v-col cols="6">
|
||||
{{ $t('modals.detail.pageOverview.dlSpeedAverage') }}:<br/>
|
||||
{{ downloadSpeedAvg | networkSpeed }}
|
||||
<div>{{ $t('modals.detail.pageOverview.dlSpeedAverage') }}:</div>
|
||||
<div>{{ downloadSpeedAvg | networkSpeed }}</div>
|
||||
</v-col>
|
||||
<v-col cols="6">
|
||||
{{ $t('modals.detail.pageOverview.upSpeedAverage') }}:<br/>
|
||||
{{ uploadSpeedAvg | networkSpeed }}
|
||||
<div>{{ $t('modals.detail.pageOverview.upSpeedAverage') }}:</div>
|
||||
<div>{{ uploadSpeedAvg | networkSpeed }}</div>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-card-text>
|
||||
|
@ -189,13 +202,21 @@ export default defineComponent({
|
|||
},
|
||||
torrentStateClass() {
|
||||
return this.torrent?.state ? this.torrent.state.toLowerCase() : ''
|
||||
},
|
||||
isFetchingMetadata() {
|
||||
return this.torrent?.state === TorrentState.METADATA
|
||||
},
|
||||
shouldRenderPieceStates() {
|
||||
return !this.isFetchingMetadata
|
||||
&& this.torrentPieceCount > 0
|
||||
&& this.torrentPieceCount < this.webuiSettings.torrentPieceCountRenderThreshold
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
torrent() {
|
||||
this.getTorrentProperties()
|
||||
if (this.torrentPieceCount < 5000) {
|
||||
this.renderTorrentPieceStates()
|
||||
async torrent() {
|
||||
await this.getTorrentProperties()
|
||||
if (this.shouldRenderPieceStates) {
|
||||
await this.renderTorrentPieceStates()
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -205,7 +226,6 @@ export default defineComponent({
|
|||
const props = await qbit.getTorrentProperties(this.torrent?.hash as string)
|
||||
this.comment = props.comment
|
||||
this.createdBy = props.created_by
|
||||
// @ts-expect-error: TS2339: Property 'dateFormat' does not exist on type 'never'.
|
||||
this.creationDate = dayjs(props.creation_date * 1000).format(this.webuiSettings.dateFormat)
|
||||
this.downloadSpeedAvg = props.dl_speed_avg
|
||||
this.isPrivateTorrent = props.is_private
|
||||
|
@ -220,10 +240,9 @@ export default defineComponent({
|
|||
|
||||
const files = await qbit.getTorrentFiles(this.torrent?.hash as string)
|
||||
const pieces = await qbit.getTorrentPieceStates(this.torrent?.hash as string)
|
||||
if (!pieces) return
|
||||
|
||||
// Source: https://github.com/qbittorrent/qBittorrent/blob/6229b817300344759139d2fedbd59651065a561d/src/webui/www/private/scripts/prop-general.js#L230
|
||||
canvas.width = pieces.length
|
||||
canvas.width = pieces.length || -1
|
||||
const ctx = canvas.getContext('2d') as CanvasRenderingContext2D
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
||||
|
||||
|
@ -318,4 +337,12 @@ canvas#pieceStates {
|
|||
.v-card__title {
|
||||
word-break: normal;
|
||||
}
|
||||
|
||||
.chipgap {
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.overflow-wrap {
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -73,6 +73,12 @@ export function getDataValue(data: number, precision: number = 2) {
|
|||
|
||||
Vue.filter('getDataValue', getDataValue)
|
||||
|
||||
export function getData(data: number, precision: number = 2) {
|
||||
return `${getDataValue(data, precision)} ${getDataUnit(data)}`
|
||||
}
|
||||
|
||||
Vue.filter('getData', getData)
|
||||
|
||||
export function titleCase(str: string): string {
|
||||
if (str.length == 0) return str
|
||||
|
||||
|
|
|
@ -271,6 +271,8 @@
|
|||
"showShutdownButton": "Show shutdown button",
|
||||
"refreshInterval": "qBittorrent API refresh interval",
|
||||
"refreshIntervalHint": "In milliseconds",
|
||||
"torrentPieceCountRenderThreshold": "Torrent piece count to disable rendering",
|
||||
"torrentPieceCountRenderThresholdHint": "In milliseconds",
|
||||
"currentVersion": "Current Version",
|
||||
"qbittorrentVersion": "QBittorrent Version",
|
||||
"registerMagnet": "Register magnet links",
|
||||
|
@ -656,6 +658,8 @@
|
|||
"tabTitleTagsCategories": "Tags & Categories",
|
||||
"pageOverview": {
|
||||
"fetchingMetadata": "Fetching...",
|
||||
"waitingForMetadata": "Waiting for metadata...",
|
||||
"disabledCanvas": "Canvas disabled to save performance",
|
||||
"selectedFileSize": "Selected Files' Size",
|
||||
"dlSpeedAverage": "Download Speed Average",
|
||||
"upSpeedAverage": "Upload Speed Average",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { JSONSchemaType } from 'ajv'
|
||||
import { PersistentStoreState } from '@/types/vuetorrent'
|
||||
import { DashboardProperty, TitleOptions } from '@/enums/vuetorrent'
|
||||
import {JSONSchemaType} from 'ajv'
|
||||
import {PersistentStoreState} from '@/types/vuetorrent'
|
||||
import {DashboardProperty, TitleOptions} from '@/enums/vuetorrent'
|
||||
|
||||
export const StoreStateSchema: JSONSchemaType<PersistentStoreState> = {
|
||||
type: 'object',
|
||||
|
@ -43,6 +43,7 @@ export const StoreStateSchema: JSONSchemaType<PersistentStoreState> = {
|
|||
openSideBarOnStart: { type: 'boolean' },
|
||||
showShutdownButton: { type: 'boolean' },
|
||||
refreshInterval: { type: 'number' },
|
||||
torrentPieceCountRenderThreshold: { type: 'number' },
|
||||
busyDesktopTorrentProperties: { $ref: '/schemas/desktopDashboardProperties' },
|
||||
doneDesktopTorrentProperties: { $ref: '/schemas/desktopDashboardProperties' },
|
||||
busyMobileCardProperties: { $ref: '/schemas/mobileDashboardProperties' },
|
||||
|
@ -67,6 +68,7 @@ export const StoreStateSchema: JSONSchemaType<PersistentStoreState> = {
|
|||
'openSideBarOnStart',
|
||||
'showShutdownButton',
|
||||
'refreshInterval',
|
||||
'torrentPieceCountRenderThreshold',
|
||||
'busyDesktopTorrentProperties',
|
||||
'doneDesktopTorrentProperties',
|
||||
'busyMobileCardProperties',
|
||||
|
|
|
@ -4,10 +4,10 @@ import VuexPersist from 'vuex-persist'
|
|||
import actions from './actions'
|
||||
import getters from './getters'
|
||||
import mutations from './mutations'
|
||||
import type { StoreState, PersistentStoreState } from '@/types/vuetorrent'
|
||||
import { Status } from '@/models'
|
||||
import { TitleOptions, DashboardProperty } from '@/enums/vuetorrent'
|
||||
import { AppPreferences } from '@/types/qbit/models'
|
||||
import type {PersistentStoreState, StoreState} from '@/types/vuetorrent'
|
||||
import {Status} from '@/models'
|
||||
import {DashboardProperty, TitleOptions} from '@/enums/vuetorrent'
|
||||
import {AppPreferences} from '@/types/qbit/models'
|
||||
|
||||
const vuexPersist = new VuexPersist<PersistentStoreState>({
|
||||
key: 'vuetorrent',
|
||||
|
@ -136,13 +136,14 @@ export default new Vuex.Store<StoreState>({
|
|||
openSideBarOnStart: true,
|
||||
showShutdownButton: true,
|
||||
refreshInterval: 2000,
|
||||
torrentPieceCountRenderThreshold: 5000,
|
||||
busyDesktopTorrentProperties: JSON.parse(JSON.stringify(desktopPropertiesTemplate)),
|
||||
doneDesktopTorrentProperties: JSON.parse(JSON.stringify(desktopPropertiesTemplate)),
|
||||
busyMobileCardProperties: JSON.parse(JSON.stringify(mobilePropertiesTemplate)),
|
||||
doneMobileCardProperties: JSON.parse(JSON.stringify(mobilePropertiesTemplate))
|
||||
}
|
||||
},
|
||||
// @ts-expect-error
|
||||
//@ts-expect-error: TS2322: Type '...' is not assignable to type 'ActionTree<StoreState, StoreState>'.
|
||||
actions: {
|
||||
...actions
|
||||
},
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import type { DashboardProperty, TitleOptions } from '@/enums/vuetorrent'
|
||||
import type {DashboardProperty, TitleOptions} from '@/enums/vuetorrent'
|
||||
|
||||
export class TorrentProperty {
|
||||
name: DashboardProperty
|
||||
|
@ -29,6 +29,7 @@ export default interface WebUISettings {
|
|||
openSideBarOnStart: boolean
|
||||
showShutdownButton: boolean
|
||||
refreshInterval: number
|
||||
torrentPieceCountRenderThreshold: number
|
||||
busyDesktopTorrentProperties: TorrentProperty[]
|
||||
doneDesktopTorrentProperties: TorrentProperty[]
|
||||
busyMobileCardProperties: TorrentProperty[]
|
||||
|
|
|
@ -30,11 +30,18 @@ exports[`General > render correctly 1`] = `
|
|||
<v-list-item-stub data-v-7da6d3e2=\\"\\" activeclass=\\"\\" tag=\\"div\\">
|
||||
<v-checkbox-stub data-v-7da6d3e2=\\"\\" errorcount=\\"1\\" errormessages=\\"\\" messages=\\"\\" rules=\\"\\" successmessages=\\"\\" backgroundcolor=\\"\\" hidedetails=\\"true\\" ripple=\\"true\\" valuecomparator=\\"[Function]\\" indeterminateicon=\\"$checkboxIndeterminate\\" officon=\\"$checkboxOff\\" onicon=\\"$checkboxOn\\" class=\\"ma-0 pa-0\\"></v-checkbox-stub>
|
||||
</v-list-item-stub>
|
||||
<v-list-item-stub data-v-7da6d3e2=\\"\\" activeclass=\\"\\" tag=\\"div\\" class=\\"mb-3\\">
|
||||
<v-list-item-stub data-v-7da6d3e2=\\"\\" activeclass=\\"\\" tag=\\"div\\">
|
||||
<v-checkbox-stub data-v-7da6d3e2=\\"\\" errorcount=\\"1\\" errormessages=\\"\\" messages=\\"\\" rules=\\"\\" successmessages=\\"\\" backgroundcolor=\\"\\" hidedetails=\\"true\\" ripple=\\"true\\" valuecomparator=\\"[Function]\\" indeterminateicon=\\"$checkboxIndeterminate\\" officon=\\"$checkboxOff\\" onicon=\\"$checkboxOn\\" class=\\"ma-0 pa-0\\"></v-checkbox-stub>
|
||||
</v-list-item-stub>
|
||||
<v-list-item-stub data-v-7da6d3e2=\\"\\" activeclass=\\"\\" tag=\\"div\\" class=\\"mb-3\\">
|
||||
<v-text-field-stub data-v-7da6d3e2=\\"\\" errorcount=\\"1\\" errormessages=\\"\\" messages=\\"\\" rules=\\"\\" successmessages=\\"\\" backgroundcolor=\\"\\" dense=\\"true\\" loaderheight=\\"2\\" clearicon=\\"$clear\\" outlined=\\"true\\" type=\\"number\\"></v-text-field-stub>
|
||||
<v-list-item-stub data-v-7da6d3e2=\\"\\" activeclass=\\"\\" tag=\\"div\\" class=\\"my-2\\">
|
||||
<v-row-stub data-v-7da6d3e2=\\"\\" tag=\\"div\\">
|
||||
<v-col-stub data-v-7da6d3e2=\\"\\" cols=\\"12\\" sm=\\"6\\" tag=\\"div\\" class=\\"mb-n4\\">
|
||||
<v-text-field-stub data-v-7da6d3e2=\\"\\" errorcount=\\"1\\" errormessages=\\"\\" messages=\\"\\" rules=\\"\\" successmessages=\\"\\" backgroundcolor=\\"\\" dense=\\"true\\" loaderheight=\\"2\\" clearicon=\\"$clear\\" outlined=\\"true\\" type=\\"number\\"></v-text-field-stub>
|
||||
</v-col-stub>
|
||||
<v-col-stub data-v-7da6d3e2=\\"\\" cols=\\"12\\" sm=\\"6\\" tag=\\"div\\">
|
||||
<v-text-field-stub data-v-7da6d3e2=\\"\\" errorcount=\\"1\\" errormessages=\\"\\" messages=\\"\\" rules=\\"\\" successmessages=\\"\\" backgroundcolor=\\"\\" dense=\\"true\\" loaderheight=\\"2\\" clearicon=\\"$clear\\" outlined=\\"true\\" type=\\"number\\"></v-text-field-stub>
|
||||
</v-col-stub>
|
||||
</v-row-stub>
|
||||
</v-list-item-stub>
|
||||
<v-list-item-stub data-v-7da6d3e2=\\"\\" activeclass=\\"\\" tag=\\"div\\" class=\\"mb-3\\">
|
||||
<v-row-stub data-v-7da6d3e2=\\"\\" tag=\\"div\\">
|
||||
|
|
Loading…
Add table
Reference in a new issue