facilmap/frontend/src/lib/components/pad-settings-dialog/pad-settings-dialog.vue

257 wiersze
7.8 KiB
Vue
Czysty Zwykły widok Historia

2023-09-12 09:15:28 +00:00
<script setup lang="ts">
2023-10-06 23:13:51 +00:00
import { computed, ref, watch } from "vue";
2023-11-02 14:14:05 +00:00
import type { CRU, PadData } from "facilmap-types";
2023-11-07 01:19:20 +00:00
import { generateRandomPadId } from "facilmap-utils";
2023-09-12 09:15:28 +00:00
import { getUniqueId, mergeObject } from "../../utils/utils";
2023-11-07 01:19:20 +00:00
import { cloneDeep, isEqual } from "lodash-es";
2023-10-30 00:14:54 +00:00
import ModalDialog from "../ui/modal-dialog.vue";
import { useToasts } from "../ui/toasts/toasts.vue";
2023-10-06 23:13:51 +00:00
import { showConfirm } from "../ui/alert.vue";
import PadIdEdit from "./pad-id-edit.vue";
2023-11-06 02:22:33 +00:00
import { injectContextRequired, requireClientContext } from "../facil-map-context-provider/facil-map-context-provider.vue";
2023-09-12 09:15:28 +00:00
const context = injectContextRequired();
2023-11-06 02:22:33 +00:00
const client = requireClientContext(context);
2023-09-12 09:15:28 +00:00
2023-10-30 00:14:54 +00:00
const toasts = useToasts();
2023-09-12 09:15:28 +00:00
const props = defineProps<{
proposedAdminId?: string;
noCancel?: boolean;
isCreate?: boolean;
}>();
const emit = defineEmits<{
2023-11-01 18:45:16 +00:00
hidden: [];
2023-09-12 09:15:28 +00:00
}>();
2023-10-06 23:13:51 +00:00
const id = getUniqueId("fm-pad-settings");
2023-09-12 09:15:28 +00:00
const isDeleting = ref(false);
const deleteConfirmation = ref("");
2023-11-07 01:19:20 +00:00
const initialPadData: PadData<CRU.CREATE> | undefined = props.isCreate ? {
2023-10-06 23:13:51 +00:00
name: "New FacilMap",
searchEngines: false,
description: "",
clusterMarkers: false,
adminId: (props.proposedAdminId || generateRandomPadId(16)),
writeId: generateRandomPadId(14),
id: generateRandomPadId(12),
legend1: "",
legend2: "",
defaultViewId: null
2023-11-07 01:19:20 +00:00
} : undefined;
const originalPadData = computed(() => props.isCreate ? initialPadData! : client.value.padData as PadData<CRU.CREATE>);
const padData = ref(cloneDeep(originalPadData.value));
2023-10-06 23:13:51 +00:00
2023-11-01 18:45:16 +00:00
const modalRef = ref<InstanceType<typeof ModalDialog>>();
2023-09-12 09:15:28 +00:00
2023-11-07 01:19:20 +00:00
const isModified = computed(() => !isEqual(padData.value, originalPadData.value));
2023-09-12 09:15:28 +00:00
2023-11-06 02:22:33 +00:00
watch(() => client.value.padData, (newPadData, oldPadData) => {
2023-10-06 23:13:51 +00:00
if (!props.isCreate && padData.value && newPadData)
mergeObject(oldPadData, newPadData, padData.value as PadData);
2023-09-12 09:15:28 +00:00
}, { deep: true });
async function save(): Promise<void> {
2023-10-30 00:14:54 +00:00
toasts.hideToast(`fm${context.id}-pad-settings-error`);
2023-09-12 09:15:28 +00:00
try {
if(props.isCreate)
2023-11-06 02:22:33 +00:00
await client.value.createPad(padData.value as PadData<CRU.CREATE>);
2023-09-12 09:15:28 +00:00
else
2023-11-06 02:22:33 +00:00
await client.value.editPad(padData.value);
2023-11-01 18:45:16 +00:00
modalRef.value?.modal.hide();
2023-09-12 09:15:28 +00:00
} catch (err) {
2023-10-30 00:14:54 +00:00
toasts.showErrorToast(`fm${context.id}-pad-settings-error`, props.isCreate ? "Error creating map" : "Error saving map settings", err);
2023-09-12 09:15:28 +00:00
}
};
2021-03-04 15:45:34 +00:00
2023-09-12 09:15:28 +00:00
async function deletePad(): Promise<void> {
2023-10-30 00:14:54 +00:00
toasts.hideToast(`fm${context.id}-pad-settings-error`);
2023-09-12 09:15:28 +00:00
if (!await showConfirm({
title: "Delete map",
message: `Are you sure you want to delete the map “${padData.value.name}”? Deleted maps cannot be restored!`,
variant: "danger"
})) {
return;
}
isDeleting.value = true;
try {
2023-11-06 02:22:33 +00:00
await client.value.deletePad();
2023-11-01 18:45:16 +00:00
modalRef.value?.modal.hide();
2023-09-12 09:15:28 +00:00
} catch (err) {
2023-10-30 00:14:54 +00:00
toasts.showErrorToast(`fm${context.id}-pad-settings-error`, "Error deleting map", err);
2023-09-12 09:15:28 +00:00
} finally {
isDeleting.value = false;
}
};
</script>
<template>
2023-10-30 00:14:54 +00:00
<ModalDialog
2023-11-07 01:19:20 +00:00
:title="props.isCreate ? 'Create collaborative map' : 'Map settings'"
2023-10-30 00:14:54 +00:00
class="fm-pad-settings"
2023-11-07 01:19:20 +00:00
:noCancel="props.noCancel"
2023-11-01 18:45:16 +00:00
:isBusy="isDeleting"
2023-11-07 01:19:20 +00:00
:isCreate="props.isCreate"
2023-11-01 18:45:16 +00:00
:isModified="isModified"
2023-11-07 01:19:20 +00:00
:okLabel="props.isCreate ? 'Create' : undefined"
2023-11-01 18:45:16 +00:00
ref="modalRef"
2023-10-30 00:14:54 +00:00
@submit="$event.waitUntil(save())"
2023-11-01 18:45:16 +00:00
@hidden="emit('hidden')"
2023-10-06 23:13:51 +00:00
>
<template v-if="padData">
<PadIdEdit
:padData="padData"
idProp="adminId"
2023-11-01 18:45:16 +00:00
v-model="padData.adminId"
2023-10-06 23:13:51 +00:00
label="Admin link"
description="When opening the map through this link, all parts of the map can be edited, including the map settings, object types and views."
></PadIdEdit>
<PadIdEdit
:padData="padData"
idProp="writeId"
2023-11-01 18:45:16 +00:00
v-model="padData.writeId"
2023-10-06 23:13:51 +00:00
label="Editable link"
description="When opening the map through this link, markers and lines can be added, changed and deleted, but the map settings, object types and views cannot be modified."
></PadIdEdit>
<PadIdEdit
:padData="padData"
idProp="id"
2023-11-01 18:45:16 +00:00
v-model="padData.id"
2023-10-06 23:13:51 +00:00
label="Read-only link"
description="When opening the map through this link, markers, lines and views can be seen, but nothing can be changed."
></PadIdEdit>
<div class="row mb-3">
<label :for="`${id}-pad-name-input`" class="col-sm-3 col-form-label">Map name</label>
<div class="col-sm-9">
2023-11-07 01:19:20 +00:00
<input
:id="`${id}-pad-name-input`"
class="form-control"
type="text"
v-model="padData.name"
/>
2023-10-06 23:13:51 +00:00
</div>
</div>
<div class="row mb-3">
<label :for="`${id}-search-engines-input`" class="col-sm-3 col-form-label">Search engines</label>
<div class="col-sm-9">
2023-11-07 01:19:20 +00:00
<div class="form-check fm-form-check-with-label">
<input
:id="`${id}-search-engines-input`"
class="form-check-input"
type="checkbox"
v-model="padData.searchEngines"
/>
<label :for="`${id}-search-engines-input`" class="form-check-label">
Accessible for search engines
</label>
</div>
2023-10-06 23:13:51 +00:00
<div class="form-text">
2023-09-12 09:15:28 +00:00
If this is enabled, search engines like Google will be allowed to add the read-only version of this map.
2023-10-06 23:13:51 +00:00
</div>
</div>
</div>
<div class="row mb-3">
<label :for="`${id}-description-input`" class="col-sm-3 col-form-label">Short description</label>
<div class="col-sm-9">
2023-11-07 01:19:20 +00:00
<input
:id="`${id}-description-input`"
class="form-control"
type="text"
v-model="padData.description"
/>
2023-10-06 23:13:51 +00:00
<div class="form-text">
2023-09-12 09:15:28 +00:00
This description will be shown under the result in search engines.
2023-10-06 23:13:51 +00:00
</div>
</div>
</div>
<div class="row mb-3">
<label :for="`${id}-cluster-markers-input`" class="col-sm-3 col-form-label">Search engines</label>
<div class="col-sm-9">
2023-11-07 01:19:20 +00:00
<div class="form-check fm-form-check-with-label">
<input
:id="`${id}-cluster-markers-input`"
class="form-check-input"
type="checkbox"
v-model="padData.clusterMarkers"
/>
<label :for="`${id}-cluster-markers-input`" class="form-check-label">
Cluster markers
</label>
</div>
2023-10-06 23:13:51 +00:00
<div class="form-text">
2023-09-12 09:15:28 +00:00
If enabled, when there are many markers in one area, they will be replaced by a placeholder at low zoom levels. This improves performance on maps with many markers.
2023-10-06 23:13:51 +00:00
</div>
</div>
</div>
<div class="row mb-3">
<label :for="`${id}-legend1-input`" class="col-sm-3 col-form-label">Legend text</label>
<div class="col-sm-9">
2023-11-07 01:19:20 +00:00
<textarea
:id="`${id}-legend1-input`"
class="form-control"
type="text"
v-model="padData.legend1"
></textarea>
<textarea
:id="`${id}-legend2-input`"
class="form-control mt-1"
type="text"
v-model="padData.legend2"
></textarea>
2023-10-06 23:13:51 +00:00
<div class="form-text">
2023-09-12 09:15:28 +00:00
Text that will be shown above and below the legend. Can be formatted with <a href="http://commonmark.org/help/" target="_blank">Markdown</a>.
2023-10-06 23:13:51 +00:00
</div>
</div>
</div>
</template>
2023-11-07 01:19:20 +00:00
<template v-if="padData && !props.isCreate">
2023-10-06 23:13:51 +00:00
<hr/>
<div class="row mb-3">
<label :for="`${id}-delete-input`" class="col-sm-3 col-form-label">Delete map</label>
<div class="col-sm-9">
<div class="input-group">
2023-11-07 01:19:20 +00:00
<input
:form="`${id}-delete-form`"
:id="`${id}-delete-input`"
class="form-control"
type="text"
v-model="deleteConfirmation"
/>
<button
:form="`${id}-delete-form`"
class="btn btn-danger"
type="submit"
:disabled="isDeleting || modalRef?.formData?.isSubmitting || deleteConfirmation != 'DELETE'"
>
2023-10-06 23:13:51 +00:00
<div v-if="isDeleting" class="spinner-border spinner-border-sm"></div>
Delete map
</button>
</div>
<div class="form-text">
To delete this map, type <code>DELETE</code> into the field and click the Delete map button.
</div>
</div>
</div>
</template>
2023-10-30 00:14:54 +00:00
</ModalDialog>
2023-10-06 23:13:51 +00:00
<form :id="`${id}-delete-form`" @submit.prevent="deleteConfirmation == 'DELETE' && deletePad()">
</form>
</template>