Skip to content

Commit

Permalink
- ADD: Added initial user permission handling.
Browse files Browse the repository at this point in the history
- ADD: Added initial multi-select feature to image gallery.
- CHG: Changed tag chip appearance.
  • Loading branch information
sebastian-raubach committed Nov 30, 2023
1 parent 50002f4 commit 9e1caf1
Show file tree
Hide file tree
Showing 10 changed files with 116 additions and 21 deletions.
4 changes: 4 additions & 0 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -377,4 +377,8 @@ export default {
margin-bottom: 1rem;
line-height: 1.8;
}
.position-relative {
position: relative;
}
</style>
4 changes: 2 additions & 2 deletions src/components/AlbumGallery.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
:label="$t('formLabelSortBy')"
density="compact" />
<v-spacer></v-spacer>
<template v-if="storeToken">
<template v-if="storeUserPermissions && storeUserPermissions['ALBUM_CREATE']">
<v-btn-group density="compact" class="me-3">
<v-btn
@click="addAlbum"
Expand Down Expand Up @@ -121,7 +121,7 @@ export default {
computed: {
...mapGetters([
'storeAlbumsPerPage',
'storeToken',
'storeUserPermissions',
'storeAlbumCardSize'
]),
disabled: function () {
Expand Down
14 changes: 10 additions & 4 deletions src/components/ImageCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,16 @@
</v-list-item>
</v-img>

<slot></slot>

<v-card-actions>
<v-btn color="primary" variant="text" :to="{ name: 'image-details', params: { imageId: image.id } }">{{ $t('buttonView') }}</v-btn>
<v-spacer></v-spacer>
<v-btn size="small" :disabled="!storeToken" color="red" variant="text" icon="mdi-heart" @click.stop.prevent="$emit('onFavoriteChanged')" v-if="image.isFavorite === 1"></v-btn>
<v-btn size="small" :disabled="!storeToken" :color="null" variant="text" icon="mdi-heart-outline" @click.stop.prevent="$emit('onFavoriteChanged')" v-else></v-btn>
<v-btn size="small" :disabled="!canEdit" color="red" variant="text" icon="mdi-heart" @click.stop.prevent="$emit('onFavoriteChanged')" v-if="image.isFavorite === 1"></v-btn>
<v-btn size="small" :disabled="!canEdit" :color="null" variant="text" icon="mdi-heart-outline" @click.stop.prevent="$emit('onFavoriteChanged')" v-else></v-btn>

<v-btn size="small" :disabled="!storeToken" color="blue" variant="text" icon="mdi-lock-open-variant" @click.stop.prevent="$emit('onPublicChanged')" v-if="image.isPublic === 1"></v-btn>
<v-btn size="small" :disabled="!storeToken" :color="null" variant="text" icon="mdi-lock" @click.stop.prevent="$emit('onPublicChanged')" v-else></v-btn>
<v-btn size="small" :disabled="!canEdit" color="blue" variant="text" icon="mdi-lock-open-variant" @click.stop.prevent="$emit('onPublicChanged')" v-if="image.isPublic === 1"></v-btn>
<v-btn size="small" :disabled="!canEdit" :color="null" variant="text" icon="mdi-lock" @click.stop.prevent="$emit('onPublicChanged')" v-else></v-btn>

<v-btn size="small" :color="null" variant="text" :icon="image.dataType === 'video' ? 'mdi-play' : 'mdi-magnify-plus'" @click.stop.prevent="overlay = true"></v-btn>

Expand Down Expand Up @@ -80,8 +82,12 @@ export default {
...mapGetters([
'storeBaseUrl',
'storeToken',
'storeUserPermissions',
'storeAccessToken'
]),
canEdit: function () {
return this.storeUserPermissions && this.storeUserPermissions['IMAGE_EDIT']
},
creationDate: function () {
let result = null
Expand Down
68 changes: 64 additions & 4 deletions src/components/ImageGallery.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,17 @@
density="compact" />
<v-spacer></v-spacer>
<v-btn-group density="compact" class="me-3">
<v-btn v-if="storeToken"
<v-btn v-if="canUpload"
@click="showImageUpload"
variant="tonal">
<v-icon>mdi-image-plus</v-icon>
</v-btn>
<v-btn v-if="canAddTag || canDelete"
:active="hasItemsSelected"
:color="hasItemsSelected ? 'primary' : null"
variant="tonal">
<v-icon>mdi-checkbox-multiple-marked-outline</v-icon> <span v-if="hasItemsSelected">{{ $t('widgetGallerySelectionCount', selectedItemCount) }}</span>
</v-btn>
<v-btn v-if="albumId"
@click="downloadAlbum"
:loading="downloadInProgress"
Expand Down Expand Up @@ -56,7 +62,9 @@
</v-col>

<v-col :cols="widths[cardSize].cols" :sm="widths[cardSize].sm" :md="widths[cardSize].md" :lg="widths[cardSize].lg" :xl="widths[cardSize].xl" :xxl="widths[cardSize].xxl" v-for="(image, index) in images" :key="`image-card-${image.id}`" v-else>
<ImageCard :height="heights[cardSize]" :image="image" @onPublicChanged="togglePublic(index)" @onFavoriteChanged="toggleFavorite(index)" />
<ImageCard :height="selectedItems[image.id] ? heightsSelected[cardSize] : heights[cardSize]" :image="image" @onPublicChanged="togglePublic(index)" @onFavoriteChanged="toggleFavorite(index)" :class="`position-relative image-card ${selectedItems[image.id] ? 'ma-2 selected' : null}`">
<v-checkbox v-model="selectedItems[image.id]" class="card-selection-button ma-2" v-if="canAddTag || canDelete" />
</ImageCard>
</v-col>
</v-row>

Expand Down Expand Up @@ -130,9 +138,24 @@ export default {
computed: {
...mapGetters([
'storeImagesPerPage',
'storeToken',
'storeUserPermissions',
'storeImageCardSize'
]),
hasItemsSelected: function () {
return Object.values(this.selectedItems).some(k => k)
},
selectedItemCount: function () {
return Object.values(this.selectedItems).filter(k => k).length
},
canUpload: function () {
return this.storeUserPermissions && this.storeUserPermissions['IMAGE_UPLOAD']
},
canDelete: function () {
return this.storeUserPermissions && this.storeUserPermissions['IMAGE_DELETE']
},
canAddTag: function () {
return this.storeUserPermissions && this.storeUserPermissions['TAG_ADD']
},
imageLocations: function () {
if (this.images) {
return this.images.filter(i => i.exif && i.exif.gpsLatitude && i.exif.gpsLongitude).map(i => {
Expand Down Expand Up @@ -216,11 +239,17 @@ export default {
ascending: 0,
cardSize: 'md',
downloadInProgress: false,
selectedItems: {},
heights: {
lg: 300,
md: 250,
sm: 200
},
heightsSelected: {
lg: 280,
md: 230,
sm: 180
},
widths: {
lg: {
xxl: 3,
Expand Down Expand Up @@ -250,6 +279,13 @@ export default {
}
},
methods: {
toggle: function (imageId) {
if (this.selectedItems[imageId]) {
delete this.selectedItems[imageId]
} else {
this.selectedItems[imageId] = true
}
},
setQuery: function (param, value) {
let query = {}
Expand Down Expand Up @@ -298,6 +334,10 @@ export default {
this.update()
},
update: function () {
const temp = {}
Object.keys(this.selectedItems).filter(k => this.selectedItems[k]).forEach(k => { temp[k] = true })
this.selectedItems = temp
this.getData({
page: this.page - 1,
limit: this.perPage,
Expand Down Expand Up @@ -337,4 +377,24 @@ export default {
this.update()
}
}
</script>
</script>

<style scoped>
.card-selection-button {
position: absolute;
top: 0;
right: 0;
}
.image-card .card-selection-button {
visibility: hidden;
}
.image-card:hover .card-selection-button {
visibility: initial;
}
.image-card.selected .card-selection-button {
visibility: initial;
}
</style>
3 changes: 2 additions & 1 deletion src/plugins/i18n/de_DE.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,5 +75,6 @@
"widgetTagsText": "Die folgenden Schlagwörter wurden mit diesem Element assoziiert. Klicke auf das Schlagwort um alle Bilder anzuzeigen die mit diesem Schlagwort assoziiert wurden. Klicke auf das x Symbol (falls vorhanden) um das Schlagwort zu entfernen.",
"widgetTagsNoData": "Kein Schlagwort gefunden",
"widgetCookieBannerText": "Frickl nutzt Cookies um das Anmelden und Benutzereinstellungen zu speichern.",
"widgetCookieBannerRejectTooltip": "Bitte beachten, dass das Ablehnen von Cookies bestimmte Funktionen von Frickl deaktiviert."
"widgetCookieBannerRejectTooltip": "Bitte beachten, dass das Ablehnen von Cookies bestimmte Funktionen von Frickl deaktiviert.",
"widgetGallerySelectionCount": "Keins ausgewählt|Eins ausgewählt|{count} ausgewählt"
}
3 changes: 2 additions & 1 deletion src/plugins/i18n/en_GB.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,5 +75,6 @@
"widgetTagsText": "The following tags have been associated with this item. Click on a tag to see all images associated with this tag. Click on the x icon (if available) to remove the tag.",
"widgetTagsNoData": "No tags found",
"widgetCookieBannerText": "Frickl uses cookies to facilitate user login and to remember user preferences.",
"widgetCookieBannerRejectTooltip": "Please be aware that rejecting cookies will disable certain features of Frickl."
"widgetCookieBannerRejectTooltip": "Please be aware that rejecting cookies will disable certain features of Frickl.",
"widgetGallerySelectionCount": "One selected|One selected|{count} selected"
}
12 changes: 12 additions & 0 deletions src/store/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { createStore } from 'vuex'
import createPersistedState from 'vuex-persistedstate'
import { bootstrap } from 'vue-gtag'
import { userHasPermission } from '@/plugins/misc'

let name = process.env.VUE_APP_INSTANCE_NAME

Expand Down Expand Up @@ -30,6 +31,17 @@ export default createStore({
storeAccessToken: (state) => state.accessToken,
storeBaseUrl: (state) => state.baseUrl,
storeToken: (state) => state.token,
storeUserPermissions: (state) => {
const result = {}

if (state.token && state.token.allPermissions && state.token.permissions) {
state.token.allPermissions.forEach(p => {
result[p.name] = userHasPermission(state.token.permissions, p.code)
})
}

return result
},
storeLocale: (state) => state.locale,
storeImagesPerPage: (state) => state.imagesPerPage,
storeAlbumsPerPage: (state) => state.albumsPerPage,
Expand Down
25 changes: 18 additions & 7 deletions src/views/ImageDetails.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@

<v-btn icon="mdi-download" :href="imgSrc['ORIGINAL']" :download="`${album.name}-${image.name}`" />

<v-btn color="red" icon="mdi-heart" :disabled="!storeToken" @click.stop.prevent="toggleFavorite" v-if="image.isFavorite === 1"></v-btn>
<v-btn color="null" icon="mdi-heart-outline" :disabled="!storeToken" @click.stop.prevent="toggleFavorite" v-else></v-btn>
<v-btn color="red" icon="mdi-heart" :disabled="!canEditImage" @click.stop.prevent="toggleFavorite" v-if="image.isFavorite === 1"></v-btn>
<v-btn color="null" icon="mdi-heart-outline" :disabled="!canEditImage" @click.stop.prevent="toggleFavorite" v-else></v-btn>

<v-btn color="blue" icon="mdi-lock-open-variant" :disabled="!storeToken" @click.stop.prevent="togglePublic" v-if="image.isPublic === 1"></v-btn>
<v-btn color="null" icon="mdi-lock" :disabled="!storeToken" @click.stop.prevent="togglePublic" v-else></v-btn>
<v-btn color="blue" icon="mdi-lock-open-variant" :disabled="!canEditImage" @click.stop.prevent="togglePublic" v-if="image.isPublic === 1"></v-btn>
<v-btn color="null" icon="mdi-lock" :disabled="!canEditImage" @click.stop.prevent="togglePublic" v-else></v-btn>
</v-toolbar>

<template v-if="image.dataType === 'image'">
Expand Down Expand Up @@ -143,10 +143,11 @@
<v-card-text>
<div v-if="tags && tags.length > 0">
<v-chip-group column>
<v-chip class="me-2 mb-2" :to="{ name: 'tag-specific', params: { tagId: tag.id } }" closable v-for="tag in tags" :key="`tag-${tag.id}`">
<v-chip label class="me-2 mb-2" :to="{ name: 'tag-specific', params: { tagId: tag.id } }" closable v-for="tag in tags" :key="`tag-${tag.id}`">
<template #close>
<v-icon icon="mdi-close-circle" @click.prevent.stop="askRemoveTag(tag)" v-if="storeToken" />
<v-icon icon="mdi-close-circle" @click.prevent.stop="askRemoveTag(tag)" v-if="canDeleteTags" />
</template>
<v-icon start icon="mdi-tag" />
{{ tag.name }}
</v-chip>
</v-chip-group>
Expand Down Expand Up @@ -203,8 +204,18 @@ export default {
'storeBaseUrl',
'storeToken',
'storeTheme',
'storeAccessToken'
'storeAccessToken',
'storeUserPermissions'
]),
canEditImage: function () {
return this.storeUserPermissions && this.storeUserPermissions['IMAGE_EDIT']
},
canDeleteTags: function () {
return this.storeUserPermissions && this.storeUserPermissions['TAG_DELETE']
},
canAddTags: function () {
return this.storeUserPermissions && this.storeUserPermissions['TAG_ADD']
},
date: function () {
if (this.image) {
if (this.image.exif) {
Expand Down
2 changes: 1 addition & 1 deletion src/views/StatisticsView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<v-divider class="mb-3" />

<v-chip-group v-model="selectedYear" column selected-class="text-primary">
<v-chip v-for="year in years" :key="`year-${year.year}`" filter>{{ year.year }} <v-badge :content="year.count" inline /></v-chip>
<v-chip label v-for="year in years" :key="`year-${year.year}`" filter>{{ year.year }} <v-badge :content="year.count" inline /></v-chip>
</v-chip-group>

<ImageHeatmapChart :chartData="chartData" v-if="chartData && chartData.length > 0" @date-selected="setDate" />
Expand Down
2 changes: 1 addition & 1 deletion src/views/Tags.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<v-divider class="mb-3" />

<v-chip-group v-model="selectedTag" column selected-class="text-primary">
<v-chip v-for="tag in tags" :key="`tag-${tag.id}`" filter>{{ tag.tag.name }} <v-badge :content="tag.count" inline /></v-chip>
<v-chip label v-for="tag in tags" :key="`tag-${tag.id}`" filter>{{ tag.tag.name }} <v-badge :content="tag.count" inline /></v-chip>
</v-chip-group>

<ImageGallery :getData="getImages" v-if="selectedTag !== null" ref="imageGallery" />
Expand Down

0 comments on commit 9e1caf1

Please sign in to comment.