浏览代码

update store with data formating and query actions

axolotle 3 年之前
父节点
当前提交
df7f47f718
共有 4 个文件被更改,包括 344 次插入3 次删除
  1. 4 3
      src/store/index.js
  2. 125 0
      src/store/modules/library.js
  3. 114 0
      src/store/texts.js
  4. 101 0
      src/store/utils.js

+ 4 - 3
src/store/index.js

@@ -1,13 +1,14 @@
 import Vue from 'vue'
 import Vuex from 'vuex'
 
-import texts from './modules/texts'
-
+import texts from './texts'
+import library from './modules/library'
 
 Vue.use(Vuex)
 
 export default new Vuex.Store({
+  ...texts,
   modules: {
-    texts
+    library
   }
 })

+ 125 - 0
src/store/modules/library.js

@@ -0,0 +1,125 @@
+import Vue from 'vue'
+
+import api from '@/api'
+import {
+  AllTags
+} from '@/api/queries'
+import {
+  getUniqueNodesIds,
+  getRelatedNodesIds,
+  buildTree
+} from '@/store/utils.js'
+
+
+export default {
+  state: {
+    tags: undefined,
+    strangeness: [0, 1, 2, 3, 4],
+    nodeDepartId: undefined,
+    trees: {}
+  },
+
+  mutations: {
+    'SET_TAGS' (state, tags) {
+      state.tags = tags
+    },
+
+    'SET_NODE_DEPART_ID' (state, id) {
+      state.nodeDepartId = id
+    },
+
+    'ADD_NODE_TREE' (state, [id, tree]) {
+      Vue.set(state.trees, id, tree)
+    }
+  },
+
+  actions: {
+    async 'INIT_LIBRARY' ({ state, commit, dispatch, rootState }) {
+      const departIds = await dispatch('GET_ALL_NODES_IDS', 'depart')
+      await dispatch('GET_NODES', { ids: departIds, dataLevel: 'initial' })
+      return departIds
+    },
+
+    async 'INIT_LIBRARY_TREE' ({ state, commit, dispatch, rootState }) {
+      const ids = await dispatch('INIT_LIBRARY')
+      return dispatch('SET_NODE_DEPART_ID', ids[ids.length - 1])
+    },
+
+    async 'INIT_LIBRARY_MAP' ({ state, commit, dispatch }) {
+      const departIds = await dispatch('INIT_LIBRARY')
+      const departNodes = await dispatch('GET_NODES', { ids: departIds.slice(0, 3), dataLevel: 'partial' })
+      const relatedIds = getRelatedNodesIds(departNodes)
+      const relatedNodes = await dispatch('GET_NODES', { ids: relatedIds, dataLevel: 'partial' })
+      return [...departNodes, ...relatedNodes]
+    },
+
+    async 'INIT_LIBRARY_LIST' ({ state, commit, dispatch }) {
+      const departIds = await dispatch('INIT_LIBRARY')
+      return dispatch('GET_NODES', { ids: departIds, dataLevel: 'partial' })
+    },
+
+    'GET_ALL_TAGS' ({ state, commit }) {
+      if (state.tags !== undefined) return state.tags
+      return api.query(AllTags).then(data => {
+        commit('SET_TAGS', data.tags)
+        return state.tags
+      })
+    },
+
+    async 'SET_NODE_DEPART_ID' ({ state, rootState, commit, dispatch, getters }, id) {
+      if (state.nodeDepartId === id) return
+
+      commit('SET_NODE_DEPART_ID', id)
+
+      if (!(id in state.trees)) {
+        const treeData = await api.queryRecursiveNodes([id])
+        const nodes = await dispatch('GET_NODES', { ids: getUniqueNodesIds(treeData), dataLevel: 'initial' })
+        commit('ADD_NODE_TREE', [id, buildTree(treeData, nodes)])
+      }
+
+      return getters.nodeTree
+    }
+  },
+
+  getters: {
+    tagsOptions: state => {
+      if (state.tags === undefined) return
+      return state.tags.map(tag => ({ value: tag.id, text: tag.name }))
+    },
+
+    nodesDepartsOptions: (state, getters, rootState) => {
+      const departIds = rootState.ids.depart
+      if (departIds === undefined || rootState.nodes[departIds[0]] === undefined) return
+      return departIds.map(id => {
+        const text = rootState.nodes[id]
+        const firstAuthor = text.authors !== null ? text.authors[0].name : 'Pad de noms'
+        return {
+          text: `${firstAuthor}, ${text.title} (${id})`,
+          value: id
+        }
+      })
+    },
+
+    orderedTextsDepart: (state, getters, rootState) => {
+      const departIds = rootState.ids.depart
+      if (departIds === undefined || rootState.nodes[departIds[0]] === undefined) return
+      return rootState.ids.depart.map(id => rootState.nodes[id]).sort((a, b) => {
+        if (!b.authors) return -1
+        if (!a.authors) return +1
+        if (a.authors[0].last_name < b.authors[0].last_name) return -1
+        if (a.authors[0].last_name > b.authors[0].last_name) return 1
+        return 0
+      }).reduce((dict, text) => {
+        const firstChar = text.authors ? text.authors[0].last_name[0] : 'Pas de noms'
+        if (!(firstChar in dict)) dict[firstChar] = []
+        dict[firstChar].push(text)
+        return dict
+      }, {})
+    },
+
+    nodeTree: (state, rootState) => {
+      if (state.nodeDepartId === undefined) return
+      return state.trees[state.nodeDepartId]
+    }
+  }
+}

