view client/src/components/systemconfiguration/PDFTemplates.vue @ 3608:f96def15847e

client: configuration: pdf templates: adjusted padding
author Markus Kottlaender <markus@intevation.de>
date Wed, 05 Jun 2019 12:11:35 +0200
parents d1bbfb9635ca
children 851c0ccba59b
line wrap: on
line source

<template>
  <div class="d-flex flex-column pb-4 border-bottom">
    <h5 class="py-2 px-3 m-0"><translate>PDF-Templates</translate></h5>
    <input
      @change="uploadTemplate"
      id="uploadTemplate"
      ref="uploadTemplate"
      type="file"
      style="visibility: hidden; position: absolute;"
    />
    <UITableHeader
      :columns="[
        { id: 'name', title: `${nameLabel}`, class: 'col-3' },
        { id: 'time', title: `${dateLabel}`, class: 'col-3' },
        { id: 'type', title: `${typeLabel}`, class: 'col-2' },
        { id: 'country', title: `${countryLabel}`, class: 'col-2' }
      ]"
    />
    <UITableBody :data="templates | sortTable(sortColumn, sortDirection)">
      <template v-slot:row="{ item: template }">
        <div class="py-1 col-3">{{ template.name }}</div>
        <div class="py-1 col-3">{{ template.time }}</div>
        <div class="py-1 col-2">{{ template.type }}</div>
        <div class="py-1 col-2" v-if="template.country">
          {{ template.country }}
        </div>
        <div class="py-1 col-2" v-else><i>global</i></div>
        <div class="col py-1 text-right">
          <button
            class="btn btn-xs btn-info mr-1"
            ref="downloadTemplate"
            @click="downloadTemplate(template)"
          >
            <font-awesome-icon icon="download" fixed-width />
          </button>
          <button class="btn btn-xs btn-dark" @click="deleteTemplate(template)">
            <font-awesome-icon icon="trash" fixed-width />
          </button>
        </div>
      </template>
    </UITableBody>
    <div class="px-3 mt-2">
      <button
        class="btn btn-info btn-sm mr-2"
        @click="
          type = 'map';
          $refs.uploadTemplate.click();
        "
      >
        <font-awesome-icon
          icon="spinner"
          class="fa-spin fa-fw"
          v-if="uploading"
        />
        <font-awesome-icon icon="upload" class="fa-fw" v-else />
        <translate>Upload new map template</translate>
      </button>
      <button
        class="btn btn-info btn-sm"
        @click="
          type = 'diagram';
          $refs.uploadTemplate.click();
        "
      >
        <font-awesome-icon
          icon="spinner"
          class="fa-spin fa-fw"
          v-if="uploading"
        />
        <font-awesome-icon icon="upload" class="fa-fw" v-else />
        <translate>Upload new diagram template</translate>
      </button>
    </div>
  </div>
</template>

<style lang="scss" scoped>
.table th,
td {
  font-size: $smaller;
  border-top: 0px !important;
  text-align: left;
  padding: $small-offset !important;
}
</style>

<script>
/* This is Free Software under GNU Affero General Public License v >= 3.0
 * without warranty, see README.md and license for details.
 *
 * SPDX-License-Identifier: AGPL-3.0-or-later
 * License-Filename: LICENSES/AGPL-3.0.txt
 *
 * Copyright (C) 2018, 2019 by via donau
 *   – Österreichische Wasserstraßen-Gesellschaft mbH
 * Software engineering by Intevation GmbH
 *
 * Author(s):
 * Markus Kottländer <markus@intevation.de>
 * Fadi Abbud <fadi.abbud@intevation.de>
 */
import { HTTP } from "@/lib/http";
import { displayError, displayInfo } from "@/lib/errors";
import { sortTable } from "@/lib/mixins";

