Began adding roads

Began adding roads

<!--

It would be great if you color the map by population using data from index.vue

Based on:
  http://bl.ocks.org/rveciana/a2a1c21ca1c71cd3ec116cc911e5fce9
  http://bl.ocks.org/mapsam/6083585

Links:

-->

<template>
  <svg width='600' height='600'></svg>
</template>

<script>
// Map stuff
const d3 = require('d3')
const topojson = require('topojson')
const d3Cartogram = require('mixins/d3-cartogram')

// Colors stuff
import * as d3Chromatic from 'd3-scale-chromatic'
const colors = d3Chromatic.schemeRdYlGn[3].reverse()
// const colors = d3Chromatic.schemeBlues[9]

const projection = d3.geoMercator().center([-78.7, 36.05]).scale(60000).precision(0.1)
const path = d3.geoPath().projection(projection)

const width = 600
const height = 600
var centered

export default {
  data: function () {
    return {
      cntycartogram: null,
      cntyboundaries: null,
      municartogram: null,
      muniboundaries: null,
      cartogram: null,
      topology: null,
      geometries: null,
      durhamhds: null,
      durhambgs: null,
      roadscartogram: null,
      osmroads: null,
      layer: null
    }
  },
  mounted: function () {
    var mounthis = this
    var dataById

    mounthis.cntycartogram = d3Cartogram.d3.cartogram()
      .projection(projection)
    mounthis.municartogram = d3Cartogram.d3.cartogram()
      .projection(projection)
    mounthis.cartogram = d3Cartogram.d3.cartogram()
      .projection(projection)
      .properties(function (d) {
        return dataById.get(d.id)
      })
    mounthis.roadscartogram = d3Cartogram.d3.cartogram()
      .projection(projection)

    const svg = d3.select(this.$el)
      .append('svg')
      .attr('width', width)
      .attr('height', height)
    svg.append('rect')
      .attr('class', 'background')
      .attr('width', width)
      .attr('height', height)
      .on('click', mounthis.clicked)

    mounthis.layer = svg.append('g')
      .attr('id', 'layer')
      .attr('class', 'key')
      .attr('transform', 'translate(0,40)')
    mounthis.cntyboundaries = mounthis.layer.append('g')
      .attr('id', 'cntyboundaries')
      .selectAll('path')
    mounthis.muniboundaries = mounthis.layer.append('g')
      .attr('id', 'muniboundaries')
      .selectAll('path')
    mounthis.durhambgs = mounthis.layer.append('g')
      .attr('id', 'durhambgs')
      .selectAll('path')
    mounthis.osmroads = mounthis.layer.append('g')
      .attr('id', 'osmroads')
      .selectAll('path')

    d3.json('statics/data/cntyboundaries.topojson', function (topo) {
      let topology = topo
      let geometries = topology.objects.cntyboundaries.geometries

      let features = mounthis.cntycartogram.features(topology, geometries)

      mounthis.cntyboundaries = mounthis.cntyboundaries.data(features)
        .enter()
        .append('path')
        .attr('class', 'cntyboundary')
        .attr('id', function (d) {
          return d.id
        })
        .attr('d', path)

      mounthis.cntyboundaries.transition()
        .duration(750)
        .ease(d3.easeLinear)
    })

    d3.json('statics/data/muniboundaries.topojson', function (topo) {
      let topology = topo
      let geometries = topology.objects.muniboundaries.geometries

      let features = mounthis.municartogram.features(topology, geometries)

      mounthis.muniboundaries = mounthis.muniboundaries.data(features)
        .enter()
        .append('path')
        .attr('class', 'muniboundary')
        .attr('id', function (d) {
          return d.id
        })
        .attr('d', path)

      mounthis.muniboundaries.transition()
        .duration(750)
        .ease(d3.easeLinear)
    })

    d3.json('statics/data/durhambgs.topojson', function (topo) {
      mounthis.topology = topo
      mounthis.geometries = mounthis.topology.objects.durhambgs.geometries

      d3.json('http://127.0.0.1:8000/api/singfamhouse/?format=json', function (data) {
        dataById = d3.nest()
          .key(function (d) { return d.id })
          .rollup(function (d) { return d[0] })
          .map(data)

        mounthis.layer.selectAll('.tooltip')
          .data(topojson.feature(mounthis.topology, mounthis.topology.objects.durhambgs).features)
          .enter()
          .append('path')
          .attr('class', 'tooltip')
          .attr('d', path)
          .on('click', mounthis.clicked)
          .on('mouseover', function (d) {
            mounthis.$emit('durhambgSelected', d.id)
          })
          .on('mouseout', function (d) {
            mounthis.$emit('durhambgDeselected', d.id)
          })

        let features = mounthis.cartogram.features(mounthis.topology, mounthis.geometries)

        mounthis.durhambgs = mounthis.durhambgs.data(features)
          .enter()
          .append('path')
          .attr('class', 'durhambg')
          .attr('id', function (d) {
            return d.id
          })
          .attr('d', path)

        let value = function (d) { return +d.properties['prc_sfno'] }

        let values = mounthis.durhambgs.data()
            .map(value)
            .filter(function (n) {
              return !isNaN(n)
            })
            .sort(d3.ascending),
          lo = values[0],
          hi = values[values.length - 1]

        let color = d3.scaleLinear()
          .domain([lo, d3.mean(values), hi])
          .range(colors)

        mounthis.durhambgs.transition()
          .duration(750)
          .ease(d3.easeLinear)
          .attr('fill', function (d) {
            return color(value(d))
          })
      })
    })

    d3.json('statics/data/osm_roads_gen0.topojson', function (topo) {
      let topology = topo
      let geometries = topology.objects.osm_roads_gen0.geometries

      let features = mounthis.roadscartogram.features(topology, geometries)

      mounthis.osmroads = mounthis.osmroads.data(features)
        .enter()
        .append('path')
        .attr('class', 'osm_roads_gen0')
        .attr('id', function (d) {
          return d.id
        })
        .attr('d', path)

      mounthis.osmroads.transition()
        .duration(750)
        .ease(d3.easeLinear)
    })
  },
  props: ['propval'],
  watch: {
    propval: function (newPropVal) {
      this.changePropVal(newPropVal)
    }
  },
  methods: {
    changePropVal: function (propval) {
      let value = function (d) {
        return +d.properties[propval[0]]
      }

      let values = this.durhambgs.data()
          .map(value)
          .filter(function (n) {
            return !isNaN(n)
          })
          .sort(d3.ascending),
        lo = values[0],
        hi = values[values.length - 1]

      let color = d3.scaleLinear()
        .domain([lo, d3.mean(values), hi])
        .range(colors)

      this.durhambgs.transition()
        .duration(750)
        .ease(d3.easeLinear)
        .attr('fill', function (d) {
          return color(value(d))
        })
    },
    clicked: function (d) {
      let x
      let y
      let k

      if (d && centered !== d) {
        let centroid = path.centroid(d)
        x = centroid[0]
        y = centroid[1]
        k = 4
        centered = d
      }
      else {
        x = width / 2
        y = height / 2
        k = 1
        centered = null
      }

      this.layer.selectAll('path')
        .classed('active', centered && function (d) { return d === centered })

      this.layer.transition()
        .duration(750)
        .attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')scale(' + k + ')translate(' + -x + ',' + -y + ')')
        .style('stroke-width', 1.5 / k + 'px')
    }
  }
}
</script>

<style>
.background {
  fill: none;
  pointer-events: all;
}
.cntyboundary {
  stroke: gray;
  fill: white;
}
.muniboundary {
  stroke: gray;
  fill: lightgray;
}
.durhambg {
  opacity: 0.9;
  stroke: #98999b;
}
.tooltip {
  fill: rgba(255, 255, 255, 0.0);
}
.tooltip:hover {
  fill: steelblue;
  fill-opacity: 0.5;
}
</style>

<!--

It would be great if you color the map by population using data from index.vue

Based on:
  http://bl.ocks.org/rveciana/a2a1c21ca1c71cd3ec116cc911e5fce9
  http://bl.ocks.org/mapsam/6083585

Links:

-->

<template>
  <svg width='600' height='600'></svg>
</template>

<script>
// Map stuff
const d3 = require('d3')
const topojson = require('topojson')
const d3Cartogram = require('mixins/d3-cartogram')

// Colors stuff
import * as d3Chromatic from 'd3-scale-chromatic'
const colors = d3Chromatic.schemeRdYlGn[3].reverse()
// const colors = d3Chromatic.schemeBlues[9]

const projection = d3.geoMercator().center([-78.7, 36.05]).scale(60000).precision(0.1)
const path = d3.geoPath().projection(projection)

const width = 600
const height = 600
var centered

