more UI polish and schedule safe guards and optimization
This commit is contained in:
@@ -95,6 +95,23 @@
|
||||
Reset Stuck ({{ stuckRunningCount }})
|
||||
</v-btn>
|
||||
<v-spacer />
|
||||
<!-- Credential Status -->
|
||||
<div class="d-flex align-center ga-2">
|
||||
<v-icon size="small" class="mr-1">mdi-key</v-icon>
|
||||
<span class="text-body-2 text-grey mr-2">Auth:</span>
|
||||
<v-chip
|
||||
v-for="platform in supportedPlatforms"
|
||||
:key="platform"
|
||||
:color="credentialsStore.hasPlatformCredentials(platform) ? 'success' : 'grey'"
|
||||
:variant="credentialsStore.hasPlatformCredentials(platform) ? 'tonal' : 'outlined'"
|
||||
size="x-small"
|
||||
:to="credentialsStore.hasPlatformCredentials(platform) ? undefined : '/credentials'"
|
||||
>
|
||||
<v-icon start size="x-small">{{ getPlatformIcon(platform) }}</v-icon>
|
||||
{{ platform }}
|
||||
</v-chip>
|
||||
</div>
|
||||
<v-divider vertical class="mx-2" />
|
||||
<div class="text-body-2 text-grey d-flex align-center">
|
||||
<v-icon size="small" class="mr-1">mdi-harddisk</v-icon>
|
||||
Storage: {{ storageStats?.total_size_formatted || 'Calculating...' }}
|
||||
@@ -267,9 +284,10 @@
|
||||
<v-btn
|
||||
size="small"
|
||||
variant="text"
|
||||
:to="`/sources/${source.id}/edit`"
|
||||
to="/subscriptions"
|
||||
>
|
||||
Edit
|
||||
View
|
||||
<v-tooltip activator="parent">View in Subscriptions</v-tooltip>
|
||||
</v-btn>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -290,13 +308,18 @@
|
||||
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
||||
import { useSourcesStore } from '../stores/sources'
|
||||
import { useDownloadsStore } from '../stores/downloads'
|
||||
import { useCredentialsStore } from '../stores/credentials'
|
||||
import { useNotificationStore } from '../stores/notifications'
|
||||
import { settingsApi, downloadsApi } from '../services/api'
|
||||
|
||||
const sourcesStore = useSourcesStore()
|
||||
const downloadsStore = useDownloadsStore()
|
||||
const credentialsStore = useCredentialsStore()
|
||||
const notifications = useNotificationStore()
|
||||
|
||||
// Supported platforms for credential status
|
||||
const supportedPlatforms = ['patreon', 'subscribestar', 'hentaifoundry', 'discord']
|
||||
|
||||
// State
|
||||
const checkingAll = ref(false)
|
||||
const retryingAll = ref(false)
|
||||
@@ -337,6 +360,7 @@ function loadDashboardData() {
|
||||
// Fire off all requests in parallel, don't block UI
|
||||
// Each section handles its own loading state
|
||||
sourcesStore.fetchSources().catch(e => console.error('Failed to fetch sources:', e))
|
||||
credentialsStore.fetchCredentials().catch(e => console.error('Failed to fetch credentials:', e))
|
||||
|
||||
downloadsStore.fetchStats()
|
||||
.catch(e => console.error('Failed to fetch stats:', e))
|
||||
@@ -490,6 +514,16 @@ function getStatusIcon(status) {
|
||||
return icons[status] || 'mdi-help-circle'
|
||||
}
|
||||
|
||||
function getPlatformIcon(platform) {
|
||||
const icons = {
|
||||
patreon: 'mdi-patreon',
|
||||
subscribestar: 'mdi-star',
|
||||
hentaifoundry: 'mdi-palette',
|
||||
discord: 'mdi-discord',
|
||||
}
|
||||
return icons[platform] || 'mdi-web'
|
||||
}
|
||||
|
||||
function getStatusColor(status) {
|
||||
const colors = {
|
||||
completed: 'success',
|
||||
|
||||
@@ -197,7 +197,7 @@
|
||||
</td>
|
||||
<td>
|
||||
<div>{{ formatDate(source.last_check) }}</div>
|
||||
<div v-if="source.enabled && source.last_check" class="text-caption text-grey">
|
||||
<div v-if="source.enabled" class="text-caption text-grey">
|
||||
Next: {{ formatNextCheck(source) }}
|
||||
</div>
|
||||
</td>
|
||||
@@ -323,15 +323,22 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch, onMounted } from 'vue'
|
||||
import { ref, watch, onMounted, computed } from 'vue'
|
||||
import { useSubscriptionsStore } from '../stores/subscriptions'
|
||||
import { useCredentialsStore } from '../stores/credentials'
|
||||
import { useSettingsStore } from '../stores/settings'
|
||||
import { useNotificationStore } from '../stores/notifications'
|
||||
|
||||
const subscriptionsStore = useSubscriptionsStore()
|
||||
const credentialsStore = useCredentialsStore()
|
||||
const settingsStore = useSettingsStore()
|
||||
const notifications = useNotificationStore()
|
||||
|
||||
// Get global schedule interval from settings (default 8 hours)
|
||||
const scheduleInterval = computed(() =>
|
||||
settingsStore.settings['download.schedule_interval'] || 28800
|
||||
)
|
||||
|
||||
const searchQuery = ref('')
|
||||
const filterEnabled = ref(null)
|
||||
const expandedIds = ref([])
|
||||
@@ -387,6 +394,7 @@ const headers = [
|
||||
onMounted(() => {
|
||||
loadSubscriptions()
|
||||
credentialsStore.fetchCredentials()
|
||||
settingsStore.fetchSettings() // For schedule_interval
|
||||
})
|
||||
|
||||
watch([searchQuery, filterEnabled], () => {
|
||||
@@ -435,9 +443,10 @@ function formatDate(dateStr) {
|
||||
}
|
||||
|
||||
function formatNextCheck(source) {
|
||||
if (!source.last_check || !source.check_interval) return 'Unknown'
|
||||
if (!source.last_check) return 'Due now'
|
||||
const lastCheck = new Date(source.last_check)
|
||||
const nextCheck = new Date(lastCheck.getTime() + source.check_interval * 1000)
|
||||
// Use global schedule_interval from settings
|
||||
const nextCheck = new Date(lastCheck.getTime() + scheduleInterval.value * 1000)
|
||||
const now = new Date()
|
||||
|
||||
if (nextCheck <= now) return 'Due now'
|
||||
|
||||
Reference in New Issue
Block a user