+ 114 - 0
src/store/texts.js

@@ -0,0 +1,114 @@
+import Vue from 'vue'
+
+import api from '@/api'
+import {
+  DATA_LEVELS,
+  ID_VARIANTS,
+  RELATIONS // FIXME REMOVE WHEN DB MAJ
+} from '@/store/utils'
+import {
+  AllNodesOfVariant
+} from '@/api/queries'
+
+
+export default {
+  state: {
+    nodes: {},
+
+    history: [],
+
+    // IDS
+    ids: {
+      // depart: undefined,
+      // kit: undefined,
+      // creation: undefined
+    }
+  },
+
+  mutations: {
+    'SET_ALL_NODES_IDS' (state, [variant, nodes]) {
+      Vue.set(state.ids, variant, nodes.map(({ id }) => id))
+    },
+
+    'ADD_NODES' (state, [nodes, dataLevel]) {
+      for (const node of nodes) {
+        const stateNode = node.id in state.nodes ? state.nodes[node.id] : undefined
+        // FIXME UPDATE AFTER DB MAJ
+        if (node.variant === null || Array.isArray(node.variant)) {
+          node.variant = node.variant !== null ? ID_VARIANTS[node.variant[0].id] : 'black'
+        }
+        if (node.type) {
+          node.type = node.type === 'texte' ? 'Textref' : 'Textprod'
+        }
+        // FIXME REMOVE AFTER DB MAJ
+        for (const relation of RELATIONS) {
+          if (relation in node && node[relation]) {
+            node[relation].forEach(subNode => {
+              subNode.variant = subNode.variant !== null ? ID_VARIANTS[subNode.variant[0].id] : 'black'
+            })
+          }
+        }
+        if (!stateNode || stateNode.dataLevel < dataLevel) {
+          node.dataLevel = dataLevel
+        }
+        Vue.set(state.nodes, node.id, stateNode ? { ...stateNode, ...node } : node)
+      }
+    }
+  },
+
+  actions: {
+    async 'GET_ALL_NODES_IDS' ({ state, commit }, variant) {
+      if (state.ids[variant] === undefined) {
+        // FIXME UPDATE WHEN QUERY OK
+        // await api.query(AllNodesOfVariant, { variantId: VARIANT_IDS[variant] }).then(data => {
+        await api.query(AllNodesOfVariant).then(data => {
+          commit('SET_ALL_NODES_IDS', [variant, data.nodes])
+        })
+      }
+      return state.ids[variant]
+    },
+
+    async 'GET_NODES' ({ state, commit, getters }, { ids, dataLevel = 'partial' }) {
+      const lvl = DATA_LEVELS[dataLevel]
+      const nodesIdsToQuery = []
+      let lowestLvl = lvl
+      for (const id of ids) {
+        const nodeLvl = id in state.nodes ? state.nodes[id].dataLevel : -1
+        if (nodeLvl < lvl) {
+          nodesIdsToQuery.push(id)
+        }
+        if (nodeLvl < lowestLvl) {
+          lowestLvl = nodeLvl
+        }
+      }
+
+      if (nodesIdsToQuery.length) {
+        const levelsToQuery = Array(lvl - lowestLvl).fill(lowestLvl + 1).map((v, i) => v + i)
+        await api.queryNodes(nodesIdsToQuery, levelsToQuery).then(data => {
+          commit('ADD_NODES', [data.nodes, lvl])
+        })
+      }
+
+      return getters.nodes(ids)
+    },
+
+    async 'GET_NODE' ({ state, commit, getters }, { id, dataLevel = 'full' }) {
+      const lvl = DATA_LEVELS[dataLevel]
+      const nodeLvl = id in state.nodes ? state.nodes[id].dataLevel : -1
+      if (nodeLvl < lvl) {
+        const levelsToQuery = Array(lvl - nodeLvl).fill(nodeLvl + 1).map((v, i) => v + i)
+        await api.queryNode(id, levelsToQuery).then(data => {
+          commit('ADD_NODES', [[data.node], lvl])
+        })
+      }
+
+      return getters.node(id)
+    }
+  },
+
+  getters: {
+    // Args getters
+    nodes: state => ids => ids.map(id => state.nodes[id]),
+    node: state => id => state.nodes[id]
+  }
+}