export default {
  data: function () {
    return {
      cntycartogram: null,
      cntyboundaries: null,
      municartogram: null,
      muniboundaries: null,
      cartogram: null,
      topology: null,
      geometries: null,
      durhamhds: null,
      durhambgs: null,
      layer: null
    }
  },
  mounted: function () {
    var mounthis = this
    var dataById

    mounthis.cntycartogram = d3Cartogram.d3.cartogram()
      .projection(projection)
    mounthis.municartogram = d3Cartogram.d3.cartogram()
      .projection(projection)

    mounthis.cartogram = d3Cartogram.d3.cartogram()
      .projection(projection)
      .properties(function (d) {
        return dataById.get(d.id)
      })

    const svg = d3.select(this.$el)
      .append('svg')
      .attr('width', width)
      .attr('height', height)
    svg.append('rect')
      .attr('class', 'background')
      .attr('width', width)
      .attr('height', height)
      .on('click', mounthis.clicked)

    mounthis.layer = svg.append('g')
      .attr('id', 'layer')
      .attr('class', 'key')
      .attr('transform', 'translate(0,40)')
    mounthis.cntyboundaries = mounthis.layer.append('g')
      .attr('id', 'cntyboundaries')
      .selectAll('path')
    mounthis.muniboundaries = mounthis.layer.append('g')
      .attr('id', 'muniboundaries')
      .selectAll('path')
    mounthis.durhambgs = mounthis.layer.append('g')
      .attr('id', 'durhambgs')
      .selectAll('path')

    d3.json('statics/data/cntyboundaries.topojson', function (topo) {
      let topology = topo
      let geometries = topology.objects.cntyboundaries.geometries

      let features = mounthis.cntycartogram.features(topology, geometries)

      mounthis.cntyboundaries = mounthis.cntyboundaries.data(features)
        .enter()
        .append('path')
        .attr('class', 'cntyboundary')
        .attr('id', function (d) {
          return d.id
        })
        .attr('d', path)

      mounthis.cntyboundaries.transition()
        .duration(750)
        .ease(d3.easeLinear)
    })

    d3.json('statics/data/muniboundaries.topojson', function (topo) {
      let topology = topo
      let geometries = topology.objects.muniboundaries.geometries

      let features = mounthis.municartogram.features(topology, geometries)

      mounthis.muniboundaries = mounthis.muniboundaries.data(features)
        .enter()
        .append('path')
        .attr('class', 'muniboundary')
        .attr('id', function (d) {
          return d.id
        })
        .attr('d', path)

      mounthis.muniboundaries.transition()
        .duration(750)
        .ease(d3.easeLinear)
    })

    d3.json('statics/data/durhambgs.topojson', function (topo) {
      mounthis.topology = topo
      mounthis.geometries = mounthis.topology.objects.durhambgs.geometries

      d3.json('http://127.0.0.1:8000/api/singfamhouse/?format=json', function (data) {
        dataById = d3.nest()
          .key(function (d) { return d.id })
          .rollup(function (d) { return d[0] })
          .map(data)

        mounthis.layer.selectAll('.tooltip')
          .data(topojson.feature(mounthis.topology, mounthis.topology.objects.durhambgs).features)
          .enter()
          .append('path')
          .attr('class', 'tooltip')
          .attr('d', path)
          .on('click', mounthis.clicked)
          .on('mouseover', function (d) {
            mounthis.$emit('durhambgSelected', d.id)
          })
          .on('mouseout', function (d) {
            mounthis.$emit('durhambgDeselected', d.id)
          })

        let features = mounthis.cartogram.features(mounthis.topology, mounthis.geometries)

        mounthis.durhambgs = mounthis.durhambgs.data(features)
          .enter()
          .append('path')
          .attr('class', 'durhambg')
          .attr('id', function (d) {
            return d.id
          })
          .attr('d', path)

        let value = function (d) { return +d.properties['prc_sfno'] }

        let values = mounthis.durhambgs.data()
            .map(value)
            .filter(function (n) {
              return !isNaN(n)
            })
            .sort(d3.ascending),
          lo = values[0],
          hi = values[values.length - 1]

        let color = d3.scaleLinear()
          .domain([lo, d3.mean(values), hi])
          .range(colors)

        mounthis.durhambgs.transition()
          .duration(750)
          .ease(d3.easeLinear)
          .attr('fill', function (d) {
            return color(value(d))
          })
      })
    })
  },
  props: ['propval'],
  watch: {
    propval: function (newPropVal) {
      this.changePropVal(newPropVal)
    }
  },
  methods: {
    changePropVal: function (propval) {
      let value = function (d) {
        return +d.properties[propval[0]]
      }

      let values = this.durhambgs.data()
          .map(value)
          .filter(function (n) {
            return !isNaN(n)
          })
          .sort(d3.ascending),
        lo = values[0],
        hi = values[values.length - 1]

      let color = d3.scaleLinear()
        .domain([lo, d3.mean(values), hi])
        .range(colors)

      this.durhambgs.transition()
        .duration(750)
        .ease(d3.easeLinear)
        .attr('fill', function (d) {
          return color(value(d))
        })
    },
    clicked: function (d) {
      let x
      let y
      let k

      if (d && centered !== d) {
        let centroid = path.centroid(d)
        x = centroid[0]
        y = centroid[1]
        k = 4
        centered = d
      }
      else {
        x = width / 2
        y = height / 2
        k = 1
        centered = null
      }

      this.layer.selectAll('path')
        .classed('active', centered && function (d) { return d === centered })

      this.layer.transition()
        .duration(750)
        .attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')scale(' + k + ')translate(' + -x + ',' + -y + ')')
        .style('stroke-width', 1.5 / k + 'px')
    }
  }
}
</script>

<style>
.background {
  fill: none;
  pointer-events: all;
}
.cntyboundary {
  stroke: gray;
  fill: white;
}
.muniboundary {
  stroke: gray;
  fill: lightgray;
}
.durhambg {
  opacity: 0.9;
  stroke: #98999b;
}
.tooltip {
  fill: rgba(255, 255, 255, 0.0);
}
.tooltip:hover {
  fill: steelblue;
  fill-opacity: 0.5;
}
</style>


checkbox false in document

checkbox false in document

<template>

    <input :id="name" type="checkbox" name="name" @change="update" :checked="value" />
    {{name}}

</template>

<template>

    <input :id="name" type="checkbox" name="name" v-model="value" :checked="content" />
    {{name}}

</template>


task_2 - added update function to the select content

<template>

          {{ field.name }}

            <input type="text" class="input" maxlength="25" required :placeholder="field.name" v-model="content[field.name]">

          {{ field.name }}

            <textarea class="input" v-model="content[field.name]" :placeholder="field.name" v-text="content[field.name]"></textarea>

          <quill-editor v-model="content[field.name]" :options="editorOptions">
          </quill-editor>
          <input type="file" id="getImage" style="display: none;" @change="uploadImage">

          {{ field.name }}

                <select>
                  <option v-for="(selectOption, selectIndex) in content[field.name]" :key="selectIndex">{{ selectOption }}</option>
                </select>

                {{option}}
                <button class="delete is-small"></button>

            <input type="text" class="input" :placeholder="field.name" @blur="styleOptions(field.name)" @keyup.enter="styleOptions(field.name)" v-model="selectOptionsRow" maxlength="25">

Separate options with commas

          {{ field.name }}

              {{tag}}
                <button class="delete is-small"></button>

              <input :placeholder="field.name" @blur="styleTags(field.name)" @keyup.enter="styleTags(field.name)" type="text" class="input" maxlength="25" v-model="inputData">

Separate tags with commas

          {{ field.name }}

                <input @change="uploadFeaturedImage($event, field.name)" class="file-input" type="file" name="resume">

                    Choose a file…

      <button class="delete" @click="hideNotifications"></button>{{notification.message}}

    <button v-if="content.state === 'saved'" type="submit" class="button is-success" @click="update(true)">Update and publish</button>
    <button type="submit" class="button is-info" @click="update(false)">Update</button>
    <router-link :to="'/admin/content/' + $route.params.key" class="button is-danger">Cancel</router-link>

</template>

<template>

          {{ field.name }}

            <input type="text" class="input" maxlength="25" required :placeholder="field.name" v-model="content[field.name]">

          {{ field.name }}

            <textarea class="input" v-model="content[field.name]" :placeholder="field.name" v-text="content[field.name]"></textarea>

          <quill-editor v-model="content[field.name]" :options="editorOptions">
          </quill-editor>
          <input type="file" id="getImage" style="display: none;" @change="uploadImage">

          {{ field.name }}

            <select>
              <option v-for="option in content[field.name]" :key="option">{{ option }}</option>
            </select>

            <input type="text" class="input" :placeholder="field.name" @blur="styleOptions(field.name)" @keyup.enter="styleOptions(field.name)" v-model="selectOptionsRow" maxlength="25">

Separate options with commas

          {{ field.name }}

              {{tag}}
                <button class="delete is-small"></button>

              <input :placeholder="field.name" @blur="styleTags(field.name)" @keyup.enter="styleTags(field.name)" type="text" class="input" maxlength="25" v-model="inputData">

Separate tags with commas

          {{ field.name }}

                <input @change="uploadFeaturedImage($event, field.name)" class="file-input" type="file" name="resume">

                    Choose a file…

      <button class="delete" @click="hideNotifications"></button>{{notification.message}}

    <button v-if="content.state === 'saved'" type="submit" class="button is-success" @click="update(true)">Update and publish</button>
    <button type="submit" class="button is-info" @click="update(false)">Update</button>
    <router-link :to="'/admin/content/' + $route.params.key" class="button is-danger">Cancel</router-link>

</template>


task_3 - integer content - added integer content

<template>

          {{ field.name }}

            <input type="text" class="input" maxlength="25" required :placeholder="field.name" v-model="content[field.name]">

          {{ field.name }}

            <textarea class="input" v-model="content[field.name]" :placeholder="field.name" v-text="content[field.name]"></textarea>

          <quill-editor v-model="content[field.name]" :options="editorOptions">
          </quill-editor>
          <input type="file" id="getImage" style="display: none;" @change="uploadImage">

          {{ field.name }}

                <select>
                  <option v-for="(selectOption, selectIndex) in content[field.name]" :key="selectIndex">{{ selectOption }}</option>
                </select>

                {{option}}
                <button class="delete is-small"></button>

            <input type="text" class="input" :placeholder="field.name" @blur="styleOptions(field.name)" @keyup.enter="styleOptions(field.name)" v-model="selectOptionsRow" maxlength="25">

Separate options with commas

          {{ field.name }}

              <input type="number" :placeholder="field.name" class="input">

          {{ field.name }}

              {{tag}}
                <button class="delete is-small"></button>

              <input :placeholder="field.name" @blur="styleTags(field.name)" @keyup.enter="styleTags(field.name)" type="text" class="input" maxlength="25" v-model="inputData">

Separate tags with commas

          {{ field.name }}

                <input @change="uploadFeaturedImage($event, field.name)" class="file-input" type="file" name="resume">

                    Choose a file…

      <button class="delete" @click="hideNotifications"></button>{{notification.message}}

    <button v-if="content.state === 'saved'" type="submit" class="button is-success" @click="update(true)">Update and publish</button>
    <button type="submit" class="button is-info" @click="update(false)">Update</button>
    <router-link :to="'/admin/content/' + $route.params.key" class="button is-danger">Cancel</router-link>

</template>

<template>

          {{ field.name }}

            <input type="text" class="input" maxlength="25" required :placeholder="field.name" v-model="content[field.name]">

          {{ field.name }}

            <textarea class="input" v-model="content[field.name]" :placeholder="field.name" v-text="content[field.name]"></textarea>

          <quill-editor v-model="content[field.name]" :options="editorOptions">
          </quill-editor>
          <input type="file" id="getImage" style="display: none;" @change="uploadImage">

          {{ field.name }}

                <select>
                  <option v-for="(selectOption, selectIndex) in content[field.name]" :key="selectIndex">{{ selectOption }}</option>
                </select>

                {{option}}
                <button class="delete is-small"></button>

            <input type="text" class="input" :placeholder="field.name" @blur="styleOptions(field.name)" @keyup.enter="styleOptions(field.name)" v-model="selectOptionsRow" maxlength="25">

Separate options with commas

          {{ field.name }}

              {{tag}}
                <button class="delete is-small"></button>

              <input :placeholder="field.name" @blur="styleTags(field.name)" @keyup.enter="styleTags(field.name)" type="text" class="input" maxlength="25" v-model="inputData">

