admin-rendering.vue 8.76 KB
Newer Older
1
<template lang='pug'>
2 3
  v-container(fluid, grid-list-lg)
    v-layout(row, wrap)
4
      v-flex(xs12)
5
        .admin-header
6
          img.animated.fadeInUp(src='/_assets/svg/icon-process.svg', alt='Rendering', style='width: 80px;')
7
          .admin-header-title
NGPixel's avatar
NGPixel committed
8 9
            .headline.primary--text.animated.fadeInLeft {{ $t('admin:rendering.title') }}
            .subtitle-1.grey--text.animated.fadeInLeft.wait-p4s {{ $t('admin:rendering.subtitle') }}
10
          v-spacer
NGPixel's avatar
NGPixel committed
11 12 13
          v-btn.animated.fadeInDown.wait-p3s(icon, outlined, color='grey', href='https://docs.requarks.io/rendering', target='_blank')
            v-icon mdi-help-circle
          v-btn.mx-3.animated.fadeInDown.wait-p2s(icon, outlined, color='grey', @click='refresh')
14
            v-icon mdi-refresh
Nick's avatar
Nick committed
15
          v-btn.animated.fadeInDown(color='success', @click='save', depressed, large)
16
            v-icon(left) mdi-check
17
            span {{$t('common:actions.apply')}}
18

Nick's avatar
Nick committed
19
      v-flex.animated.fadeInUp(lg3, xs12)
20
        v-toolbar(
NGPixel's avatar
NGPixel committed
21
          color='blue darken-2'
22 23 24 25
          dense
          flat
          dark
          )
26
          .subtitle-1 Pipeline
27 28 29 30 31 32
        v-expansion-panels.adm-rendering-pipeline(
          v-model='selectedCore'
          accordion
          mandatory
          )
          v-expansion-panel(
33 34 35
            v-for='core in renderers'
            :key='core.key'
            )
36 37 38 39 40 41 42 43 44 45 46 47
            v-expansion-panel-header(
              hide-actions
              ripple
            )
              v-toolbar(
                color='blue'
                dense
                dark
                flat
                )
                v-spacer
                .body-2 {{core.input}}
48
                v-icon.mx-2 mdi-arrow-right-circle
49 50 51 52 53 54 55 56
                .caption {{core.output}}
                v-spacer
            v-expansion-panel-content
              v-list.py-0(two-line, dense)
                template(v-for='(rdr, n) in core.children')
                  v-list-item(
                    :key='rdr.key'
                    @click='selectRenderer(rdr.key)'
57
                    :class='currentRenderer.key === rdr.key ? ($vuetify.theme.dark ? `grey darken-4-l4` : `blue lighten-5`) : ``'
58
                    )
59
                    v-list-item-avatar(size='24', tile)
60 61 62 63 64 65 66 67
                      v-icon(:color='currentRenderer.key === rdr.key ? "primary" : "grey"') {{rdr.icon}}
                    v-list-item-content
                      v-list-item-title {{rdr.title}}
                      v-list-item-subtitle: .caption {{rdr.description}}
                    v-list-item-avatar(size='24')
                      status-indicator(v-if='rdr.isEnabled', positive, pulse)
                      status-indicator(v-else, negative, pulse)
                  v-divider.my-0(v-if='n < core.children.length - 1')
68

69
      v-flex(lg9, xs12)
Nick's avatar
Nick committed
70
        v-card.wiki-form.animated.fadeInUp
71
          v-toolbar(
NGPixel's avatar
NGPixel committed
72
            color='indigo'
73 74 75 76 77
            dark
            flat
            dense
            )
            v-icon.mr-2 {{currentRenderer.icon}}
78
            .subtitle-1 {{currentRenderer.title}}
79
            v-spacer
80 81 82 83 84 85
            v-switch(
              dark
              color='white'
              label='Enabled'
              v-model='currentRenderer.isEnabled'
              hide-details
86
              inset
87
              )
88 89 90 91 92 93
          v-card-info(color='blue')
            div
              div {{currentRenderer.description}}
              span.caption: a(href='https://docs.requarks.io/en/rendering', target='_blank') Documentation
          v-card-text.pb-4.pl-4
            .overline.mb-5 Rendering Module Configuration
94
            .body-2.ml-3(v-if='!currentRenderer.config || currentRenderer.config.length < 1'): em This rendering module has no configuration options you can modify.
95 96 97
            template(v-else, v-for='(cfg, idx) in currentRenderer.config')
              v-select(
                v-if='cfg.value.type === "string" && cfg.value.enum'
98
                outlined
99 100 101 102 103 104 105
                :items='cfg.value.enum'
                :key='cfg.key'
                :label='cfg.value.title'
                v-model='cfg.value.value'
                :hint='cfg.value.hint ? cfg.value.hint : ""'
                persistent-hint
                :class='cfg.value.hint ? "mb-2" : ""'
NGPixel's avatar
NGPixel committed
106
                color='indigo'
107 108 109 110 111 112
              )
              v-switch(
                v-else-if='cfg.value.type === "boolean"'
                :key='cfg.key'
                :label='cfg.value.title'
                v-model='cfg.value.value'
NGPixel's avatar
NGPixel committed
113
                color='indigo'
114 115
                :hint='cfg.value.hint ? cfg.value.hint : ""'
                persistent-hint
116
                inset
117 118 119
                )
              v-text-field(
                v-else
120
                outlined
121 122 123 124 125 126
                :key='cfg.key'
                :label='cfg.value.title'
                v-model='cfg.value.value'
                :hint='cfg.value.hint ? cfg.value.hint : ""'
                persistent-hint
                :class='cfg.value.hint ? "mb-2" : ""'
NGPixel's avatar
NGPixel committed
127
                color='indigo'
128
                )