+ 101 - 0
src/store/utils.js

@@ -0,0 +1,101 @@
+import { hierarchy } from 'd3-hierarchy'
+
+
+export const RELATIONS = [
+  'parents',
+  'siblings',
+  'children'
+]
+
+export const DATA_LEVELS = {
+  initial: 0,
+  partial: 1,
+  full: 2
+}
+
+export const ID_VARIANTS = {
+  9: 'depart',
+  22: 'critique',
+  63: 'echo',
+  6: 'reflexion',
+  7: 'lecture',
+  8: 'sensible',
+  23: 'kit'
+  // undefined: 'creation'
+}
+
+export const VARIANT_IDS = Object.fromEntries(
+  Object.entries(ID_VARIANTS).map(([key, value]) => [value, key])
+)
+
+
+export function getUniqueNodesIds (tree) {
+  function extractId (ids, node) {
+    ids.add(node.id)
+    for (const relation of RELATIONS) {
+      if (relation in node && node[relation]) {
+        for (const subNode of node[relation]) {
+          extractId(ids, subNode)
+        }
+      }
+    }
+    return ids
+  }
+  return Array.from(extractId(new Set(), tree))
+}
+
+
+export function getRelatedNodesIds (nodes) {
+  const ids = new Set()
+  for (const node of nodes) {
+    for (const relation of RELATIONS) {
+      if (relation in node && node[relation]) {
+        node[relation].forEach(({ id }) => {
+          ids.add(id)
+        })
+      }
+    }
+  }
+  return Array.from(ids)
+}
+
+
+export function buildTree (treeData, nodesData) {
+  const uniqueIds = []
+  const nodes = []
+  const links = []
+  const h = hierarchy(treeData, (node) => {
+    return RELATIONS.reduce((acc, relation) => {
+      if (node[relation]) {
+        node[relation].forEach((item, i) => {
+          item.linkType = relation
+        })
+        return [...acc, ...node[relation]]
+      }
+      return acc
+    }, [])
+  })
+
+  h.each(node => {
+    node.id = node.data.id
+    if (!uniqueIds.includes(node.id)) {
+      uniqueIds.push(node.id)
+      node.data = nodesData.find(n => n.id === node.id)
+      nodes.push(node)
+      if (node.children) {
+        node.children.forEach(child => {
+          const asSource = links.find(link => link.source === node.id && link.target === child.data.id)
+          const asTarget = links.find(link => link.source === child.data.id && link.target === node.id)
+          if (!asSource && !asTarget) {
+            links.push({ source: node.id, target: child.data.id, linkType: child.data.linkType })
+          }
+        })
+      }
+    }
+  })
+
+  return {
+    nodes,
+    links
+  }
+}