Separate tags with commas

          {{ field.name }}

                <input @change="uploadFeaturedImage($event, field.name)" class="file-input" type="file" name="resume">

                    Choose a file…

      <button class="delete" @click="hideNotifications"></button>{{notification.message}}

    <button v-if="content.state === 'saved'" type="submit" class="button is-success" @click="update(true)">Update and publish</button>
    <button type="submit" class="button is-info" @click="update(false)">Update</button>
    <router-link :to="'/admin/content/' + $route.params.key" class="button is-danger">Cancel</router-link>

</template>


Fix #2228

Fix #2228

<template>

	<router-link class="mk-avatar" :class="{ cat }" :to="user | userPage" :title="user | acct" :target="target" v-else-if="!disableLink && !disablePreview" v-user-preview="user.id">

	</router-link>
	<router-link class="mk-avatar" :class="{ cat }" :to="user | userPage" :title="user | acct" :target="target" v-else-if="!disableLink && disablePreview">

	</router-link>
</template>


Fix bug

Fix bug

<template>
<form class="mk-signin" :class="{ signing }" @submit.prevent="onSubmit">
	<div class="avatar" :style="{ backgroundImage: user ? `url('${ user.avatarUrl }')` : null }" v-show="withAvatar">

	<ui-input v-model="username" type="text" pattern="^[a-zA-Z0-9_]+$" spellcheck="false" autofocus required @input="onUsernameChange">
		%i18n:@username%
		@
		@{{ host }}
	</ui-input>
	<ui-input v-model="password" type="password" required>
		%i18n:@password%
		%fa:lock%
	</ui-input>
	<ui-input v-if="user && user.twoFactorEnabled" v-model="token" type="number" required/>
	<ui-button type="submit" :disabled="signing">{{ signing ? '%i18n:@signing-in%' : '%i18n:@signin%' }}</ui-button>

%i18n:@or% <a :href="`${apiUrl}/signin/twitter`">%i18n:@signin-with-twitter%

</form>
</template>


Improve usability

Improve usability

<template>

	<ui-container :body-togglable="true">
		<template #header><fa :icon="faUsers"/> {{ $t('owned-groups') }}</template>
		<ui-margin>
			<ui-button @click="add"><fa :icon="faPlus"/> {{ $t('create-group') }}</ui-button>
		</ui-margin>

			<ui-hr/>
			<ui-margin>
				<router-link :to="`/i/groups/${group.id}`">{{ group.name }}</router-link>
			</ui-margin>

	</ui-container>

	<ui-container :body-togglable="true">
		<template #header><fa :icon="faUsers"/> {{ $t('joined-groups') }}</template>

			<ui-hr v-if="i != 0"/>
			<ui-margin>
				<router-link :to="`/i/groups/${group.id}`">{{ group.name }}</router-link>
			</ui-margin>

	</ui-container>

	<ui-container :body-togglable="true">
		<template #header><fa :icon="faEnvelopeOpenText"/> {{ $t('invites') }}</template>

			<ui-hr v-if="i != 0"/>
			<ui-margin>

{{ invite.group.name }}

				<ui-horizon-group>
					<ui-button @click="acceptInvite(invite)"><fa :icon="faCheck"/> {{ $t('accept-invite') }}</ui-button>
					<ui-button @click="rejectInvite(invite)"><fa :icon="faBan"/> {{ $t('reject-invite') }}</ui-button>
				</ui-horizon-group>
			</ui-margin>

	</ui-container>

</template>

<template>

	<ui-container>
		<template #header><fa :icon="faUsers"/> {{ $t('owned-groups') }}</template>
		<ui-margin>
			<ui-button @click="add"><fa :icon="faPlus"/> {{ $t('create-group') }}</ui-button>
		</ui-margin>

			<ui-hr/>
			<ui-margin>
				<router-link :to="`/i/groups/${group.id}`">{{ group.name }}</router-link>
			</ui-margin>

	</ui-container>

	<ui-container>
		<template #header><fa :icon="faUsers"/> {{ $t('joined-groups') }}</template>

			<ui-hr v-if="i != 0"/>
			<ui-margin>
				<router-link :to="`/i/groups/${group.id}`">{{ group.name }}</router-link>
			</ui-margin>

	</ui-container>

	<ui-container>
		<template #header><fa :icon="faEnvelopeOpenText"/> {{ $t('invites') }}</template>

			<ui-hr v-if="i != 0"/>
			<ui-margin>

{{ invite.group.name }}

				<ui-horizon-group>
					<ui-button @click="acceptInvite(invite)"><fa :icon="faCheck"/> {{ $t('accept-invite') }}</ui-button>
					<ui-button @click="rejectInvite(invite)"><fa :icon="faBan"/> {{ $t('reject-invite') }}</ui-button>
				</ui-horizon-group>
			</ui-margin>

	</ui-container>

</template>


:art:

:art:

<template>

 0">

	<slot name="empty" v-if="notes.length == 0 && !fetching && requestInitPromise == null"></slot>

%fa:exclamation-triangle% %i18n:common.error.title%

		<ui-button @click="resolveInitPromise">%i18n:common.error.retry%</ui-button>

		<template v-for="i in 10">
			<mk-note-skeleton :key="i"/>
		</template>

	<component :is="!$store.state.device.reduceMotion ? 'transition-group' : 'div'" name="mk-notes" class="notes transition" tag="div" ref="notes">
		<template v-for="(note, i) in _notes">
			<x-note :note="note" :key="note.id" @update:note="onNoteUpdated(i, $event)" ref="note"/>

				%fa:angle-up%{{ note._datetext }}
				%fa:angle-down%{{ _notes[i + 1]._datetext }}

		</template>
	</component>

		<button @click="loadMore" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }">
			<template v-if="!moreFetching">%i18n:@load-more%</template>
			<template v-if="moreFetching">%fa:spinner .pulse .fw%</template>
		</button>

</template>


Implement vuetify active list item

Implement vuetify active list item

<template>
  <v-list three-line>
    <v-list-item v-for="option in activityContent.options().items" :key="option.id" class="px-0">
      <template #default="{ active }">
        <v-list-item-action>
          <api-checkbox fieldname="checked" :value="active" :uri="option._meta.self" />
        </v-list-item-action>
        <v-list-item-content>
          <v-list-item-title>{{ $tc(`activityContent.laThematicArea.entity.option.${option.translateKey}.name`) }}</v-list-item-title>
          <v-list-item-subtitle>{{ $tc(`activityContent.laThematicArea.entity.option.${option.translateKey}.description`) }}</v-list-item-subtitle>
        </v-list-item-content>
      </template>
    </v-list-item>
  </v-list>
</template>

<script>

import ApiCheckbox from '@/components/form/api/ApiCheckbox'

export default {
  name: 'LAThematicArea',
  components: { ApiCheckbox },
  props: {
    activityContent: { type: Object, required: true }
  },
  methods: {
    async refreshContent () {
      await this.api.reload(this.activityContent)
    }
  }
}
</script>

<template>
  <v-list three-line>
    <v-list-item v-for="option in activityContent.options().items" :key="option.id" class="px-0">
      <v-list-item-action>
        <api-checkbox fieldname="checked" :uri="option._meta.self" />
      </v-list-item-action>
      <v-list-item-content>
        <v-list-item-title>{{ $tc(`activityContent.laThematicArea.entity.option.${option.translateKey}.name`) }}</v-list-item-title>
        <v-list-item-subtitle>{{ $tc(`activityContent.laThematicArea.entity.option.${option.translateKey}.description`) }}</v-list-item-subtitle>
      </v-list-item-content>
    </v-list-item>
  </v-list>
</template>

<script>

import ApiCheckbox from '@/components/form/api/ApiCheckbox'

export default {
  name: 'LAThematicArea',
  components: { ApiCheckbox },
  props: {
    activityContent: { type: Object, required: true }
  },
  methods: {
    async refreshContent () {
      await this.api.reload(this.activityContent)
    }
  }
}
</script>


edit sprites

edit sprites

<template>

  <div class="card" v-for='u in pageConfig.page_item_num' v-if="((pageConfig.current_page-1)*pageConfig.page_item_num+$index) < dataset.length" track-by="$index" >

      <input type="text" maxlength="50" class="sprite-name" :value="dataset[(pageConfig.current_page-1)*pageConfig.page_item_num+$index].name" @change="uploadNameChange($event, (pageConfig.current_page-1)*pageConfig.page_item_num+$index)"/>
      <mdl-anchor-button accent raised v-mdl-ripple-effect style="min-width: 88px;" @click="showPreview($event, (pageConfig.current_page-1)*pageConfig.page_item_num+$index)">预览</mdl-anchor-button>

      上传时间：{{ dataset[(pageConfig.current_page-1)*pageConfig.page_item_num+$index].createdAt }}
      共享范围：<select id="icon-scope" v-model="dataset[(pageConfig.current_page-1)*pageConfig.page_item_num+$index].scope" @change="editScope($event, (pageConfig.current_page-1)*pageConfig.page_item_num+$index)">
          <option value="private">私有</option>
          <option value="public">公开</option>
        </select>

      <mdl-anchor-button colored v-mdl-ripple-effect class = "delete-button" @click="deleteSprite(dataset[(pageConfig.current_page-1)*pageConfig.page_item_num+$index].sprite_id)">删除</mdl-anchor-button>

          图标说明

            <input type="text" :value="dataset[(pageConfig.current_page-1)*pageConfig.page_item_num+$index].description" @change="editDescription($event, (pageConfig.current_page-1)*pageConfig.page_item_num+$index)">

          图标详情（{{sprite.icons.length}}）

0?true:false">

 1?'':'disabled'">
        navigate_before

{{ pageConfig.first_page + page }}

 1)&&(pageConfig.current_page < parseInt(total_items/pageConfig.page_item_num)+1)?'':'disabled'">
        navigate_next

  <foxgis-dialog id="delete-dialog" class='modal' :dialog="dialogcontent" @dialog-action="deleteAction"></foxgis-dialog>

</template>

