Fix app links icon upload
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user