SpeciesFileGroup/taxonworks

View on GitHub
app/javascript/vue/tasks/browse_annotations/app.vue

Summary

Maintainability
Test Coverage
<template>
  <div>
    <div class="flex-separate middle">
      <h1>Browse Annotations</h1>
      <span
        @click="resetApp"
        class="reload-app"
        data-icon="reset"
        >Reset
      </span>
    </div>
    <spinner
      v-if="isLoading"
      full-screen
      legend="Loading..."
      :logo-size="{ width: '100px', height: '100px' }"
    />
    <div class="flexbox">
      <div class="annotation_type separate-right">
        <h2>Annotation type</h2>
        <annotation-types v-model="filter.annotation_type" />
      </div>
      <div class="annotation_on separate-right separate-left">
        <h2>On</h2>
        <annotation-on
          v-model="filter.model"
          :annotation-type="filter.annotation_type"
        />
      </div>
      <div class="annotation_for separate-right separate-left">
        <h2>For</h2>
        <annotation-for
          v-model="filter.selected_for"
          :select-options-url="filter.annotation_type.select_options_url"
          :all-select-option-url="filter.annotation_type.all_select_option_url"
          :on-model="filter.model"
        />
      </div>
      <div class="annotation_by separate-right separate-left">
        <h2>By</h2>
        <annotation-by v-model="filter.selected_by" />
      </div>
      <div class="annotation_dates separate-right separate-left">
        <h2>When</h2>
        <annotation-dates v-model="filter.annotation_dates" />
      </div>
      <div class="annotation_logic separate-left">
        <h2>Place result</h2>
        <annotation-logic v-model="filter.annotation_logic" />
      </div>
    </div>
    <button
      class="button normal-input button-default separate-bottom"
      @click="processResult()"
      :disabled="submitAvailable"
      type="submit"
    >
      Submit
    </button>
    <request-bar
      class="separate-top"
      :list="resultList"
      :type="filter.annotation_type.type"
      :url="request.url"
      :total="request.total"
    />

    <div class="flex-separate margin-medium-bottom margin-medium-top">
      <pagination-component
        v-if="pagination && resultList.length"
        @nextPage="processResult"
        :pagination="pagination"
      />
      <div
        v-if="resultList.length"
        class="horizontal-left-content"
      >
        <span class="horizontal-left-content">
          {{ recordsAtCurrentPage }} - {{ recordsAtNextPage }} of
          {{ pagination.total }} records.
        </span>
        <div class="margin-small-left">
          <select v-model="per">
            <option
              v-for="records in maxRecords"
              :key="records"
              :value="records"
            >
              {{ records }}
            </option>
          </select>
          records per page.
        </div>
      </div>
    </div>
    <view-list :list="resultList" />
  </div>
</template>
<script>
//TODO: Make a main filter component and move each annotator filter there.
import AnnotationTypes from './components/annotation_types'
import AnnotationOn from './components/annotation_on'
import AnnotationFor from './components/annotation_for'
import AnnotationDates from './components/annotation_dates'
import AnnotationLogic from './components/annotation_logic'
import AnnotationBy from './components/annotation_by'
//
import ViewList from './components/view/list.vue'
import RequestBar from './components/view/requestBar.vue'

import Spinner from '@/components/ui/VSpinner.vue'
import AjaxCall from '@/helpers/ajaxCall'
import PaginationComponent from '@/components/pagination'
import GetPagination from '@/helpers/getPagination'

export default {
  name: 'BrowseAnnotations',

  components: {
    AnnotationBy,
    AnnotationTypes,
    AnnotationFor,
    AnnotationOn,
    AnnotationDates,
    AnnotationLogic,
    ViewList,
    RequestBar,
    Spinner,
    PaginationComponent
  },

  data() {
    return {
      filter: this.resetFilter(),
      isLoading: false,
      resultList: [],
      request: {
        url: '',
        total: 0
      },
      for: {
        tags: 'keyword_id',
        data_attributes: 'controlled_vocabulary_term_id',
        confidences: 'confidence_level_id'
      },
      per: 500,
      pagination: undefined,
      maxRecords: [50, 100, 250, 500, 1000]
    }
  },

  computed: {
    submitAvailable() {
      return !this.filter.annotation_type.type || !this.filter.model
    },

    recordsAtCurrentPage() {
      return (this.pagination.paginationPage - 1) * this.pagination.perPage || 1
    },

    recordsAtNextPage() {
      const recordsCount =
        this.pagination.paginationPage * this.pagination.perPage
      return recordsCount > this.pagination.total
        ? this.pagination.total
        : recordsCount
    }
  },

  watch: {
    per() {
      this.processResult()
    }
  },

  methods: {
    processResult({ page } = {}) {
      const type = this.filter.annotation_type.type
      const objectType = `${type.slice(0, -1)}_object_type`

      const params = {
        [objectType]: [this.filter.model],
        by: this.filter.selected_by,
        created_after: this.filter.annotation_dates.after,
        created_before: this.filter.annotation_dates.before,
        per: this.per,
        page,
        extend: ['annotated_object']
      }
      params[this.for[type]] = this.filter.selected_for
      this.isLoading = true

      AjaxCall('get', `/${type}.json`, {
        params
      }).then((response) => {
        this.pagination = GetPagination(response)
        if (this.filter.annotation_logic === 'replace') {
          this.resultList = response.body
        } else {
          let concat = response.body.concat(this.resultList)

          concat = concat.filter(
            (item, index, self) =>
              index ===
              self.findIndex((i) => i.id === item.id && i.type === item.type)
          )
          this.resultList = concat
        }

        this.request.url = response.request.responseURL
        this.request.total = response.body.length
        this.isLoading = false
      })
    },

    resetApp() {
      this.filter = this.resetFilter()
      this.resultList = []
      this.request.url = ''
      this.request.total = 0
    },

    resetFilter() {
      return {
        annotation_type: {
          type: undefined,
          used_on: undefined,
          select_options_url: undefined,
          all_select_option_url: undefined
        },
        annotation_dates: {
          after: undefined,
          before: undefined
        },
        annotation_logic: 'replace',
        selected_type: undefined,
        selected_for: [],
        selected_by: [],
        model: undefined,
        result: 'initial result'
      }
    }
  }
}
</script>
<style lang="scss">
.reload-app {
  cursor: pointer;
  &:hover {
    opacity: 0.8;
  }
}
</style>