2025-03-01 11:44:38 +01:00
< script setup >
import { ref , onMounted , useTemplateRef } from 'vue' ;
import { FormGroup , TextInput , Button , TagInput } from 'pankow' ;
2025-03-19 01:09:17 +01:00
import ImagePicker from '../ImagePicker.vue' ;
2025-03-01 11:44:38 +01:00
import AppsModel from '../../models/AppsModel.js' ;
2025-05-20 14:48:18 +02:00
import { API _ORIGIN } from '../../constants.js' ;
2025-03-01 11:44:38 +01:00
const props = defineProps ( [ 'app' ] ) ;
const appsModel = AppsModel . create ( ) ;
2025-03-19 01:09:17 +01:00
const imagePicker = useTemplateRef ( 'imagePicker' ) ;
2025-03-01 11:44:38 +01:00
const busy = ref ( false ) ;
const labelError = ref ( '' ) ;
const tagsError = ref ( '' ) ;
const iconError = ref ( '' ) ;
const label = ref ( '' ) ;
const tags = ref ( [ ] ) ;
const iconUrl = ref ( '' ) ;
2025-03-19 01:09:17 +01:00
function getDataURLFromFile ( file ) {
return new Promise ( ( resolve , reject ) => {
const reader = new FileReader ( ) ;
2025-03-01 11:44:38 +01:00
2025-03-19 01:09:17 +01:00
reader . onload = function ( event ) {
resolve ( event . target . result ) ;
2025-03-01 11:44:38 +01:00
} ;
2025-03-19 01:09:17 +01:00
reader . onerror = function ( event ) {
reject ( event . target . error ) ;
} ;
reader . readAsDataURL ( file ) ;
} ) ;
2025-03-01 11:44:38 +01:00
}
async function onSubmit ( ) {
busy . value = true ;
labelError . value = '' ;
tagsError . value = '' ;
iconError . value = '' ;
if ( label . value !== props . app . label ) {
const [ error ] = await appsModel . configure ( props . app . id , 'label' , { label : label . value } ) ;
if ( error ) {
labelError . value = error . body ? error . body . message : 'Internal error' ;
busy . value = false ;
return console . error ( error ) ;
}
}
if ( tags . value . join ( ) !== props . app . tags . join ( ) ) {
const [ error ] = await appsModel . configure ( props . app . id , 'tags' , { tags : tags . value } ) ;
if ( error ) {
tagsError . value = error . body ? error . body . message : 'Internal error' ;
busy . value = false ;
return console . error ( error ) ;
}
}
2025-05-20 14:48:18 +02:00
busy . value = false ;
}
2025-03-01 11:44:38 +01:00
2025-05-20 14:48:18 +02:00
async function onIconSubmit ( icon ) {
const tmp = ( await getDataURLFromFile ( icon ) ) . replace ( /^data:image\/[a-z]+;base64,/ , '' ) ;
const [ error ] = await appsModel . configure ( props . app . id , 'icon' , { icon : tmp } ) ;
if ( error ) {
iconError . value = error . body ? error . body . message : 'Internal error' ;
return error ;
2025-03-01 11:44:38 +01:00
}
}
2025-05-20 14:48:18 +02:00
async function onIconUnset ( ) {
const [ error ] = await appsModel . configure ( props . app . id , 'icon' , { icon : '' } ) ;
if ( error ) {
iconError . value = error . body ? error . body . message : 'Internal error' ;
return error ;
}
iconUrl . value = props . app . iconUrl ? ` ${ API _ORIGIN } /api/v1/apps/ ${ props . app . id } /icon?ts= ${ Date . now ( ) } ` : ` ${ API _ORIGIN } /img/appicon_fallback.png ` ; // calculate full icon url with cache busting
2025-03-19 01:09:17 +01:00
}
2025-03-01 11:44:38 +01:00
onMounted ( ( ) => {
label . value = props . app . label ;
tags . value = props . app . tags ;
iconUrl . value = props . app . iconUrl ;
} ) ;
< / script >
< template >
< div >
2025-05-20 14:48:18 +02:00
< div style = "display: inline-block;" >
< label > { { $t ( 'app.display.icon' ) } } < / label >
< ImagePicker ref = "imagePicker" :src = "iconUrl" fallback -src = " / img / appicon_fallback.png " :save-handler = "onIconSubmit" :unset-handler = "onIconUnset" :size = "512" display -height = " 128px " / >
< / div >
2025-03-01 11:44:38 +01:00
< form @submit.prevent ="onSubmit()" autocomplete = "off" >
< fieldset :disabled = "busy" >
< input type = "submit" style = "display: none;" / >
< FormGroup >
< label for = "labelInput" > { { $t ( 'app.display.label' ) } } < / label >
< TextInput id = "labelInput" v-model = "label" />
< div class = "text-error" v-if = "labelError" > {{ labelError }} < / div >
< / FormGroup >
< FormGroup >
< label for = "tagsInput" > { { $t ( 'app.display.tags' ) } } < / label >
< TagInput id = "tagsInput" :placeholder = "$t('app.display.tagsPlaceholder')" v-model = "tags" v-tooltip="$t('app.display.tagsTooltip')" />
< div class = "text-error" v-if = "tagsError" > {{ tagsError }} < / div >
< / FormGroup >
2025-05-20 14:48:18 +02:00
< Button @click ="onSubmit()" :loading = "busy" :disabled = "busy" > { { $t ( 'app.display.saveAction' ) } } < / Button >
2025-03-01 11:44:38 +01:00
< / fieldset >
< / form >
< / div >
< / template >