129
              v-divider.my-5(v-if='idx < currentRenderer.config.length - 1')
130 131 132
          v-card-chin
            v-spacer
            .caption.pr-3.grey--text Module: {{ currentRenderer.key }}
133 134 135
</template>

<script>
136
import _ from 'lodash'
137 138 139
import { DepGraph } from 'dependency-graph'

import { StatusIndicator } from 'vue-status-indicator'
140 141

import renderersQuery from 'gql/admin/rendering/rendering-query-renderers.gql'
142
import renderersSaveMutation from 'gql/admin/rendering/rendering-mutation-save-renderers.gql'
143

144
export default {
145 146 147
  components: {
    StatusIndicator
  },
148
  data() {
149
    return {
150 151 152
      selectedCore: -1,
      renderers: [],
      currentRenderer: {}
153 154
    }
  },
155 156 157
  watch: {
    renderers(newValue, oldValue) {
      _.delay(() => {
158 159
        this.selectedCore = _.findIndex(newValue, ['key', 'markdownCore'])
        this.selectRenderer('markdownCore')
160 161 162
      }, 500)
    }
  },
163 164 165 166 167 168 169
  methods: {
    selectRenderer (key) {
      this.renderers.map(rdr => {
        if (_.some(rdr.children, ['key', key])) {
          this.currentRenderer = _.find(rdr.children, ['key', key])
        }
      })
170 171
    },
    async refresh () {
172
      await this.$apollo.queries.renderers.refetch()
173
      this.$store.commit('showNotification', {
174 175 176
        message: 'Rendering active configuration has been reloaded.',
        style: 'success',
        icon: 'cached'
177 178 179
      })
    },
    async save () {
180 181 182 183 184 185 186 187 188 189 190 191 192 193
      this.$store.commit(`loadingStart`, 'admin-rendering-saverenderers')
      await this.$apollo.mutate({
        mutation: renderersSaveMutation,
        variables: {
          renderers: _.reduce(this.renderers, (result, core) => {
            result = _.concat(result, core.children.map(rd => ({
              key: rd.key,
              isEnabled: rd.isEnabled,
              config: rd.config.map(cfg => ({ key: cfg.key, value: JSON.stringify({ v: cfg.value.value }) }))
            })))
            return result
          }, [])
        }
      })
194
      this.$store.commit('showNotification', {
195 196 197
        message: 'Rendering configuration saved successfully.',
        style: 'success',
        icon: 'check'
198
      })
199
      this.$store.commit(`loadingStop`, 'admin-rendering-saverenderers')
200 201
    }
  },
202 203 204 205
  apollo: {
    renderers: {
      query: renderersQuery,
      fetchPolicy: 'network-only',
206
      update: (data) => {
NGPixel's avatar
NGPixel committed
207 208 209 210 211 212 213
        let renderers = _.cloneDeep(data.rendering.renderers).map(str => ({
          ...str,
          config: _.sortBy(str.config.map(cfg => ({
            ...cfg,
            value: JSON.parse(cfg.value)
          })), [t => t.value.order])
        }))
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
        // Build tree
        const graph = new DepGraph({ circular: true })
        const rawCores = _.filter(renderers, ['dependsOn', null]).map(core => {
          core.children = _.concat([_.cloneDeep(core)], _.filter(renderers, ['dependsOn', core.key]))
          return core
        })
        // Build dependency graph
        rawCores.map(core => { graph.addNode(core.key) })
        rawCores.map(core => {
          rawCores.map(coreTarget => {
            if (core.key !== coreTarget.key) {
              if (core.output === coreTarget.input) {
                graph.addDependency(core.key, coreTarget.key)
              }
            }
          })
        })
        // Reorder cores in reverse dependency order
        let orderedCores = []
        _.reverse(graph.overallOrder()).map(coreKey => {
          orderedCores.push(_.find(rawCores, ['key', coreKey]))
        })
        return orderedCores
      },
238 239 240
      watchLoading (isLoading) {
        this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-rendering-refresh')
      }
241
    }
242 243 244 245 246
  }
}
</script>

<style lang='scss'>
247
.adm-rendering-pipeline {
248 249 250 251 252 253 254 255
  .v-expansion-panel--active .v-expansion-panel-header {
    min-height: 0;
  }

  .v-expansion-panel-header {
    padding: 0;
    margin-top: 1px;
  }
256

257 258
  .v-expansion-panel-content__wrap {
    padding: 0;
259 260
  }
}
261
</style>