Skip to content

Commit

Permalink
feature/catalog_improvement (#54)
Browse files Browse the repository at this point in the history
  • Loading branch information
mlyubimov authored Nov 29, 2023
1 parent 59602b6 commit 122979e
Show file tree
Hide file tree
Showing 10 changed files with 898 additions and 600 deletions.
21 changes: 21 additions & 0 deletions frontend/src/components/Loading.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<template>
<div class="column items-center">
<q-spinner
color="primary"
size="3em"
class="q-mb-md"
></q-spinner>
<p>{{ props.label }}</p>
</div>
</template>

<script setup>
import { defineProps } from 'vue'
const props = defineProps({
label: {
type: String,
default: 'Loading...'
}
})
</script>
17 changes: 17 additions & 0 deletions frontend/src/composables/useBeforunload.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const beforeUnloadHandler = (event) => {
// Recommended
event.preventDefault()

// Included for legacy support, e.g. Chrome/Edge < 119
event.returnValue = true
}

const beforeunloadActive = () => {
window.addEventListener('beforeunload', beforeUnloadHandler)
}

const beforeunloadDeactivate = () => {
window.removeEventListener('beforeunload', beforeUnloadHandler)
}

export { beforeunloadActive, beforeunloadDeactivate }
49 changes: 49 additions & 0 deletions frontend/src/composables/usePromiseQueue.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { beforeunloadActive, beforeunloadDeactivate } from 'composables/useBeforunload'

export default function promiseQueue () {
const queue = []
let process = false

const addToQueue = (fn, params) => {
queue.push({
fn,
params
})

if (!process) {
executeQueue()
}
}

const executeQueue = () => {
process = true
beforeunloadActive()

return new Promise((resolve, reject) => {
const next = () => {
if (queue.length) {
const { fn, params } = queue.shift()

fn(...params)
.then(() => next())
.catch((error) => {
process = false
beforeunloadDeactivate()
reject(error)
})
} else {
process = false
beforeunloadDeactivate()
resolve()
}
}

next()
})
}

return {
addToQueue,
executeQueue
}
}
128 changes: 28 additions & 100 deletions frontend/src/layouts/AppsLayout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,13 @@
>
<div
class="apps-navbar row justify-end items-center full-width q-mb-xl"
:class="action.type ? 'disabled' : ''"
>
<q-icon
v-if="currentApp || flags.installedPage"
name="mdi-chevron-left"
size="56px"
class="cursor-pointer q-mr-md"
@click="appsStore.toggleFlag('installedPage', false); router.push({ name: 'Apps' })"
@click="appsStore.toggleFlag('installedPage', false); !appsStore.initialCategory ? router.push({ name: 'Apps' }) : router.push({ name: 'AppsCategory', params: { path: appsStore.initialCategory.name.toLowerCase() } })"
></q-icon>
<q-icon
v-else
Expand All @@ -36,8 +35,8 @@
<div>
<q-btn
flat
rounded
no-caps
dense
:color="flags.installedPage ? 'primary' : 'black'"
style="font-weight: 400"
icon="svguse:common-icons.svg#installed"
Expand All @@ -46,18 +45,19 @@
label="Installed"
>
<q-badge
v-if="$q.screen.width > 365 && updatableAppsAmount > 0"
v-if="$q.screen.width > 365 && flags.updatabledAppsCount > 0"
color="positive"
floating
class="outdated-badge"
>{{ updatableAppsAmount }}</q-badge>
:label="flags.updatabledAppsCount"
/>
</q-btn>
</div>
<div class="q-ml-md">
<q-btn
flat
rounded
no-caps
dense
color="black"
style="font-weight: 400"
icon="mdi-github"
Expand Down Expand Up @@ -180,7 +180,6 @@
import { onMounted, computed, watch } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { useQuasar } from 'quasar'
import { fetchCategories, fetchAppsShort, fetchAppById } from 'util/fetch'
import SearchBar from 'components/SearchBar.vue'
import { log } from 'composables/useLog'
import { rpcErrorHandler } from 'composables/useRpcUtils'
Expand All @@ -197,11 +196,7 @@ const appsStore = useAppsStore()
const flags = computed(() => appsStore.flags)
const flipperReady = computed(() => appsStore.flipperReady)
const action = computed(() => appsStore.action)
const sdk = computed(() => appsStore.sdk)
const currentApp = computed(() => appsStore.currentApp)
const apps = computed(() => appsStore.apps)
const installedApps = computed(() => appsStore.installedApps)
const categories = computed(() => appsStore.categories)
const router = useRouter()
Expand All @@ -217,20 +212,6 @@ onMounted(() => {
}
})
const updatableAppsAmount = computed(() => {
return apps.value.filter(app => {
if (app.isInstalled === true && app.installedVersion && app.currentVersion.status === 'READY') {
if (sdk.value.api && app.installedVersion.api !== sdk.value.api) {
return true
}
if (app.installedVersion.isOutdated) {
return true
}
}
return false
}).length
})
const startRpc = async () => {
appsStore.toggleFlag('rpcToggling', true)
Expand All @@ -254,13 +235,12 @@ const startRpc = async () => {
}
const toggleInstalled = () => {
if (flags.value.installedPage) {
appsStore.toggleFlag('installedPage', false)
router.push({ name: 'Apps' })
} else {
router.push({ name: 'InstalledApps' })
if (!mainFlags.value.connected) {
appsStore.toggleFlag('connectFlipperDialog', true)
return
}
router.push({ name: 'InstalledApps' })
}
const ensureCommonPaths = async () => {
Expand Down Expand Up @@ -290,68 +270,26 @@ const ensureCommonPaths = async () => {
const watchParams = async () => {
const path = route.params.path
appsStore.setInitalCategory(null)
if (route.name === 'InstalledApps') {
appsStore.toggleFlag('installedPage', true)
if (!mainFlags.value.connected) {
appsStore.toggleFlag('connectFlipperDialog', true)
}
return
} else {
appsStore.toggleFlag('installedPage', false)
}
if (!path) {
return
}
appsStore.toggleFlag('installedPage', false)
const normalize = (string) => string.toLowerCase().replaceAll(' ', '-')
const category = categories.value.find(e => normalize(e.name) === normalize(path))
if (category) {
appsStore.setInitalCategory(category)
} else {
try {
const appFull = await fetchAppById(path, sdk.value)
if (appFull.detail && appFull.detail.status === 'error') {
router.push({ name: 'Apps' })
return
}
appsStore.setCurrentApp(appFull)
const installed = installedApps.value.find(e => e.id === appsStore.currentApp.id)
const newCurrentApp = currentApp.value
if (installed) {
newCurrentApp.isInstalled = true
newCurrentApp.installedVersion = installed.installedVersion
newCurrentApp.installedVersion.isOutdated = currentApp.value.currentVersion.id !== currentApp.value.installedVersion.id
}
newCurrentApp.actionButton = appsStore.actionButton(newCurrentApp)
appsStore.setCurrentApp(newCurrentApp)
appsStore.setInitalCategory(categories.value.find(e => e.id === appFull.categoryId))
} catch (error) {
console.error(error)
}
}
}
const start = async () => {
appsStore.toggleFlag('rpcActive', mainFlags.value.rpcActive)
appsStore.toggleFlag('loadingInitial', true)
const params = {
limit: 500,
offset: 0,
sort_by: 'updated_at',
sort_order: -1,
is_latest_release_version: true
}
const categoryParams = {
limit: 500
}
if (mainFlags.value.connected) {
if (!flags.value.rpcActive) {
Expand All @@ -367,13 +305,6 @@ const start = async () => {
appsStore.setPropertySdk({ api })
appsStore.setPropertySdk({ target })
params.api = api
params.target = target
delete params.is_latest_release_version
categoryParams.target = params.target
categoryParams.api = params.api
} catch (error) {
appsStore.toggleFlag('outdatedFirmwareDialogPersistent', true)
}
Expand All @@ -388,22 +319,7 @@ const start = async () => {
mainStore.start()
}
appsStore.setCategories(await fetchCategories(categoryParams))
await watchParams()
appsStore.toggleFlag('loadingInitial', false)
let newApps = [], allApps = []
do {
newApps = await fetchAppsShort(params)
allApps = allApps.concat(newApps)
if (newApps.length === params.limit) {
params.offset += params.limit
}
} while (newApps.length === params.limit)
appsStore.setApps(allApps)
await appsStore.updateInstalledApps(installedApps.value)
}
watch(flipperReady, () => {
Expand All @@ -414,6 +330,16 @@ watch(flipperReady, () => {
watch(route, async () => {
await watchParams()
})
watch(() => mainFlags.value.connected, (condition) => {
if (condition) {
appsStore.toggleFlag('loadingInstalledApps', true)
}
if (!condition) {
appsStore.onClearInstalledAppsList()
}
})
</script>

<style lang="sass" scoped>
Expand All @@ -424,12 +350,14 @@ watch(route, async () => {
height: 40px
.outdated-badge
width: 17px
height: 17px !important
position: relative
top: -11px
left: -72px
position: absolute
top: -3px
left: 32px
font-size: 10px
border: 1px #ffffff solid
border-radius: 17px
padding: 5px
</style>
src/composables/useLog
21 changes: 11 additions & 10 deletions frontend/src/layouts/MainLayout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -600,7 +600,7 @@ const downloadLogs = () => {
}
const start = async (manual) => {
mainStore.start(manual)
await mainStore.start(manual)
}
onMounted(async () => {
Expand All @@ -625,20 +625,21 @@ onMounted(async () => {
const isProd = process.env.PRODUCTION
const savedChannel = localStorage.getItem('catalogChannel')
if (savedChannel) {
if (savedChannel !== 'production') {
mainStore.toggleFlag('catalogChannelProduction', false)
} else {
mainStore.toggleFlag('catalogCanSwitchChannel', true)
}
if (isProd) {
localStorage.setItem('catalogChannel', 'production')
} else {
if (isProd) {
localStorage.setItem('catalogChannel', 'production')
if (savedChannel === 'production') {
mainStore.toggleFlag('catalogChannelProduction', true)
} else {
mainStore.toggleFlag('catalogChannelProduction', false)
}
if (!savedChannel) {
localStorage.setItem('catalogChannel', 'dev')
mainStore.toggleFlag('catalogChannelProduction', false)
mainStore.toggleFlag('catalogCanSwitchChannel', true)
}
mainStore.toggleFlag('catalogCanSwitchChannel', true)
}
navigator.serial.addEventListener('disconnect', e => {
Expand Down
Loading

0 comments on commit 122979e

Please sign in to comment.