export default {
  name: "pdftemplates",
  mixins: [sortTable],
  data() {
    return {
      templates: [],
      uploading: false,
      type: null
    };
  },
  computed: {
    nameLabel() {
      return this.$gettext("Name");
    },
    dateLabel() {
      return this.$gettext("Date");
    },
    countryLabel() {
      return this.$gettext("Country");
    },
    typeLabel() {
      return this.$gettext("Type");
    }
  },
  methods: {
    downloadTemplate(template) {
      if (template) {
        var templateData = "";
        var element = document.createElement("a");
        element.style.display = "none";
        element.setAttribute("download", template.name + ".json");
        document.body.appendChild(element);
        HTTP.get(`/templates/${template.type}/${template.name}`, {
          headers: {
            "X-Gemma-Auth": localStorage.getItem("token"),
            "Content-type": "text/xml; charset=UTF-8"
          }
        })
          .then(response => {
            templateData = response.data.template_data;
            element.setAttribute(
              "href",
              "data:text/json;charset=utf-8," +
                encodeURIComponent(
                  JSON.stringify(
                    {
                      name: templateData.name,
                      properties: templateData.properties,
                      elements: templateData.elements
                    },
                    null,
                    2
                  )
                )
            );
            element.click();
          })
          .catch(e => {
            const { status, data } = e.response;
            displayError({
              title: this.$gettext("Backend Error"),
              message: `${status}: ${data.message || data}`
            });
          })
          .finally(() => {
            document.body.removeChild(element);
          });
      }
    },
    uploadTemplate() {
      const reader = new FileReader();
      reader.onload = event => {
        let template;
        try {
          template = JSON.parse(event.target.result);
        } catch (e) {
          displayError({
            title: this.$gettext("Format Error"),
            message: this.$gettext(
              "Uploaded file does not contain valid json data."
            )
          });
          // allow the user to upload the same file
          // if user wants to upload the same file after edit it.
          this.$refs.uploadTemplate.value = null;
        }
        if (template.name) {
          // check if an element in the uploaded file does not match the predefind template-elements
          let checkElement = false;
          template.elements.forEach(e => {
            if (
              [
                "text",
                "box",
                "textbox",
                "image",
                "bottleneck",
                "legend",
                "scalebar",
                "scale",
                "northarrow",
                "diagramlegend",
                "diagramtitle",
                "diagram"
              ].indexOf(e.type) === -1
            ) {
              checkElement = true;
              displayError({
                title: this.$gettext("Invalid element"),
                message:
                  e.type +
                  this.$gettext(" does not match any template's element")
              });
              // allow the user to upload the same file
              this.$refs.uploadTemplate.value = null;
            }
          });

          if (!checkElement) {
            this.uploading = true;
            HTTP.post(
              "/templates/" + this.type + "/" + template.name,
              {
                template_name: template.name,
                template_data: template
              },
              {
                headers: {
                  "X-Gemma-Auth": localStorage.getItem("token"),
                  "Content-type": "text/xml; charset=UTF-8"
                }
              }
            )
              .then(() => {
                this.loadTemplates();
                displayInfo({
                  message:
                    template.name + " " + this.$gettext("uploaded successfully")
                });
              })
              .catch(e => {
                const { status, data } = e.response;
                if (status === 400) {
                  displayError({
                    title: this.$gettext("Error"),
                    message: `${data.message || data}`
                  });
                } else {
                  displayError({
                    title: this.$gettext("Backend Error"),
                    message: `${status}: ${data.message || data}`
                  });
                }
              })
              .finally(() => {
                this.uploading = false;
                this.$refs.uploadTemplate.value = null;
              });
          }
        } else {
          displayError({
            title: this.$gettext("Format Error"),
            message: this.$gettext(
              "The provided template has no name property."
            )
          });
          // allow the user to upload the same file
          this.$refs.uploadTemplate.value = null;
        }
      };

      reader.onerror = error => console.log(error);
      reader.readAsText(this.$refs.uploadTemplate.files[0]);
    },
    loadTemplates() {
      HTTP.get("/templates", {
        headers: {
          "X-Gemma-Auth": localStorage.getItem("token"),
          "Content-type": "text/xml; charset=UTF-8"
        }
      })
        .then(response => {
          this.templates = response.data;
        })
        .catch(e => {
          const { status, data } = e.response;
          displayError({
            title: this.$gettext("Backend Error"),
            message: `${status}: ${data.message || data}`
          });
        });
    },
    deleteTemplate(template) {
      this.$store.commit("application/popup", {
        icon: "trash",
        title: this.$gettext("Delete Template"),
        content:
          this.$gettext(
            "Do you really want to delete the following template:"
          ) +
          `<br>
        <b>${template.name}</b>`,
        confirm: {
          label: this.$gettext("Delete"),
          icon: "trash",
          callback: () => {
            HTTP.delete(`/templates/${template.type}/${template.name}`, {
              headers: {
                "X-Gemma-Auth": localStorage.getItem("token"),
                "Content-type": "text/xml; charset=UTF-8"
              }
            }).then(() => {
              let removeIndex = this.templates.findIndex(
                t => t.name === template.name
              );
              if (removeIndex !== -1) {
                this.templates.splice(removeIndex, 1);
                displayInfo({
                  message:
                    template.name + " " + this.$gettext("deleted successfully")
                });
              }
            });
          }
        },
        cancel: {
          label: this.$gettext("Cancel"),
          icon: "times"
        }
      });
    }
  },
  mounted() {
    this.loadTemplates();
  }
};
</script>