view client/src/components/Importqueue.vue @ 1558:0ded4c56978e

refac: component filestructure. remove admin/map hierarchy
author Thomas Junk <thomas.junk@intevation.de>
date Wed, 12 Dec 2018 09:22:20 +0100
parents client/src/components/admin/Importqueue.vue@a3c2b192daa2
children
line wrap: on
line source

<template>
  <div class="d-flex flex-row">
    <div :class="spacerStyle"></div>
    <div class="mt-3 importqueuecard flex-grow-1">
      <div class="card shadow-xs">
        <h6
          class="mb-0 py-2 px-3 border-bottom d-flex text-info align-items-center"
        >
          <font-awesome-icon icon="tasks" class="mr-2"></font-awesome-icon>
          <translate class="headline">Importqueue</translate>
        </h6>
        <div class="card-body importcardbody">
          <div class="card-body importcardbody">
            <div class="searchandfilter d-flex flex-row">
              <div class="searchgroup input-group">
                <div class="input-group-prepend">
                  <span class="input-group-text" id="search">
                    <font-awesome-icon icon="search"></font-awesome-icon>
                  </span>
                </div>
                <input
                  v-model="searchQuery"
                  type="text"
                  class="form-control"
                  placeholder
                  aria-label="Search"
                  aria-describedby="search"
                />
              </div>
              <div class="filters">
                <button
                  @click="setFilter('successful')"
                  :class="successfulStyle"
                >
                  <translate>Successful</translate>
                </button>
                <button @click="setFilter('failed')" :class="failedStyle">
                  <translate>Failed</translate>
                </button>
                <button @click="setFilter('pending')" :class="pendingStyle">
                  <translate>Pending</translate>
                </button>
                <button @click="setFilter('rejected')" :class="rejectedStyle">
                  <translate>Rejected</translate>
                </button>
                <button @click="setFilter('accepted')" :class="acceptedStyle">
                  <translate>Accepted</translate>
                </button>
              </div>
            </div>
            <div class="text-left d-flex flex-row w-50 border-bottom">
              <div class="header py-1 jobid mr-2">
                <translate>Id</translate>
              </div>
              <div class="header py-1 enqueued mr-2">
                <translate>Enqueued</translate>
              </div>
              <div class="header py-1 kind mr-2">
                <translate>Kind</translate>
              </div>
              <div class="header py-1 user mr-2">
                <translate>User</translate>
              </div>
              <div class="header py-1 signer mr-2">
                <translate>Signer</translate>
              </div>
              <div class="header py-1 state mr-2">
                <translate>State</translate>
              </div>
            </div>
            <div class="text-left" v-for="job in filteredImports" :key="job.id">
              <Importqueuedetail :job="job"></Importqueuedetail>
            </div>
            <div>
              <button @click="refresh" class="btn btn-info refresh">
                <translate>Refresh</translate>
              </button>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<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 by via donau
 *   – Österreichische Wasserstraßen-Gesellschaft mbH
 * Software engineering by Intevation GmbH
 *
 * Author(s):
 * Markus Kottländer <markus@intevation.de>
 */
import { displayError } from "../lib/errors.js";
import { mapState } from "vuex";
import { HTTP } from "../lib/http.js";
import Importqueuedetail from "./Importqueuedetail";