<template>

  <div class="card" v-for='u in pageConfig.page_item_num' v-if="((pageConfig.current_page-1)*pageConfig.page_item_num+$index) < dataset.length" track-by="$index" >

      <input type="text" maxlength="50" class="sprite-name" :value="dataset[(pageConfig.current_page-1)*pageConfig.page_item_num+$index].name" @change="uploadNameChange($event, (pageConfig.current_page-1)*pageConfig.page_item_num+$index)"/>
      <mdl-anchor-button accent raised v-mdl-ripple-effect style="min-width: 88px;" @click="showPreview($event, (pageConfig.current_page-1)*pageConfig.page_item_num+$index)">预览</mdl-anchor-button>

      上传时间：{{ dataset[(pageConfig.current_page-1)*pageConfig.page_item_num+$index].createdAt }}
      共享范围：<select id="icon-scope" v-model="dataset[(pageConfig.current_page-1)*pageConfig.page_item_num+$index].scope" @change="editScope($event, (pageConfig.current_page-1)*pageConfig.page_item_num+$index)">
          <option value="private">私有</option>
          <option value="public">公开</option>
        </select>

      <mdl-anchor-button colored v-mdl-ripple-effect class = "delete-button" @click="deleteSprite(dataset[(pageConfig.current_page-1)*pageConfig.page_item_num+$index].sprite_id)">删除</mdl-anchor-button>

      <foxgis-icon-panel :dataset="sprite" class="icon-panel"></foxgis-icon-panel>

0?true:false">

 1?'':'disabled'">
        navigate_before

{{ pageConfig.first_page + page }}

 1)&&(pageConfig.current_page < parseInt(total_items/pageConfig.page_item_num)+1)?'':'disabled'">
        navigate_next

  <foxgis-dialog id="delete-dialog" class='modal' :dialog="dialogcontent" @dialog-action="deleteAction"></foxgis-dialog>

</template>


Change important section to allow favorites too

Signed-off-by: GretaD <9a2413ca1cbc98a3d95fc4d94b0952e5a7369afd@gmail.com>

<template>
	<AppContent>
		<AppDetailsToggle v-if="showMessage" @close="hideMessage" />
		<div id="app-content-wrapper">
			<AppContentList
				v-infinite-scroll="onScroll"
				v-shortkey.once="shortkeys"
				infinite-scroll-immediate-check="false"
				:show-details="showMessage"
				:infinite-scroll-disabled="false"
				:infinite-scroll-distance="10"
				@shortkey.native="onShortcut"
			>
				<Mailbox
					v-if="!folder.isPriorityInbox"
					:account="account"
					:folder="folder"
					:search-query="query"
					:bus="bus"
				/>
				<template v-else>
					<SectionTitle class="app-content-list-item important" :name="t('mail', 'Priority')" />
					<Mailbox
						class="nameimportant"
						:account="unifiedAccount"
						:folder="unifiedInbox"
						:paginate="false"
						:search-query="appendToSearch('is:important')"
						:bus="bus"
					/>
					<SectionTitle class="app-content-list-item starred" :name="t('mail', 'Favorites')" />
					<Mailbox
						class="namestarred"
						:account="unifiedAccount"
						:folder="unifiedInbox"
						:paginate="false"
						:search-query="appendToSearch('is:starred not:important')"
						:bus="bus"
					/>
					<SectionTitle class="app-content-list-item other" :name="t('mail', 'Other')" />
					<Mailbox
						class="nameother"
						:account="unifiedAccount"
						:folder="unifiedInbox"
						:open-first="false"
						:search-query="appendToSearch('not:starred not:important')"
						:bus="bus"
					/>
				</template>
			</AppContentList>
			<NewMessageDetail v-if="newMessage" />
			<Message v-else-if="showMessage" @delete="deleteMessage" />
			<NoMessageSelected v-else-if="hasMessages && !isMobile" />
		</div>
	</AppContent>
</template>

<script>
import AppContent from '@nextcloud/vue/dist/Components/AppContent'
import AppContentList from '@nextcloud/vue/dist/Components/AppContentList'
import infiniteScroll from 'vue-infinite-scroll'
import isMobile from '@nextcloud/vue/dist/Mixins/isMobile'
import SectionTitle from './SectionTitle'
import Vue from 'vue'

import AppDetailsToggle from './AppDetailsToggle'
import logger from '../logger'
import Mailbox from './Mailbox'
import Message from './Message'
import NewMessageDetail from './NewMessageDetail'
import NoMessageSelected from './NoMessageSelected'
import {normalizedEnvelopeListId} from '../store/normalization'
import {UNIFIED_ACCOUNT_ID, UNIFIED_INBOX_ID} from '../store/constants'

export default {
	name: 'MailboxMessage',
	directives: {
		infiniteScroll,
	},
	components: {
		AppContent,
		AppContentList,
		AppDetailsToggle,
		Mailbox,
		Message,
		NewMessageDetail,
		NoMessageSelected,
		SectionTitle,
	},
	mixins: [isMobile],
	props: {
		account: {
			type: Object,
			required: true,
		},
		folder: {
			type: Object,
			required: true,
		},
	},
	data() {
		return {
			alive: false,
			bus: new Vue(),
			searchQuery: undefined,
			shortkeys: {
				del: ['del'],
				flag: ['s'],
				next: ['arrowright'],
				prev: ['arrowleft'],
				refresh: ['r'],
				unseen: ['u'],
			},
		}
	},
	computed: {
		unifiedAccount() {
			return this.$store.getters.getAccount(UNIFIED_ACCOUNT_ID)
		},
		unifiedInbox() {
			return this.$store.getters.getFolder(UNIFIED_ACCOUNT_ID, UNIFIED_INBOX_ID)
		},
		hasMessages() {
			// it actually should be `return this.$store.getters.getEnvelopes(this.account.id, this.folder.id).length > 0`
			// but for some reason Vue doesn't track the dependencies on reactive data then and messages in subfolders can't
			// be opened then
			const list = this.folder.envelopeLists[normalizedEnvelopeListId(this.searchQuery)]

			if (list === undefined) {
				return false
			}
			return list.length > 0
		},
		showMessage() {
			return (this.folder.isPriorityInbox === true || this.hasMessages) && this.$route.name === 'message'
		},
		query() {
			if (this.$route.params.filter === 'starred') {
				if (this.searchQuery) {
					return this.searchQuery + ' is:starred'
				}
				return 'is:starred'
			}
			return this.searchQuery
		},
		newMessage() {
			return (
				this.$route.params.messageUid === 'new' ||
				this.$route.params.messageUid === 'reply' ||
				this.$route.params.messageUid === 'replyAll'
			)
		},
	},
	created() {
		this.alive = true

		new OCA.Search(this.searchProxy, this.clearSearchProxy)
	},
	beforeDestroy() {
		this.alive = false
	},
	methods: {
		hideMessage() {
			this.$router.replace({
				name: 'folder',
				params: {
					accountId: this.account.id,
					folderId: this.folder.id,
					filter: this.$route.params.filter ? this.$route.params.filter : undefined,
				},
			})
		},
		deleteMessage(envelopeUid) {
			this.bus.$emit('delete', envelopeUid)
		},
		onScroll(event) {
			logger.debug('scroll', {event})

			this.bus.$emit('loadMore')
		},
		onShortcut(e) {
			this.bus.$emit('shortcut', e)
		},
		appendToSearch(str) {
			if (this.searchQuery === undefined) {
				return str
			}
			return this.searchQuery + ' ' + str
		},
		searchProxy(query) {
			if (this.alive) {
				this.search(query)
			}
		},
		clearSearchProxy() {
			if (this.alive) {
				this.clearSearch()
			}
		},
		search(query) {
			this.searchQuery = query
		},
		clearSearch() {
			this.searchQuery = undefined
		},
	},
}
</script>

<style scoped></style>

<template>
	<AppContent>
		<AppDetailsToggle v-if="showMessage" @close="hideMessage" />
		<div id="app-content-wrapper">
			<AppContentList
				v-infinite-scroll="onScroll"
				v-shortkey.once="shortkeys"
				infinite-scroll-immediate-check="false"
				:show-details="showMessage"
				:infinite-scroll-disabled="false"
				:infinite-scroll-distance="10"
				@shortkey.native="onShortcut"
			>
				<Mailbox
					v-if="!folder.isPriorityInbox"
					:account="account"
					:folder="folder"
					:search-query="query"
					:bus="bus"
				/>
				<template v-else>
					<SectionTitle class="app-content-list-item important" :name="t('mail', 'Priority')" />
					<Mailbox
						class="nameimportant"
						:account="unifiedAccount"
						:folder="unifiedInbox"
						:paginate="false"
						:search-query="appendToSearch('is:important not:starred')"
						:bus="bus"
					/>
					<SectionTitle class="app-content-list-item starred" :name="t('mail', 'Favorites')" />
					<Mailbox
						class="namestarred"
						:account="unifiedAccount"
						:folder="unifiedInbox"
						:paginate="false"
						:search-query="appendToSearch('is:starred not:important')"
						:bus="bus"
					/>
					<SectionTitle class="app-content-list-item other" :name="t('mail', 'Other')" />
					<Mailbox
						class="nameother"
						:account="unifiedAccount"
						:folder="unifiedInbox"
						:open-first="false"
						:search-query="appendToSearch('not:starred not:important')"
						:bus="bus"
					/>
				</template>
			</AppContentList>
			<NewMessageDetail v-if="newMessage" />
			<Message v-else-if="showMessage" @delete="deleteMessage" />
			<NoMessageSelected v-else-if="hasMessages && !isMobile" />
		</div>
	</AppContent>
</template>

<script>
import AppContent from '@nextcloud/vue/dist/Components/AppContent'
import AppContentList from '@nextcloud/vue/dist/Components/AppContentList'
import infiniteScroll from 'vue-infinite-scroll'
import isMobile from '@nextcloud/vue/dist/Mixins/isMobile'
import SectionTitle from './SectionTitle'
import Vue from 'vue'

import AppDetailsToggle from './AppDetailsToggle'
import logger from '../logger'
import Mailbox from './Mailbox'
import Message from './Message'
import NewMessageDetail from './NewMessageDetail'
import NoMessageSelected from './NoMessageSelected'
import {normalizedEnvelopeListId} from '../store/normalization'
import {UNIFIED_ACCOUNT_ID, UNIFIED_INBOX_ID} from '../store/constants'

