feat(export): implement collection export for ics/rss/widget

This commit is contained in:
lesion 2023-11-03 23:03:53 +01:00
parent c333430ee6
commit a0de5547c7
No known key found for this signature in database
GPG key ID: 352918250B012177
4 changed files with 426 additions and 412 deletions

View file

@ -1,7 +1,6 @@
<template lang="pug">
v-row
v-col(cols=12)
span {{ filters }} - {{ meta }}
v-col(sm=3 cols=12)
v-switch(
v-if='settings.allow_recurrent_event'
v-model='show_recurrent'
@ -9,13 +8,12 @@ v-row
inset color='primary'
hide-details
:label="$t('event.show_recurrent')")
v-col.mb-4(cols=12)
v-col(sm="5" cols=12)
v-autocomplete.p-0(
:disabled='!!collection'
v-model="filters"
outlined
rounded
:label='$t("common.search")'
:filter='filter'
cache-items
:label='$t("common.filter")'
hide-details
color='primary'
hide-selected
@ -45,6 +43,29 @@ v-row
v-list-item-content
v-list-item-title(v-text='item.label')
v-list-item-subtitle(v-if='item.type ==="place"' v-text='item.label !== "online" && item.address')
v-col(sm=4 cols=12)
v-autocomplete.p-0(
:disabled='!!filters.length'
v-model="collection"
outlined
:label='$t("common.collections")'
hide-details
color='primary'
hide-selected
:menu-props="{ maxWidth: '400' }"
:items='collections'
@change='change'
hide-no-data
clearable
:clear-icon='mdiCloseCircle'
item-text='name')
template(v-slot:itsdfems='{ item }')
v-list-item-avatar
v-icon(v-text="item.type === 'place' ? mdiMapMarker : item.type === 'tag' ? mdiTag : mdiCollage")
v-list-item-content
v-list-item-title(v-text='item.label')
v-list-item-subtitle(v-if='item.type ==="place"' v-text='item.label !== "online" && item.address')
</template>
<script>
@ -55,23 +76,23 @@ import debounce from 'lodash/debounce'
export default {
name: 'Search',
props: {
filters: { type: Object, default: () => ({ }) }
value: { type: Object, default: () => ({ }) }
},
data () {
return {
mdiTag, mdiMapMarker, mdiCloseCircle, mdiCollage,
// meta: [],
items: [],
show_recurrent: this.filters.show_recurrent || false
filters: [],
collection: null,
collections: [],
show_recurrent: this.value.show_recurrent || false
}
},
async fetch () {
this.collections = await this.$axios.$get('/collections')
},
computed: {
...mapState(['settings']),
meta: {
get () {
return this.filters
}
}
},
methods: {
filter (item, queryText, itemText) {
@ -80,27 +101,31 @@ export default {
},
search: debounce(async function(search) {
this.items = await this.$axios.$get(`/event/meta?search=${search.target.value}`)
console.error('items ', this.items.length)
}, 100),
remove (item) {
console.error(item)
// const filters = {
// tags: this.filters.filter(t => t.type === 'tag' && t.label !== item.label).map(t => t.label),
// places: this.filters.filter(p => p.type === 'place' && p.id !== item.id).map(p => p.id),
// show_recurrent: this.show_recurrent
// }
this.filters = this.filters.filter(m => m.type !== item.type || m.type === 'place' ? m.id !== item.id : m.label !== item.label)
this.$emit('update', filters)
// this.change()
// this.$emit('input', filters)
this.change()
},
change (v, i) {
console.error(v, i)
if (!v) return
const collection = v.find(c => c.type === 'collection')
if (collection) {
this.$emit('update', { collection: collection.label, places: [], tags: [] })
return
}
change () {
if (this.collection) {
this.filters = []
this.$emit('input', { collection: this.collection, places: [], tags: [], show_recurrent: this.show_recurrent })
} else {
const filters = {
tags: v.filter(t => t.type === 'tag').map(t => t.label),
places: v.filter(p => p.type === 'place').map(p => p.id),
tags: this.filters.filter(t => t.type === 'tag').map(t => t.label),
places: this.filters.filter(p => p.type === 'place').map(p => p.id),
show_recurrent: this.show_recurrent
}
this.$emit('update', filters)
this.$emit('input', filters)
}
}
}
}

View file

@ -125,7 +125,8 @@
"insert_your_address": "Enter your e-mail address",
"feed_description": "To follow updates from a computer or smartphone without the need to periodically open this site, use RSS feeds. </p>\n\n<p> With RSS feeds you use a special app to receive updates from sites that interest you. It's a good way to follow many sites quickly, without the need to create an account or other complications. </p>\n\n<li> If you have Android, we recommend <a href=\"https://f-droid.org/en/packages/net.frju.flym/\">Flym</a> or Feeder </li>\n<li> For iPhone / iPad you can use <a href=\"https://itunes.apple.com/ua/app/feeds4u/id1038456442?mt=8\"> Feed4U </a> </li>\n<li> For desktop / laptop we recommend Feedbro, to be installed on <a href=\"https://addons.mozilla.org/en-GB/firefox/addon/feedbroreader/\"> Firefox </a> or <a href=\"https://chrome.google.com/webstore/detail/feedbro/mefgmmbdailogpfhfblcnnjfmnpnmdfa\"> Chrome </a>. </li>\n<br/>\nAdding this link to your RSS feed reader will keep you up to date.",
"ical_description": "Computers and smartphones are commonly equipped with a calendar app capable of importing a remote calendar.",
"list_description": "If you have a website and want to show a list of events, use the following code"
"list_description": "If you have a website and want to show a list of events, use the following code",
"filter_description": "You can filter your export here by tags and place or by a preset collection"
},
"register": {
"description": "Social movements should organize and self-finance.<br/>\n<br/>Before you can publish, <strong> the account must be approved</strong>, consider that <strong> behind this site you will find real people</strong>, so write two lines to let us know what events you would like to publish.",

View file

@ -4,13 +4,11 @@ v-container.pa-0.pa-md-3
v-card-title {{$t('common.share')}}
v-card-text
p.text-body-1 {{$t('export.intro')}}
v-row
v-col(:md='2' :cols='12')
v-card-title.py-0 {{$t('common.filter')}}
v-col
Search(
:filters='filters'
@update='f => filters = f')
v-alert.blue-grey.darken-4.text-body-1.lime--text.text--lighten-3
v-card-title {{$t('common.filter')}}
v-card-subtitle {{$t('export.filter_description')}}
v-card-text
Search(v-model='filters')
v-tabs(v-model='type' show-arrows :next-icon='mdiChevronRight' :prev-icon='mdiChevronLeft')
//- TOFIX
@ -52,7 +50,7 @@ v-container.pa-0.pa-md-3
v-col.col-12.col-lg-4
v-text-field(v-model='list.title' :label='$t("common.title")')
v-text-field(v-model='list.maxEvents' type='number' min='1' :label='$t("common.max_events")')
v-switch(v-model='list.theme' inset true-value='dark' false-value='light' :label="$t('admin.is_dark')")
v-switch(v-model='list.theme' hide-details inset true-value='dark' false-value='light' :label="$t('admin.is_dark')")
v-switch(v-model='list.sidebar' inset true-value='true' false-value='false' :label="$t('admin.widget')")
v-col.col-12.col-lg-8
gancio-events(:baseurl='settings.baseurl'

View file

@ -75,13 +75,6 @@ const eventController = {
raw: true
})
const collections = await Collection.findAll({
where: {
name: Sequelize.where(Sequelize.fn('LOWER', Sequelize.col('name')), 'LIKE', '%' + search + '%'),
},
attributes: [['name', 'label'], 'id'],
raw: true
})
const ret = places.map(p => {
p.type = 'place'
@ -89,10 +82,7 @@ const eventController = {
}).concat(tags.map(t => {
t.type = 'tag'
return t
}).concat(collections.map(c => {
c.type = 'collection'
return c
}))).sort((a, b) => b.w - a.w).slice(0, 10)
})).sort((a, b) => b.w - a.w).slice(0, 10)
return res.json(ret)
},