export default {
  name: "importqueue",
  components: {
    Importqueuedetail
  },
  data() {
    return {
      searchQuery: "",
      successful: false,
      failed: false,
      pending: false,
      rejected: false,
      accepted: false
    };
  },
  mounted() {
    this.loadQueue();
  },
  methods: {
    setFilter(name) {
      this[name] = !this[name];
      const allSet =
        this.successful &&
        this.failed &&
        this.pending &&
        this.accepted &&
        this.rejected;
      if (allSet) {
        this.successful = false;
        this.failed = false;
        this.pending = false;
        this.accepted = false;
        this.rejected = false;
      }
    },
    loadQueue() {
      this.$store.dispatch("imports/getImports").catch(error => {
        const { status, data } = error.response;
        displayError({
          title: this.$gettext("Backend Error"),
          message: `${status}: ${data.message || data}`
        });
      });
    },
    refresh() {
      this.loadQueue();
    },
    showDetails(id) {
      HTTP.get("/imports/" + id, {
        headers: { "X-Gemma-Auth": localStorage.getItem("token") }
      })
        .then(response => {
          const { entries } = response.data;
          this.entries = entries;
          this.$modal.show("details");
        })
        .catch(error => {
          const { status, data } = error.response;
          displayError({
            title: this.$gettext("Backend Error"),
            message: `${status}: ${data.message || data}`
          });
        });
    },
    close() {
      this.$modal.hide("details");
    }
  },
  computed: {
    ...mapState("imports", ["imports"]),
    ...mapState("application", ["showSidebar"]),
    sortIcon() {
      return this.sortAsc ? "sort-amount-down" : "sort-amount-up";
    },
    filteredImports() {
      const filtered = this.imports
        .filter(element => {
          if (!this.searchQuery) return true;
          return [(element.kind, element.user, element.enqueued)].some(x => {
            return x.toLowerCase().includes(this.searchQuery.toLowerCase());
          });
        })
        .filter(y => {
          if (
            !this.successful &&
            !this.failed &&
            !this.pending &&
            !this.accepted &&
            !this.rejected
          )
            return true;
          let filterCriteria = [];
          if (this.successful) filterCriteria.push("successful");
          if (this.failed) filterCriteria.push("failed");
          if (this.pending) filterCriteria.push("pending");
          if (this.accepted) filterCriteria.push("accepted");
          if (this.rejected) filterCriteria.push("rejected");
          const result = filterCriteria.map(selectedState => {
            return y.state === selectedState;
          });
          return result.some(x => x);
        });
      return filtered;
    },
    spacerStyle() {
      return [
        "spacer ml-3",
        {
          "spacer-expanded": this.showSidebar,
          "spacer-collapsed": !this.showSidebar
        }
      ];
    },
    successfulStyle() {
      return {
        btn: true,
        "btn-light": !this.successful,
        "btn-dark": this.successful
      };
    },
    pendingStyle() {
      return {
        btn: true,
        "btn-light": !this.pending,
        "btn-dark": this.pending
      };
    },
    failedStyle() {
      return {
        btn: true,
        "btn-light": !this.failed,
        "btn-dark": this.failed
      };
    },
    rejectedStyle() {
      return {
        btn: true,
        "btn-light": !this.rejected,
        "btn-dark": this.rejected
      };
    },
    acceptedStyle() {
      return {
        btn: true,
        "btn-light": !this.accepted,
        "btn-dark": this.accepted
      };
    }
  }
};
</script>

<style lang="scss" scoped>
.jobid {
  width: 80px;
}

.enqueued {
  width: 120px;
}

.user {
  width: 80px;
}

.signer {
  width: 80px;
}

.kind {
  width: 80px;
}

.state {
  width: 80px;
}

.header {
  font-weight: bold;
  font-size: 0.9em;
}

.details thead {
  display: block;
}
.details tbody {
  display: block;
}

.details tbody {
  height: 260px;
  overflow-y: auto;
  overflow-x: hidden;
}

.closebutton {
  top: $small-offset;
}

.refresh {
  position: absolute;
  right: $offset;
  bottom: $offset;
}

.spacer {
  height: 100vh;
}

.spacer-collapsed {
  min-width: $icon-width + $offset;
  transition: $transition-fast;
}

.spacer-expanded {
  min-width: $sidebar-width;
}

.importqueuecard {
  width: 97%;
  margin-left: $offset;
  margin-right: $offset;
  min-height: 20rem;
}

.card-body {
  width: 100%;
  margin-left: auto;
  margin-right: auto;
}

.searchandfilter {
  position: relative;
  margin-bottom: $xx-large-offset;
}

.filters {
  position: absolute;
  right: 0;
}

.filters button {
  margin-right: $small-offset;
}

.table td,
.table th {
  border-top: 0 !important;
  text-align: left;
  padding: $small-offset !important;
}

.searchgroup {
  position: absolute;
  left: 0;
  width: 45%;
}
</style>