export default {
	name: 'MailboxMessage',
	directives: {
		infiniteScroll,
	},
	components: {
		AppContent,
		AppContentList,
		AppDetailsToggle,
		Mailbox,
		Message,
		NewMessageDetail,
		NoMessageSelected,
		SectionTitle,
	},
	mixins: [isMobile],
	props: {
		account: {
			type: Object,
			required: true,
		},
		folder: {
			type: Object,
			required: true,
		},
	},
	data() {
		return {
			alive: false,
			bus: new Vue(),
			searchQuery: undefined,
			shortkeys: {
				del: ['del'],
				flag: ['s'],
				next: ['arrowright'],
				prev: ['arrowleft'],
				refresh: ['r'],
				unseen: ['u'],
			},
		}
	},
	computed: {
		unifiedAccount() {
			return this.$store.getters.getAccount(UNIFIED_ACCOUNT_ID)
		},
		unifiedInbox() {
			return this.$store.getters.getFolder(UNIFIED_ACCOUNT_ID, UNIFIED_INBOX_ID)
		},
		hasMessages() {
			// it actually should be `return this.$store.getters.getEnvelopes(this.account.id, this.folder.id).length > 0`
			// but for some reason Vue doesn't track the dependencies on reactive data then and messages in subfolders can't
			// be opened then
			const list = this.folder.envelopeLists[normalizedEnvelopeListId(this.searchQuery)]

			if (list === undefined) {
				return false
			}
			return list.length > 0
		},
		showMessage() {
			return (this.folder.isPriorityInbox === true || this.hasMessages) && this.$route.name === 'message'
		},
		query() {
			if (this.$route.params.filter === 'starred') {
				if (this.searchQuery) {
					return this.searchQuery + ' is:starred'
				}
				return 'is:starred'
			}
			return this.searchQuery
		},
		newMessage() {
			return (
				this.$route.params.messageUid === 'new' ||
				this.$route.params.messageUid === 'reply' ||
				this.$route.params.messageUid === 'replyAll'
			)
		},
	},
	created() {
		this.alive = true

		new OCA.Search(this.searchProxy, this.clearSearchProxy)
	},
	beforeDestroy() {
		this.alive = false
	},
	methods: {
		hideMessage() {
			this.$router.replace({
				name: 'folder',
				params: {
					accountId: this.account.id,
					folderId: this.folder.id,
					filter: this.$route.params.filter ? this.$route.params.filter : undefined,
				},
			})
		},
		deleteMessage(envelopeUid) {
			this.bus.$emit('delete', envelopeUid)
		},
		onScroll(event) {
			logger.debug('scroll', {event})

			this.bus.$emit('loadMore')
		},
		onShortcut(e) {
			this.bus.$emit('shortcut', e)
		},
		appendToSearch(str) {
			if (this.searchQuery === undefined) {
				return str
			}
			return this.searchQuery + ' ' + str
		},
		searchProxy(query) {
			if (this.alive) {
				this.search(query)
			}
		},
		clearSearchProxy() {
			if (this.alive) {
				this.clearSearch()
			}
		},
		search(query) {
			this.searchQuery = query
		},
		clearSearch() {
			this.searchQuery = undefined
		},
	},
}
</script>

<style scoped></style>


Add basic emoji support

Add basic emoji support

<template>

            <input id="attach" class="mdl-button mdl-js-button mdl-button--icon attach-button" type="image" src="../../assets/images/ic_attach.png"/>
            <input id="emoji" class="mdl-button mdl-js-button mdl-button--icon emoji-button" type="image" src="../../assets/images/ic_mood.png" @click="toggleEmoji"/>
            <Picker set="emojione" :style="emojiStyle"  :set="set" :per-line="perLine" :skins="skin" :onItemClick="insertEmoji" v-show="show_emoji"/>

                <textarea class="mdl-textfield__input disabled" type="text" id="message-entry" autofocus @keydown.shift.enter.stop @keydown.enter.prevent.stop="dispatchSend" v-model="message"></textarea>
                Type message...

            <button class="send mdl-button mdl-js-button mdl-button--fab mdl-button--mini-fab mdl-button--colored mdl-js-ripple-effect" id="send-button" @click="dispatchSend">
                send
            </button>

</template>

<template>

            <input id="attach" class="mdl-button mdl-js-button mdl-button--icon attach-button" type="image" src="../../assets/images/ic_attach.png"/>
            <input id="emoji" class="mdl-button mdl-js-button mdl-button--icon emoji-button" type="image" src="../../assets/images/ic_mood.png"/>
            <Picker set="emojione"/>

                <textarea class="mdl-textfield__input disabled" type="text" id="message-entry" autofocus @keydown.shift.enter.stop @keydown.enter.prevent.stop="dispatchSend" v-model="message"></textarea>
                Type message...

            <button class="send mdl-button mdl-js-button mdl-button--fab mdl-button--mini-fab mdl-button--colored mdl-js-ripple-effect" id="send-button" @click="dispatchSend">
                send
            </button>

</template>


[tasks] Fix end date and estimation deletion

<template>

            {{ $t('tasks.fields.asset_type') }}

            {{ $t('tasks.fields.sequence') }}

            {{ $t('tasks.fields.entity_name') }}

            {{ $t('tasks.fields.task_status') }}

            {{ $t('tasks.fields.assignees') }}

            {{ $t('tasks.fields.frames') }}

            {{ $t('tasks.fields.estimation').substring(0, 3) }}.

            {{ $t('tasks.fields.duration').substring(0, 3) }}.

            {{ $t('tasks.fields.retake_count') }}

            {{ $t('tasks.fields.start_date') }}

            {{ $t('tasks.fields.due_date') }}

            {{ $t('tasks.fields.real_start_date') }}

            {{ $t('tasks.fields.real_end_date') }}

            {{ $t('tasks.fields.last_comment_date') }}

            <entity-thumbnail
              class="flexrow-item"
              :entity="getEntity(task.entity.id)"
              :width="50"
              :height="33"
              :empty-width="50"
              :empty-height="33"
            />

            {{ getEntity(task.entity.id).asset_type_name }}

            {{ getEntity(task.entity.id).sequence_name }}

            {{ getEntity(task.entity.id).name }}

          <validation-cell
            class="status unselectable"
            :task-test="task"
            :is-border="false"
            :is-assignees="false"
            :selectable="false"
            :is-static="true"
          />

              <people-avatar
                class="flexrow-item"
                :key="task.id + '-' + personId"
                :person="personMap[personId]"
                :size="30"
                :font-size="17"
                v-for="personId in task.assignees"
              />

            {{ getEntity(task.entity.id).nb_frames }}

            <input
              v-if="selectionGrid[task.id]"
              :ref="task.id + '-estimation'"
              class="input"
              @change="updateEstimation($event.target.value)"
              :value="formatDuration(task.estimation)"
            />

              {{ formatDuration(task.estimation) }}

            {{ formatDuration(task.duration) }}

              •

            <date-field
              class="flexrow-item"
              :with-margin="false"
              :value="getDate(task.start_date)"
              @input="updateStartDate"
              v-if="selectionGrid[task.id]"
            />

              {{ formatDate(task.start_date) }}

            <date-field
              class="flexrow-item"
              :with-margin="false"
              :value="getDate(task.due_date)"
              @input="updateDueDate"
              v-if="selectionGrid[task.id]"
            />

              {{ formatDate(task.due_date) }}

            {{ formatDate(task.real_start_date) }}

            {{ formatDate(task.end_date) }}

            {{ formatDate(task.last_comment_date) }}

    {{ tasks.length }} {{ $tc('tasks.number', tasks.length) }}
    ({{ formatDuration(timeEstimated) }}
     {{ $tc('main.days_estimated', isTimeEstimatedPlural) }},
     {{ formatDuration(timeSpent) }}
     {{ $tc('main.days_spent', isTimeSpentPlural) }},
     {{ nbFrames }} {{ $tc('main.nb_frames', nbFrames) }})

</template>


refactor: use getPoll usecase

refactor: use getPoll usecase

<template>

{{ internalPoll.prompt }}

          <emojify :text="option.text" />

                  <emojify :text="option.text" />

                    {{ getPercent(option) }}%

                      {{ option.respondents }}

          Total: {{ total }}

          <nuxt-link :to="`/polls/${internalPoll.id}`" class="text-muted">

            Closed at

              ~

            {{ until }}
          </nuxt-link>

</template>


Fix the link in SongCards

Fix the link in SongCards

<template>

      <toggle-play-button-container v-if="isActive"></toggle-play-button-container>

        <router-link
          class="song-card-title"
          :title="song.title"
          :to="{ name: 'songDetail', params: { id: songId } }"
        >
          {{ title }}
        </router-link>

        <router-link
          class="song-card-user-username"
          :title="user.username"
          :to="{ name: 'userDetail', params: { id: user.id } }"
        >
          {{ user.username }}
        </router-link>

        <song-heart
          :className="'song-card-heart'"
          :authedUser="authedUser"
          :isLiked="isLiked"
        >
        </song-heart>

</template>

<template>

      <toggle-play-button-container v-if="isActive"></toggle-play-button-container>

        <router-link
          class="song-card-title"
          :title="song.title"
          :to="{ name: 'songs', params: { id: songId } }"
        >
          {{ title }}
        </router-link>

        <router-link
          class="song-card-user-username"
          :title="user.username"
          to="/"
        >
          {{ user.username }}
        </router-link>

        <song-heart
          :className="'song-card-heart'"
          :authedUser="authedUser"
          :isLiked="isLiked"
        >
        </song-heart>

</template>


Include meta data about validation

Include meta data about validation

// Component provides an interface for cycling through the megakaryocytes
// predictions in the interface and provide validated feedback
<template>

      {{ steps[activeStep].instruction }}

      <v-divider></v-divider>

        <v-btn small color="primary" @click="beginValidation"> Begin </v-btn>

      <v-container fluid id="validation-controls" v-else>
        <v-layout>
          <v-flex xs2>

            <v-btn flat icon color="primary" @click="previousMega">
              <v-icon> arrow_back </v-icon>
            </v-btn>
          </v-flex>

          <v-flex xs8>
            <v-layout align-center justify-center>

                Mega: {{ this.activeMegaIndex + 1  }} / {{ this.getMegas().length }}
                Score: {{ Math.round(this.getMegas()[this.activeMegaIndex].data.score * 100) / 100 }}

            </v-layout>
            <v-divider></v-divider>
            <v-layout align-center justify-center>

              <v-btn small color="success"
              :outline="!(this.activeValidationButton === 'correct')"
              :depressed="this.activeValidationButton === 'correct'"
              @click="markCorrect"
              >
                Correct
              </v-btn>
              <v-btn small color="warning"
              :outline="!(this.activeValidationButton === 'flag')"
              :depressed="this.activeValidationButton === 'flag'"
              @click="flagForReview">
                Flag for review
              </v-btn>
              <v-btn small color="error"
              :outline="!(this.activeValidationButton === 'incorrect')"
              :depressed="this.activeValidationButton === 'incorrect'"
              @click="markIncorrect">
                Incorrect
              </v-btn>
            </v-layout>
          </v-flex>

          <v-flex xs2 text-xs-right>

            <v-btn flat icon color="primary" @click="nextMega">
              <v-icon> arrow_forward </v-icon>
            </v-btn>
          </v-flex>
        </v-layout>
      </v-container>

