Fix app links icon upload

This commit is contained in:
Girish Ramakrishnan
2025-09-11 16:34:10 +02:00
parent 23012fbb5c
commit f8015c156e
4 changed files with 37 additions and 48 deletions
+6 -27
View File
@@ -7,6 +7,7 @@ const t = i18n.t;
import { computed, ref, useTemplateRef } from 'vue';
import { Dialog, FormGroup, InputDialog, MultiSelect, Radiobutton, TagInput, TextInput } from '@cloudron/pankow';
import { API_ORIGIN } from '../constants.js';
import { getDataURLFromFile } from '../utils.js';
import ImagePicker from './ImagePicker.vue';
import ApplinksModel from '../models/ApplinksModel.js';
import UsersModel from '../models/UsersModel.js';
@@ -30,7 +31,7 @@ const id = ref('');
const upstreamUri = ref('');
const label = ref('');
const tags = ref([]);
const iconFile = ref(null); // if set to '' we will reset
const iconFile = ref(null);
const iconUrl = ref('');
const accessRestrictionOption = ref('');
const accessRestriction = ref({
@@ -52,30 +53,10 @@ const isValid = computed(() => {
return true;
});
function getDataURLFromFile(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = function(event) {
resolve(event.target.result);
};
reader.onerror = function(event) {
reject(event.target.error);
};
reader.readAsDataURL(file);
});
}
function onIconChanged(file) {
iconFile.value = file;
}
function onResetIcon() {
iconFile.value = '';
}
async function onSubmit() {
busy.value = true;
@@ -92,9 +73,9 @@ async function onSubmit() {
data.accessRestriction.groups = accessRestriction.value.groups.map(function (g) { return g.id; });
}
if (iconFile.value === '') { // user reset the icon
if (iconFile.value === 'fallback') { // user reset the icon
data.icon = '';
} else if (iconFile.value) { // user loaded custom icon
} else if (iconFile.value !== 'src') { // user loaded custom icon
data.icon = (await getDataURLFromFile(iconFile.value)).replace(/^data:image\/[a-z]+;base64,/, '');
}
@@ -110,8 +91,6 @@ async function onSubmit() {
emits('success');
applinkDialog.value.close();
// clear this to retrigger ImagePicker loading
iconUrl.value = '';
busy.value = false;
}
@@ -139,7 +118,7 @@ defineExpose({
upstreamUri.value = applink ? applink.upstreamUri : '';
label.value = applink ? applink.label : '';
iconUrl.value = applink ? applink.iconUrl : 'fallback';
iconFile.value = null;
iconFile.value = applink?.iconUrl ? 'src' : 'fallback';
tags.value = applink ? applink.tags : [];
accessRestrictionOption.value = applink && applink.accessRestriction ? 'groups' : 'any';
accessRestriction.value = applink && applink.accessRestriction ? applink.accessRestriction : { users: [], groups: [] };
@@ -193,7 +172,7 @@ defineExpose({
<div>
<label for="previewIcon">{{ $t('app.display.icon') }}</label>
<ImagePicker ref="imagePicker" mode="simple" v-if="iconUrl" :src="iconUrl" :fallback-src="`${API_ORIGIN}/img/appicon_fallback.png`" :unset-handler="mode === 'new' ? null : onResetIcon" @changed="onIconChanged" size="512" display-height="80px" style="width: 80px"/>
<ImagePicker ref="imagePicker" mode="simple" :src="iconUrl" :fallback-src="`${API_ORIGIN}/img/appicon_fallback.png`" @changed="onIconChanged" size="512" display-height="80px" style="width: 80px"/>
</div>
<FormGroup>
+12 -5
View File
@@ -28,6 +28,7 @@ const busy = ref(false);
watchEffect(() => {
internalSrc.value = props.src;
isChanged.value = false;
});
function dataURLtoFile(dataURL, filename) {
@@ -70,6 +71,7 @@ async function onSave() {
function onCancel() {
internalSrc.value = props.src || props.fallbackSrc;
isChanged.value = false;
emit('changed', 'src');
}
function onEdit() {
@@ -77,14 +79,17 @@ function onEdit() {
}
async function onUnset() {
if (typeof props.unsetHandler !== 'function') return;
busy.value = true;
const error = await props.unsetHandler();
if (!error) isChanged.value = false;
if (typeof props.unsetHandler === 'function') {
const error = await props.unsetHandler();
if (!error) isChanged.value = false;
} else {
isChanged.value = false;
}
internalSrc.value = props.fallbackSrc;
emit('changed', 'fallback');
busy.value = false;
}
@@ -142,7 +147,7 @@ function onChanged(event) {
internalSrc.value = canvas.toDataURL('image/png');
isChanged.value = true;
emit('changed', file); // <— notify parent
emit('changed', file);
};
image.src = fr.result;
@@ -178,6 +183,8 @@ function onError() {
<template v-else-if="mode === 'simple'">
<div class="image-picker-actions">
<Button @click.stop="onEdit" tool small icon="fa fa-pencil-alt" :disabled="busy"/>
<Button v-if="isChanged" @click.stop="onCancel" secondary tool small icon="fa fa-undo" :disabled="busy"/>
<Button v-else-if="internalSrc !== fallbackSrc" @click.stop="onUnset" tool small icon="fa fa-trash" :loading="busy" :disabled="busy"/>
</div>
</template>
</div>
+1 -16
View File
@@ -5,6 +5,7 @@ import { FormGroup, TextInput, Button, TagInput } from '@cloudron/pankow';
import ImagePicker from '../ImagePicker.vue';
import AppsModel from '../../models/AppsModel.js';
import { API_ORIGIN } from '../../constants.js';
import { getDataURLFromFile } from '../../utils.js';
const props = defineProps([ 'app' ]);
@@ -19,22 +20,6 @@ const label = ref('');
const tags = ref([]);
const iconUrl = ref('');
function getDataURLFromFile(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = function(event) {
resolve(event.target.result);
};
reader.onerror = function(event) {
reject(event.target.error);
};
reader.readAsDataURL(file);
});
}
const haveValuesChanged = computed(() => {
return (label.value !== props.app.label) || tags.value.join() !== props.app.tags.join();
});