Add appstore category dropdown
This commit is contained in:
@@ -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 () => {
|
||||
<AppInstallDialog ref="appInstallDialog" @close="onAppInstallDialogClose"/>
|
||||
<ApplinkDialog ref="applinkDialog" @success="onApplinkDialogSuccess()"/>
|
||||
|
||||
<div class="filter-bar">
|
||||
<div></div>
|
||||
<Spinner v-if="!ready" class="pankow-spinner-large"/>
|
||||
<TextInput v-show="ready" ref="searchInput" @keydown.esc="search = ''" v-model="search" :placeholder="$t('appstore.searchPlaceholder')" style="max-width: 100%; width: 500px;"/>
|
||||
<div>
|
||||
<Button secondary plain icon="fas fa-exchange-alt" @click="onInstall(proxyApp)">{{ $t('apps.addAppproxyAction') }}</Button>
|
||||
<Button secondary plain icon="fas fa-link" @click="onApplinkDialogOpen()">{{ $t('apps.addApplinkAction') }}</Button>
|
||||
</div>
|
||||
<div class="filter-bar" :disabled="!ready" :style="{ 'pointer-events': ready ? null : 'none' }">
|
||||
<SingleSelect @select="onCategory" v-model="category" :options="categories" option-key="id" option-label="label"/>
|
||||
<TextInput ref="searchInput" @keydown.esc="search = ''" v-model="search" :placeholder="$t('appstore.searchPlaceholder')" style="flex-grow: 1;"/>
|
||||
<Button secondary plain icon="fas fa-exchange-alt" @click="onInstall(proxyApp)">{{ $t('apps.addAppproxyAction') }}</Button>
|
||||
<Button secondary plain icon="fas fa-link" @click="onApplinkDialogOpen()">{{ $t('apps.addApplinkAction') }}</Button>
|
||||
</div>
|
||||
|
||||
<div v-if="!ready" style="width: 100%; text-align: center;">
|
||||
<Spinner class="pankow-spinner-large"/>
|
||||
</div>
|
||||
|
||||
<div v-if="!search && ready">
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user