</template>

// Component provides an interface for cycling through the megakaryocytes
// predictions in the interface and provide validated feedback
<template>

      {{ steps[activeStep].instruction }}

      <v-divider></v-divider>

      <v-container fluid id="validation-controls">
        <v-layout>
          <v-flex xs2>

            <v-btn flat icon color="primary" @click="previousMega">
              <v-icon> arrow_back </v-icon>
            </v-btn>
          </v-flex>

          <v-flex xs8>
            <v-layout align-center justify-center>

                Mega: {{ this.activeMegaIndex + 1  }} / {{ this.getMegas().length }}

            </v-layout>
            <v-divider></v-divider>
            <v-layout align-center justify-center>

              <v-btn small color="success"
              :outline="!(this.activeValidationButton === 'correct')"
              :depressed="this.activeValidationButton === 'correct'"
              @click="markCorrect"
              >
                Correct
              </v-btn>
              <v-btn small color="warning"
              :outline="!(this.activeValidationButton === 'adjusted')"
              :depressed="this.activeValidationButton === 'adjusted'"
              @click="markAdjusted">
                Adjust
              </v-btn>
              <v-btn small color="error"
              :outline="!(this.activeValidationButton === 'incorrect')"
              :depressed="this.activeValidationButton === 'incorrect'"
              @click="markIncorrect">
                Incorrect
              </v-btn>
            </v-layout>
          </v-flex>

          <v-flex xs2 text-xs-right>

            <v-btn flat icon color="primary" @click="nextMega">
              <v-icon> arrow_forward </v-icon>
            </v-btn>
          </v-flex>
        </v-layout>
      </v-container>

</template>


Fix clearing of annotation after displaying comments

<template>

      {{ $t('playlists.client_playlist') }}

      {{ playlist.name }}

    <button-simple
      @click="$emit('show-add-shots')"
      class="playlist-button add-shots-button flexrow-item"
      icon="plus"
      text="Add Shots"
      v-if="isCurrentUserManager && !isAddingShot"
    />
    <button-simple
      @click="$emit('edit-clicked')"
      class="edit-button playlist-button flexrow-item"
      icon="edit"
      v-if="isCurrentUserManager"
    />
    <button-simple
      @click="showDeleteModal"
      class="delete-button playlist-button flexrow-item"
      icon="delete"
      v-if="isCurrentUserManager"
    />

    <raw-video-player
      class="raw-player"
      ref="raw-player"
      :shots="shotList"
      @metadata-loaded="onMetadataLoaded"
      @shot-change="onShotChange"
      @time-update="onTimeUpdate"
      @max-duration-update="onMaxDurationUpdate"
    />
    <raw-video-player
      class="raw-player"
      ref="raw-player-comparison"
      :shots="shotListToCompare"
      v-if="isComparing"
    />

      <canvas
        id="annotation-canvas"
        ref="annotation-canvas"
        class="canvas"
      >
      </canvas>

    <task-info
      ref="task-info"
      :class="{
        'flexrow-item': true,
        'task-info-column': true,
        'hidden': isCommentsHidden
      }"
      :task="task"
      :is-preview="false"
    />

      <progress
        ref="progress"
        value="0"
        min="0"
        @click="onProgressBarClicked"
      >

      </progress>

  <annotation-bar
    class="playlist-annotations"
    ref="playlist-annotation"
    :annotations="annotations"
    :max-duration-raw="maxDurationRaw"
    @select-annotation="loadAnnotation"
    v-if="playlist.id && !isAddingShot"
  />

    <button-simple
      class="button playlist-button flexrow-item"
      @click="onPlayClicked"
      icon="play"
      v-if="!isPlaying"
    />
    <button-simple
      class="button playlist-button flexrow-item"
      @click="onPlayClicked"
      icon="pause"
      v-else
    />

      {{ currentTime }}

    /

      {{ maxDuration }}

      ({{ currentFrame }})

    <button-simple
      class="button playlist-button flexrow-item"
      @click="onPreviousFrameClicked"
      icon="left"
    />
    <button-simple
      class="button playlist-button flexrow-item"
      @click="onNextFrameClicked"
      icon="right"
    />

      {{ shotList.length > 0 ? playingShotIndex + 1 : 0 }}

    /

      {{ shotList.length }}

    <button-simple
      class="button playlist-button flexrow-item"
      @click="onPlayPreviousShotClicked"
      icon="back"
    />
    <button-simple
      class="playlist-button flexrow-item"
      @click="onPlayNextShotClicked"
      icon="forward"
    />
    <button-simple
      :class="{
        'comparison-button': true,
        'flexrow-item': true,
        'playlist-button': true,
        active: isComparing
      }"
      icon="compare"
      @click="onCompareClicked"
      v-if="taskTypeOptions"
    />
    <combobox
      class="playlist-button flexrow-item comparison-list"
      :options="taskTypeOptions"
      v-model="taskTypeToCompare"
      v-if="isComparing"
    />

    <button-simple
      class="playlist-button flexrow-item"
      icon="undo"
      @click="undoLastAction"
    />

    <button-simple
      class="playlist-button flexrow-item"
      icon="redo"
      @click="redoLastAction"
    />

    <pencil-picker
      :isActive="isDrawing"
      :isOpen="isShowingPencilPalette"
      :pencil="pencil"
      :palette="this.pencilPalette"
      @toggle-palette="onPickPencil"
      @change="onChangePencil"
    />

    <color-picker
      :isActive="isDrawing"
      :isOpen="isShowingPalette"
      :color="this.color"
      :palette="this.palette"
      @TogglePalette="onPickColor"
      @change="onChangeColor"
    />

    <button-simple
      :class="{
        'playlist-button': true,
        'flexrow-item': true,
        active: isDrawing
      }"
      @click="onAnnotateClicked"
      icon="pencil"
    />
    <button-simple
      class="playlist-button flexrow-item"
      icon="remove"
      @click="onDeleteClicked"
    />
    <button-simple
      class="button playlist-button flexrow-item"
      @click="onCommentClicked"
      icon="comment"
    />
    <button-simple
      class="playlist-button flexrow-item"
      @click="onFilmClicked"
      icon="film"
    />

        {{ $t('playlists.download_zip') }}

        {{ $t('playlists.build_mp4') }}

        {{ $t('playlists.no_build') }}

            {{ $t('playlists.available_build') }}

              {{ formatDate(job.created_at) }}

            <spinner
              class="build-spinner"
              v-if="job.status === 'running'"
            />
            <button
              class="delete-job-button"
              @click="onRemoveBuildJob(job)"
              v-else
            >
              x
            </button>

      <button-simple
        class="playlist-button"
        icon="download"
        @click="toggleDlButtons"
      />

    <button-simple
      class="button playlist-button flexrow-item"
      @click="onFullscreenClicked"
      icon="maximize"
      v-if="isFullScreenEnabled"
    />

    <spinner class="spinner" v-if="isLoading" />

      <playlisted-shot
        :ref="'shot-' + index"
        :index="index"
        :shot="shot"
        :is-playing="playingShotIndex === index"
        @play-click="playShot"
        @remove-shot="removeShot"
        @preview-changed="onPreviewChanged"
        @shot-dropped="onShotDropped"
      />

  <delete-modal
    :active="modals.delete"
    :is-loading="loading.deletePlaylist"
    :is-error="errors.deletePlaylist"
    :text="deleteText"
    :error-text="$t('playlists.delete_error')"
    @confirm="confirmRemovePlaylist"
    @cancel="hideDeleteModal"
  />

</template>


[productions] Fix glitches in new production page

