diff --git a/dashboard/src/views/AppstoreView.vue b/dashboard/src/views/AppstoreView.vue index 8ea9aaeae..ff2fa84f8 100644 --- a/dashboard/src/views/AppstoreView.vue +++ b/dashboard/src/views/AppstoreView.vue @@ -4,8 +4,9 @@ import { useI18n } from 'vue-i18n'; const i18n = useI18n(); const t = i18n.t; -import { ref, computed, useTemplateRef, onMounted, inject } from 'vue'; -import { Button, TextInput, Spinner, InputDialog } from 'pankow'; +import moment from 'moment'; +import { ref, computed, useTemplateRef, onMounted, inject, watch } from 'vue'; +import { Button, TextInput, Spinner, InputDialog, SingleSelect } from 'pankow'; import AppsModel from '../models/AppsModel.js'; import AppstoreModel from '../models/AppstoreModel.js'; import AppInstallDialog from '../components/AppInstallDialog.vue'; @@ -20,7 +21,37 @@ const ready = ref(false); const proxyApp = ref(); const apps = ref([]); const search = ref(''); + +// clear category on search +watch(search, (newValue) => { + if (newValue) category.value =''; +}); + +function filterForNewApps(apps) { + var minApps = apps.length < 12 ? apps.length : 12; // prevent endless loop + var tmp = []; + var i = 0; + + do { + var offset = moment().subtract(i++, 'days'); + tmp = apps.filter(function (app) { return moment(app.publishedAt).isAfter(offset); }); + } while(tmp.length < minApps); + + return tmp; +} + const filteredApps = computed(() => { + if (category.value) { + if (category.value === 'new') { + return filterForNewApps(apps.value); + } else { + return apps.value.filter(a => { + if (a.manifest.tags.join().toLowerCase().indexOf(category.value) !== -1) return true; + return false; + }); + } + } + if (!search.value) return apps.value; const s = search.value.toLowerCase(); @@ -45,6 +76,36 @@ const inputDialog = useTemplateRef('inputDialog'); const features = inject('features'); const installedApps = ref([]); +const category = ref(''); +const categories = [ + { id: '', label: t('appstore.category.all') }, + { id: 'new', label: t('appstore.category.newApps') }, + { id: 'analytics', label: 'Analytics'}, + { id: 'automation', label: 'Automation'}, + { id: 'blog', label: 'Blog'}, + { id: 'chat', label: 'Chat'}, + { id: 'crm', label: 'CRM'}, + { id: 'document', label: 'Documents'}, + { id: 'email', label: 'Email'}, + { id: 'federated', label: 'Federated'}, + { id: 'finance', label: 'Finance'}, + { id: 'forum', label: 'Forum'}, + { id: 'fun', label: 'Fun'}, + { id: 'gallery', label: 'Gallery'}, + { id: 'game', label: 'Games'}, + { id: 'git', label: 'Code Hosting'}, + { id: 'hosting', label: 'Web Hosting'}, + { id: 'learning', label: 'Learning'}, + { id: 'media', label: 'Media'}, + { id: 'no-code', label: 'No-code'}, + { id: 'notes', label: 'Notes'}, + { id: 'project', label: 'Project Management'}, + { id: 'sync', label: 'File Sync'}, + { id: 'voip', label: 'VoIP'}, + { id: 'vpn', label: 'VPN'}, + { id: 'wiki', label: 'Wiki'}, +]; + function onAppInstallDialogClose() { window.location.href = '#/appstore'; } @@ -127,14 +188,15 @@ onMounted(async () => { -
-
- - -
- - -
+
+ + + + +
+ +
+
@@ -178,11 +240,10 @@ onMounted(async () => { .filter-bar { width: 100%; display: flex; + gap: 6px; justify-content: space-between; margin-bottom: 30px; - padding-left: 20px; - padding-right: 20px; -} + } .grid { position: relative;