SpeciesFileGroup/taxonworks

View on GitHub
app/javascript/vue/components/radials/object/components/contents/main.vue

Summary

Maintainability
Test Coverage
<template>
  <div class="content_annotator">
    <h3
      v-if="content.id"
      v-html="content.object_tag"
    />
    <h3 v-else>New record</h3>
    <fieldset class="margin-medium-bottom">
      <legend>Topic</legend>
      <SmartSelector
        class="full_width margin-small-bottom"
        ref="smartSelector"
        autocomplete-url="/controlled_vocabulary_terms/autocomplete"
        :autocomplete-params="{ 'type[]': 'Topic' }"
        get-url="/controlled_vocabulary_terms/"
        model="topics"
        target="Content"
        klass="Otu"
        :add-tabs="['all']"
        pin-section="Topic"
        buttons
        inline
        label="name"
        pin-type="BiologicalRelationship"
        :filter="(topic) => list.every((item) => item.topic.id !== topic.id)"
        @selected="setTopic"
      >
        <template #all>
          <a
            v-if="!allTopics.length"
            target="blank"
            href="/controlled_vocabulary_terms/new"
          >
            Create a topic first.
          </a>
          <TopicItem
            v-for="item in topicsAvailable"
            :key="item.id"
            :topic="item"
            @select="setTopic"
          />
        </template>
      </SmartSelector>
      <hr />
      <SmartSelectorItem
        :item="topic"
        label="name"
        @unset="() => (topic = null)"
      />
    </fieldset>
    <div>
      <VSpinner
        v-if="!topic"
        :show-spinner="false"
        legend="Select a topic first"
      />
      <MarkdownEditor
        v-model="content.text"
        :configs="config"
      />
    </div>
    <div
      class="margin-small-top margin-small-bottom horizontal-left-content gap-small"
    >
      <VBtn
        color="create"
        medium
        :disabled="!validate"
        @click="saveContent"
      >
        {{ content.id ? 'Update' : 'Create' }}
      </VBtn>
      <VBtn
        color="primary"
        medium
        @click="
          () => {
            setContent(makeContent())
          }
        "
      >
        New
      </VBtn>
    </div>
    <TableList
      :header="['Text', 'Topic', '']"
      :attributes="['text_for_list', ['topic', 'name']]"
      :list="shortList"
      edit
      class="list"
      @delete="removeItem"
      @edit="setContent"
    />
  </div>
</template>

<script setup>
import TopicItem from '../citations/topicItem.vue'
import TableList from '@/components/table_list.vue'
import MarkdownEditor from '@/components/markdown-editor.vue'
import SmartSelector from '@/components/ui/SmartSelector.vue'
import SmartSelectorItem from '@/components/ui/SmartSelectorItem.vue'
import VSpinner from '@/components/ui/VSpinner.vue'
import VBtn from '@/components/ui/VBtn/index.vue'
import { shorten } from '@/helpers/strings.js'
import { ControlledVocabularyTerm, Content } from '@/routes/endpoints'
import { computed, ref, onBeforeMount } from 'vue'
import { useSlice } from '@/components/radials/composables'
import { TOPIC } from '@/constants'

const props = defineProps({
  objectId: {
    type: Number,
    required: true
  },

  objectType: {
    type: String,
    required: true
  },

  radialEmit: {
    type: Object,
    required: true
  }
})

const extend = ['otu', 'topic']

const config = {
  status: false,
  spellChecker: false
}

const { list, addToList, removeFromList } = useSlice({
  radialEmit: props.radialEmit
})

const content = ref(makeContent())
const topic = ref(null)
const allTopics = ref([])

const topicsAvailable = computed(() =>
  allTopics.value.filter(
    (topic) => !list.value.find((item) => item.topic_id === topic.id)
  )
)

const validate = computed(() => content.value.text.length > 1 && topic.value)
const shortList = computed(() =>
  list.value.map((content) => ({
    ...content,
    text_for_list: shorten(content.text, 150)
  }))
)

onBeforeMount(async () => {
  ControlledVocabularyTerm.where({ type: [TOPIC] }).then(({ body }) => {
    allTopics.value = body
  })

  Content.where({
    otu_id: props.objectId,
    extend
  }).then(({ body }) => {
    list.value = body
  })
})

function saveContent() {
  const { text, id } = content.value
  const payload = {
    content: {
      id,
      text,
      topic_id: topic.value.id,
      otu_id: props.objectId,
      type: props.objectType
    },
    extend
  }

  const saveRecord = id ? Content.update(id, payload) : Content.create(payload)

  saveRecord.then(({ body }) => {
    addToList(body)
    TW.workbench.alert.create('Content was successfully saved.', 'notice')
    content.value = makeContent()
  })
}

function makeContent() {
  return {
    text: ''
  }
}

function setTopic(item) {
  topic.value = item
}

function setContent(item) {
  content.value = item
  topic.value = item?.topic
}

function removeItem(item) {
  Content.destroy(item.id).then((_) => {
    removeFromList(item)

    if (item.id === content.value?.id) {
      setContent(makeContent())
    }
  })
}
</script>