<template>

              {{ $t('productions.creation.new_project') }}

              {{ $t('productions.creation.create_production') }}

        <timeline-item
          :title="$t('productions.creation.give_a_name')"
          :subtitle="$t('productions.creation.give_a_name_description')"
          :step="1"
          :is-completed="hasValidName"
        >
          <text-field
            input-class="w600 is-inline"
            :placeholder="$t('productions.creation.placeholder_name')"
            v-model="productionToCreate.name"
          />
        </timeline-item>
        <timeline-item
          :title="$t('productions.creation.production_settings')"
          :subtitle="$t('productions.creation.production_settings_description')"
          :step="2"
          :is-completed="hasValidSettings"
        >

            <combobox
              :options="productionTypeOptions"
              :label="$t('productions.fields.type')"
              localeKeyPrefix="productions.type."
              v-model="productionToCreate.settings.type"
              thin
              is-inline
            />

            {{ $t('productions.creation.explaination_type') }}

            <text-field
              class="flexrow-item"
              input-class=" is-small is-size-3"
              :label="$t('productions.fields.fps')"
              type="number"
              :step="1"
              :placeholder="$t('productions.creation.placeholder_fps')"
              v-model="productionToCreate.settings.fps"
              thin
            />

            <text-field
              class="flexrow-item mr0"
              input-class=" is-small is-size-2"
              :label="$t('productions.fields.ratio')"
              type="number"
              :step="1"
              :placeholder="$t('productions.creation.placeholder_ratio1')"
              v-model="productionToCreate.settings.ratio[0]"
              thin
            />
            :
            <text-field
              class="flexrow-item"
              input-class=" is-small is-size-2"
              type="number"
              :step="1"
              :placeholder="$t('productions.creation.placeholder_ratio2')"
              :empty-label="true"
              v-model="productionToCreate.settings.ratio[1]"
              thin
            />

            <text-field
              class="flexrow-item mr0 ml2"
              input-class=" is-small is-size-4"
              :label="$t('productions.fields.resolution')"
              type="number"
              :step="1"
              :placeholder="$t('productions.creation.placeholder_resolution1')"
              v-model="productionToCreate.settings.resolution[0]"
              thin
            />
            x
            <text-field
              class="flexrow-item"
              input-class=" is-small is-size-4"
              type="number"
              :placeholder="$t('productions.creation.placeholder_resolution2')"
              :step="1"
              :empty-label="true"
              v-model="productionToCreate.settings.resolution[1]"
              thin
            />

            {{ $t('productions.creation.explaination_video') }}

              {{
                $t('productions.creation.start_and_end_dates')
              }}

            <datepicker
              wrapper-class="datepicker"
              input-class=" is-small date-input input"
              label="Start date"
              :placeholder="startDatePlaceholder"
              :language="locale"
              :disabled-dates="{ days: [6, 0] }"
              :monday-first="true"
              format="yyyy-MM-dd"
              v-model="productionToCreate.settings.dateStart"
            />
            -
            <datepicker
              wrapper-class="datepicker"
              input-class="is-small date-input input"
              :language="locale"
              :disabled-dates="{ days: [6, 0] }"
              :placeholder="endDatePlaceholder"
              :monday-first="true"
              :disabledDates="{ to: productionToCreate.settings.dateStart }"
              format="yyyy-MM-dd"
              v-model="productionToCreate.settings.dateEnd"
            />

            {{ $t('productions.creation.explaination_date') }}

        </timeline-item>
        <timeline-item
          :title="$t('productions.creation.select_asset_task_type')"
          :subtitle="$t(
            'productions.creation.select_asset_task_type_description'
           )"
          :step="3"
          :is-completed="hasValidAssetTaskTypes"
        >
          <draggable
            v-model="productionToCreate.assetTaskTypes"
            draggable=".task-type"
          >
            <task-type-name
              class="task-type"
              :task-type="taskType"
              :key="taskType.id"
              deletable
              @delete="deleteFromList(taskType, 'assetTaskTypes')"
              v-for="taskType in productionToCreate.assetTaskTypes"
            />
            <combobox-task-type
              slot="footer"
              class="is-inline"
              :task-type-list="availableAssetTaskTypes"
              add-placeholder
              @input="id => productionToCreate.assetTaskTypes.push(
                taskTypeMap.get(id)
              )"
              v-if="availableAssetTaskTypes.length > 0"
            />
          </draggable>
        </timeline-item>
        <timeline-item
          :title="$t('productions.creation.select_shot_task_type')"
          :subtitle="$t(
            'productions.creation.select_shot_task_type_description'
          )"
          :step="4"
          :is-completed="hasValidShotTaskTypes"
        >
          <draggable
            v-model="productionToCreate.shotTaskTypes"
            draggable=".task-type"
          >
            <task-type-name
              class="task-type"
              :task-type="taskType"
              :key="taskType.id"
              @delete="deleteFromList(taskType, 'shotTaskTypes')"
              deletable
              v-for="taskType in productionToCreate.shotTaskTypes"
            />
            <combobox-task-type
              slot="footer"
              class="is-inline"
              :task-type-list="availableShotTaskTypes"
              add-placeholder
              @input="id => productionToCreate.shotTaskTypes.push(
                taskTypeMap.get(id)
              )"
              v-if="availableShotTaskTypes.length > 0"
            />
          </draggable>
        </timeline-item>
        <timeline-item
          :title="$t('productions.creation.select_task_status')"
          :subtitle="$t('productions.creation.select_task_status_description')"
          :step="5"
          :is-completed="hasValidTaskStatuses"
        >

            <validation-tag
              class="task-status flexrow-item"
              :task="{ task_status_id: taskStatus.id }"
              :key="taskStatus.id"
              pointer
              is-static
              @click="deleteFromList(taskStatus, 'taskStatuses')"
              v-for="taskStatus in productionToCreate.taskStatuses"
            />
            <combobox-status
              slot="footer"
              class="flexrow-item"
              :task-status-list="availableTaskStatuses"
              :with-margin="false"
              add-placeholder
              @input="id => productionToCreate.taskStatuses.push(
                taskStatusMap.get(id)
              )"
              v-if="availableTaskStatuses.length > 0"
            />

        </timeline-item>
        <timeline-item
          :title="$t('productions.creation.add_asset_types')"
          :subtitle="$t('productions.creation.add_asset_types_description')"
          :step="6"
          :is-completed="hasValidAssetTypes"
        >

              {{ assetType.name }}

            <combobox
              class="flexrow-item"
              :options="availableAssetTypes"
              :with-margin="false"
              @input="id => {
                assetTypeMap.get(id) && productionToCreate.assetTypes.push(
                  assetTypeMap.get(id)
                )
              }"
              v-if="availableAssetTypes.length > 1"
            />

        </timeline-item>
        <timeline-item
          :title="$t('productions.creation.add_assets')"
          :subtitle="$t('productions.creation.add_assets_description')"
          :step="7"
          :is-completed="hasValidAssets"
          :optional="true"
        >

             0">
              {{ nbAssetsToImport }}
              {{ $t('productions.creation.assets_to_import') }}

            <button
              class="button import-button"
              @click="toggleModal('isAssetsImportDisplayed')"
            >
              {{ $t('productions.creation.import_assets_button') }}
            </button>

        </timeline-item>
        <timeline-item
          :title="$t('productions.creation.add_shots')"
          :subtitle="$t('productions.creation.add_shots_description')"
          :step="8"
          :is-completed="hasValidShots"
          :optional="true"
          is-last
        >

             0">
              {{ nbShotsToImport }}
              {{ $t('productions.creation.shots_to_import') }}

            <button
              class="button import-button"
              @click="toggleModal('isShotsImportDisplayed')"
            >
              {{ $t('productions.creation.import_shots_button') }}
            </button>

        </timeline-item>

            {{ $t('productions.creation.errorImportingAssets') }}

            {{ errors.importingAssetsError }}

            {{ $t('productions.creation.errorImportingShots') }}

            {{ errors.importingShotsError }}

            {{ $t('productions.creation.error') }}
            {{ errors.creatingProductionError }}

          <button
            class="button big-button"
            v-if="hasAllDataCorrect"
            @click="createProduction"
          >
            <spinner
              class="mr05 mt05"
              :size="20"
              is-white
              v-if="loading.createProduction"
            />
            {{ $t('productions.creation.create_button') }}
          </button>
          <button class="button big-button" v-else>
            {{ $t('productions.creation.create_button_disabled') }}
          </button>

    <import-render-modal
      :active="modals.isAssetsImportRenderDisplayed"
      :is-loading="loading.importingAssets"
      :is-error="errors.importingAssets"
      :import-error="errors.importingAssetsError"
      :parsed-csv="parsedAssetsCSV"
      :form-data="assetsCsvFormData"
      :columns="assetsColumns"
      :data-matchers="assetsDataMatchers"
      :database="{}"
      :disable-update="true"
      @reupload="resetAssetsImport"
      @confirm="uploadAssetsImportFile"
      @cancel="toggleModal('isAssetsImportRenderDisplayed')"
    />

    <import-modal
      ref="import-assets-modal"
      :active="modals.isAssetsImportDisplayed"
      :is-loading="loading.importingAssets"
      :is-error="errors.importingAssets"
      :form-data="assetsCsvFormData"
      :columns="assetsColumns"
      @confirm="renderAssetsImport"
      @cancel="toggleModal('isAssetsImportDisplayed')"
    />

    <import-render-modal
      :active="modals.isShotsImportRenderDisplayed"
      :is-loading="loading.importingShots"
      :is-error="errors.importingShots"
      :import-error="errors.importingShotsError"
      :parsed-csv="parsedShotsCSV"
      :form-data="shotsCsvFormData"
      :columns="shotsColumns"
      :data-matchers="shotsDataMatchers"
      :database="{}"
      :disable-update="true"
      @reupload="resetShotsImport"
      @confirm="uploadShotsImportFile"
      @cancel="toggleModal('isShotsImportRenderDisplayed')"
    />

    <import-modal
      ref="import-shots-modal"
      :active="modals.isShotsImportDisplayed"
      :is-loading="loading.importingShots"
      :is-error="errors.importingShots"
      :form-data="shotsCsvFormData"
      :columns="shotsColumns"
      @confirm="renderShotsImport"
      @cancel="toggleModal('isShotsImportDisplayed')"
    />

    <manage-shots-modal
      :active="modals.isAddShotsDisplayed"
      @add-episode="addEpisode"
      @add-sequence="addSequence"
      @add-shot="addShot"
      @cancel="toggleModal('isAddShotsDisplayed')"
    />

</template>

<template>

              {{ $t('productions.creation.new_project') }}

              {{ $t('productions.creation.create_production') }}

        <timeline-item
          :title="$t('productions.creation.give_a_name')"
          :subtitle="$t('productions.creation.give_a_name_description')"
          :step="1"
          :is-completed="hasValidName"
        >
          <text-field
            input-class="w600 is-inline"
            :placeholder="$t('productions.creation.placeholder_name')"
            v-model="productionToCreate.name"
          />
        </timeline-item>
        <timeline-item
          :title="$t('productions.creation.production_settings')"
          :subtitle="$t('productions.creation.production_settings_description')"
          :step="2"
          :is-completed="hasValidSettings"
        >

            <combobox
              :options="productionTypeOptions"
              :label="$t('productions.fields.type')"
              localeKeyPrefix="productions.type."
              v-model="productionToCreate.settings.type"
              thin
              is-inline
            />

            {{ $t('productions.creation.explaination_type') }}

            <text-field
              class="flexrow-item"
              input-class=" is-small is-size-3"
              :label="$t('productions.fields.fps')"
              type="number"
              :step="1"
              :placeholder="$t('productions.creation.placeholder_fps')"
              v-model="productionToCreate.settings.fps"
              thin
            />

            <text-field
              class="flexrow-item mr0"
              input-class=" is-small is-size-2"
              :label="$t('productions.fields.ratio')"
              type="number"
              :step="1"
              :placeholder="$t('productions.creation.placeholder_ratio1')"
              v-model="productionToCreate.settings.ratio[0]"
              thin
            />
            :
            <text-field
              class="flexrow-item"
              input-class=" is-small is-size-2"
              type="number"
              :step="1"
              :placeholder="$t('productions.creation.placeholder_ratio2')"
              :empty-label="true"
              v-model="productionToCreate.settings.ratio[1]"
              thin
            />

            <text-field
              class="flexrow-item mr0 ml2"
              input-class=" is-small is-size-4"
              :label="$t('productions.fields.resolution')"
              type="number"
              :step="1"
              :placeholder="$t('productions.creation.placeholder_resolution1')"
              v-model="productionToCreate.settings.resolution[0]"
              thin
            />
            x
            <text-field
              class="flexrow-item"
              input-class=" is-small is-size-4"
              type="number"
              :placeholder="$t('productions.creation.placeholder_resolution2')"
              :step="1"
              :empty-label="true"
              v-model="productionToCreate.settings.resolution[1]"
              thin
            />

            {{ $t('productions.creation.explaination_video') }}

              {{
                $t('productions.creation.start_and_end_dates')
              }}

            <datepicker
              wrapper-class="datepicker"
              input-class=" is-small date-input input"
              label="Start date"
              :placeholder="startDatePlaceholder"
              :language="locale"
              :disabled-dates="{ days: [6, 0] }"
              :monday-first="true"
              format="yyyy-MM-dd"
              v-model="productionToCreate.settings.dateStart"
            />
            -
            <datepicker
              wrapper-class="datepicker"
              input-class="is-small date-input input"
              :language="locale"
              :disabled-dates="{ days: [6, 0] }"
              :placeholder="endDatePlaceholder"
              :monday-first="true"
              :disabledDates="{ to: productionToCreate.settings.dateStart }"
              format="yyyy-MM-dd"
              v-model="productionToCreate.settings.dateEnd"
            />

            {{ $t('productions.creation.explaination_date') }}

        </timeline-item>
        <timeline-item
          :title="$t('productions.creation.select_asset_task_type')"
          :subtitle="$t(
            'productions.creation.select_asset_task_type_description'
           )"
          :step="3"
          :is-completed="hasValidAssetTaskTypes"
        >
          <draggable
            v-model="productionToCreate.assetTaskTypes"
            draggable=".task-type"
          >
            <task-type-name
              class="task-type"
              :task-type="taskType"
              :key="taskType.id"
              deletable
              @delete="deleteFromList(taskType, 'assetTaskTypes')"
              v-for="taskType in productionToCreate.assetTaskTypes"
            />
            <combobox-task-type
              slot="footer"
              class="is-inline"
              :task-type-list="availableAssetTaskTypes"
              add-placeholder
              @input="id => productionToCreate.assetTaskTypes.push(
                taskTypeMap.get(id)
              )"
              v-if="availableAssetTaskTypes.length > 0"
            />
          </draggable>
        </timeline-item>
        <timeline-item
          :title="$t('productions.creation.select_shot_task_type')"
          :subtitle="$t(
            'productions.creation.select_shot_task_type_description'
          )"
          :step="4"
          :is-completed="hasValidShotTaskTypes"
        >
          <draggable
            v-model="productionToCreate.shotTaskTypes"
            draggable=".task-type"
          >
            <task-type-name
              class="task-type"
              :task-type="taskType"
              :key="taskType.id"
              @delete="deleteFromList(taskType, 'shotTaskTypes')"
              deletable
              v-for="taskType in productionToCreate.shotTaskTypes"
            />
            <combobox-task-type
              slot="footer"
              class="is-inline"
              :task-type-list="availableShotTaskTypes"
              add-placeholder
              @input="id => productionToCreate.shotTaskTypes.push(
                taskTypeMap.get(id)
              )"
              v-if="availableShotTaskTypes.length > 0"
            />
          </draggable>
        </timeline-item>
        <timeline-item
          :title="$t('productions.creation.select_task_status')"
          :subtitle="$t('productions.creation.select_task_status_description')"
          :step="5"
          :is-completed="hasValidTaskStatuses"
        >

            <validation-tag
              class="task-status flexrow-item"
              :task="{ task_status_id: taskStatus.id }"
              :key="taskStatus.id"
              pointer
              is-static
              @click="deleteFromList(taskStatus, 'taskStatuses')"
              v-for="taskStatus in productionToCreate.taskStatuses"
            />
            <combobox-status
              slot="footer"
              class="flexrow-item"
              :task-status-list="availableTaskStatuses"
              :with-margin="false"
              add-placeholder
              @input="id => productionToCreate.taskStatuses.push(
                taskStatusMap.get(id)
              )"
              v-if="availableTaskStatuses.length > 0"
            />

        </timeline-item>
        <timeline-item
          :title="$t('productions.creation.add_asset_types')"
          :subtitle="$t('productions.creation.add_asset_types_description')"
          :step="6"
          :is-completed="hasValidAssetTypes"
        >

              {{ assetType.name }}

            <combobox
              class="flexrow-item"
              :options="availableAssetTypes"
              :with-margin="false"
              @input="id => {
                assetTypeMap.get(id) && productionToCreate.assetTypes.push(
                  assetTypeMap.get(id)
                )
              }"
              v-if="availableAssetTypes.length > 1"
            />

        </timeline-item>
        <timeline-item
          :title="$t('productions.creation.add_assets')"
          :subtitle="$t('productions.creation.add_assets_description')"
          :step="7"
          :is-completed="hasValidAssets"
          :optional="true"
        >

             0">
              {{ nbAssetsToImport }}
              {{ $t('productions.creation.assets_to_import') }}

            <button
              class="button import-button"
              @click="toggleModal('isAssetsImportDisplayed')"
            >
              {{ $t('productions.creation.import_assets_button') }}
            </button>

        </timeline-item>
        <timeline-item
          :title="$t('productions.creation.add_shots')"
          :subtitle="$t('productions.creation.add_shots_description')"
          :step="8"
          :is-completed="hasValidShots"
          :optional="true"
          is-last
        >

             0">
              {{ nbShotsToImport }}
              {{ $t('productions.creation.shots_to_import') }}

            <button
              class="button import-button"
              @click="toggleModal('isShotsImportDisplayed')"
            >
              {{ $t('productions.creation.import_shots_button') }}
            </button>

        </timeline-item>

            {{ $t('productions.creation.errorImportingAssets') }}

            {{ errors.importingAssetsError }}

            {{ $t('productions.creation.errorImportingShots') }}

            {{ errors.importingShotsError }}

            {{ $t('productions.creation.error') }}
            {{ errors.creatingProductionError }}

          <button
            class="button big-button"
            v-if="hasAllDataCorrect"
            @click="createProduction"
          >
            <spinner
              v-if="loading.createProduction"
              :size="20"
              class="mr1"
            />
            {{ $t('productions.creation.create_button') }}
          </button>
          <button class="button big-button" v-else>
            {{ $t('productions.creation.create_button_disabled') }}
          </button>

    <import-render-modal
      :active="modals.isAssetsImportRenderDisplayed"
      :is-loading="loading.importingAssets"
      :is-error="errors.importingAssets"
      :import-error="errors.importingAssetsError"
      :parsed-csv="parsedAssetsCSV"
      :form-data="assetsCsvFormData"
      :columns="assetsColumns"
      :data-matchers="assetsDataMatchers"
      :database="{}"
      :disable-update="true"
      @reupload="resetAssetsImport"
      @confirm="uploadAssetsImportFile"
      @cancel="toggleModal('isAssetsImportRenderDisplayed')"
    />

    <import-modal
      ref="import-assets-modal"
      :active="modals.isAssetsImportDisplayed"
      :is-loading="loading.importingAssets"
      :is-error="errors.importingAssets"
      :form-data="assetsCsvFormData"
      :columns="assetsColumns"
      @confirm="renderAssetsImport"
      @cancel="toggleModal('isAssetsImportDisplayed')"
    />

    <import-render-modal
      :active="modals.isShotsImportRenderDisplayed"
      :is-loading="loading.importingShots"
      :is-error="errors.importingShots"
      :import-error="errors.importingShotsError"
      :parsed-csv="parsedShotsCSV"
      :form-data="shotsCsvFormData"
      :columns="shotsColumns"
      :data-matchers="shotsDataMatchers"
      :database="{}"
      :disable-update="true"
      @reupload="resetShotsImport"
      @confirm="uploadShotsImportFile"
      @cancel="toggleModal('isShotsImportRenderDisplayed')"
    />

    <import-modal
      ref="import-shots-modal"
      :active="modals.isShotsImportDisplayed"
      :is-loading="loading.importingShots"
      :is-error="errors.importingShots"
      :form-data="shotsCsvFormData"
      :columns="shotsColumns"
      @confirm="renderShotsImport"
      @cancel="toggleModal('isShotsImportDisplayed')"
    />

    <manage-shots-modal
      :active="modals.isAddShotsDisplayed"
      @add-episode="addEpisode"
      @add-sequence="addSequence"
      @add-shot="addShot"
      @cancel="toggleModal('isAddShotsDisplayed')"
    />

</template>


chore: 👷 fix text

chore: 👷 fix text

<template>

          Staking - SETH2

0.5

$143.09

      You are currently not staking any ETH. To earn rewards start staking.
      Start staking

        <v-progress-circular
          indeterminate
          color="greenPrimary"
          :width="2"
          :size="20"
          class="mr-1"
        />
        0.05 ETH Pending

        View on EthVM
        <v-icon color="greenPrimary" small class="ml-1">mdi-open-in-new</v-icon>

Redeem to ETH

        Stake more ETH

Redeem to ETH

      <mew-button title="Stake more ETH" />

</template>

<template>

          Staking - SETH2

0.5

$143.09

      You are currently not staking any ETH. To earn rewards start staking.
      Start staking

        <v-progress-circular
          indeterminate
          color="greenPrimary"
          :width="2"
          :size="20"
          class="mr-1"
        />
        0.05 ETH Pending

        View on EthVM
        <v-icon color="greenPrimary" small class="ml-1">mdi-open-in-new</v-icon>

Redeem to ETH

        Stake more ETH

Re=deem to ETH

      <mew-button title="Stake more ETH" />

</template>


Fix linting error

Fix linting error

<template>

    <transition name="side-panel">
      <FocusTrap
        @shouldFocusFirstEl="$emit('shouldFocusFirstEl')"
        @shouldFocusLastEl="focusLastEl"
      >

              <slot name="header">
              </slot>

          <KIconButton
            v-if="fullScreenSidePanelCloseButton"
            icon="close"
            class="close-button"
            :styles="closeButtonStyles"
            :ariaLabel="coreString('closeAction')"
            :tooltip="coreString('closeAction')"
            @click="closePanel"
          />

            <slot></slot>

      </FocusTrap>
    </transition>

    <Backdrop
      :transitions="true"
      class="backdrop"
      @click="closePanel"
    />

</template>


Change updated event handler to mounted in MapCard

<template>

      <input class="checkbox-input" :checked="isSelected" @click.prevent="toggleSelection" type="checkBox">

    <MapQuickActions class="card-actions" :map="map" @mouseover="mouseOverChildElement" @mouseleave="mouseOutChildElement" @open="openQuickActions" @close="closeQuickActions"></MapQuickActions>

          {{ map.name }}

{{ map.description }}

{{ $t(`mapCard.noDescription`) }}

{{ $t(`mapCard.shared.${map.privacy}`) }}

          <span class="icon icon--privacy icon--sharedBy" :style="{ backgroundImage: `url('${map.permission.owner.avatar_url}')` }">

{{ $t(`mapCard.sharedBy`, { owner: map.permission.owner.username })}}

{{ lastUpdated }}

          <ul class="card-tagList" v-if="tagsLength <= maxTags">

              {{ tag }}<span v-if="index < map.tags.length - 1">,

              {{ $t(`mapCard.noTags`) }}

          <FeaturesDropdown v-if="tagsLength > maxTags" :list=map.tags>
            {{tagsLength}} {{$t(`mapCard.tags`)}}
          </FeaturesDropdown>

</template>