keep replace replace replace replace replace replace replace replace keep keep keep keep

// will only work if provided a function

context.data.on.beforeEnter = () => mergeTransitions(beforeEnter, ourBeforeEnter)

context.data.on.leave = mergeTransitions(leave, ourLeave)

import { Vue } from 'vue/types/vue'
import { VNode, VNodeDirective, FunctionalComponentOptions } from 'vue/types'

export function createSimpleFunctional (
  c: string,
  el = 'div',
  name?: string
): FunctionalComponentOptions {
  return {
    name: name || c.replace(/__/g, '-'),

    functional: true,

    render (h, { data, children }): VNode {
      data.staticClass = (`${c} ${data.staticClass || ''}`).trim()

      return h(el, data, children)
    }
  }
}

export function createSimpleTransition (
  name: string,
  origin = 'top center 0',
  mode?: string
): FunctionalComponentOptions {
  return {
    name,

    functional: true,

    props: {
      group: {
        type: Boolean,
        default: false
      },
      mode: {
        type: String,
        default: mode
      },
      origin: {
        type: String,
        default: origin
      }
    },

    render (h, context): VNode {
      const tag = `transition${context.props.group ? '-group' : ''}`
      context.data = context.data || {}
      context.data.props = {
        name,
        mode: context.props.mode
      }
      context.data.on = context.data.on || {}
      if (!Object.isExtensible(context.data.on)) {
        context.data.on = { ...context.data.on }
      }

      context.data.on.beforeEnter = (el: HTMLElement) => {
        el.style.transformOrigin = context.props.origin
        el.style.webkitTransformOrigin = context.props.origin
      }

      if (!context.props.mode) {
        const group = context.props.group

        context.data.on.beforeLeave = (el: HTMLElement) => {
          // When using group, this helps Vue FLIP
          // look correct when transitioning
          // https://vuejs.org/v2/guide/transitions.html#List-Move-Transitions
          if (group) el.style.display = 'none'
          else el.style.position = 'absolute'
        }
      }

      return h(tag, context.data, context.children)
    }
  }
}

export function createJavaScriptTransition (
  name: string,
  functions: Record<string, () => any>,
  mode = 'in-out'
): FunctionalComponentOptions {
  return {
    name,

    functional: true,

    props: {
      mode: {
        type: String,
        default: mode
      }
    },

    render (h, context): VNode {
      const data = {
        props: {
          ...context.props,
          name
        },
        on: functions
      }

      return h('transition', data, context.children)
    }
  }
}

export type BindingConfig = Pick<VNodeDirective, 'arg' | 'modifiers' | 'value'>
export function directiveConfig (binding: BindingConfig, defaults = {}): VNodeDirective {
  return {
    ...defaults,
    ...binding.modifiers,
    value: binding.arg,
    ...(binding.value || {})
  }
}

export function addOnceEventListener (el: EventTarget, event: string, cb: () => void): void {
  var once = () => {
    cb()
    el.removeEventListener(event, once, false)
  }

  el.addEventListener(event, once, false)
}

export function getNestedValue (obj: any, path: (string | number)[], fallback?: any): any {
  const last = path.length - 1

  if (last < 0) return obj === undefined ? fallback : obj

  for (let i = 0; i < last; i++) {
    if (obj == null) {
      return fallback
    }
    obj = obj[path[i]]
  }

  if (obj == null) return fallback

  return obj[path[last]] === undefined ? fallback : obj[path[last]]
}

export function deepEqual (a: any, b: any): boolean {
  if (a === b) return true

  if (a instanceof Date && b instanceof Date) {
    // If the values are Date, they were convert to timestamp with getTime and compare it
    if (a.getTime() !== b.getTime()) return false
  }

  if (a !== Object(a) || b !== Object(b)) {
    // If the values aren't objects, they were already checked for equality
    return false
  }

  const props = Object.keys(a)

  if (props.length !== Object.keys(b).length) {
    // Different number of props, don't bother to check
    return false
  }

  return props.every(p => deepEqual(a[p], b[p]))
}

export function getObjectValueByPath (obj: object, path: string, fallback?: any): any {
  // credit: http://stackoverflow.com/questions/6491463/accessing-nested-javascript-objects-with-string-key#comment55278413_6491621
  if (!path || path.constructor !== String) return fallback
  path = path.replace(/\[(\w+)\]/g, '.$1') // convert indexes to properties
  path = path.replace(/^\./, '') // strip a leading dot
  return getNestedValue(obj, path.split('.'), fallback)
}

export function getPropertyFromItem (
  item: object,
  property: string | (string | number)[] | ((item: object, fallback?: any) => any),
  fallback?: any
): any {
  if (property == null) return item === undefined ? fallback : item

  if (item !== Object(item)) return fallback === undefined ? item : fallback

  if (typeof property === 'string') return getObjectValueByPath(item, property, fallback)

  if (Array.isArray(property)) return getNestedValue(item, property, fallback)

  if (typeof property !== 'function') return fallback

  const value = property(item, fallback)

  return typeof value === 'undefined' ? fallback : value
}

export function createRange (length: number): number[] {
  return Array.from({ length }, (v, k) => k)
}

export function getZIndex (el?: Element | null): number {
  if (!el || el.nodeType !== Node.ELEMENT_NODE) return 0

  const index = +window.getComputedStyle(el).getPropertyValue('z-index')

  if (isNaN(index)) return getZIndex(el.parentNode as Element)
  return index
}

const tagsToReplace = {
  '&': '&',
  '<': '<',
  '>': '>'
} as any

export function escapeHTML (str: string): string {
  return str.replace(/[&<>]/g, tag => tagsToReplace[tag] || tag)
}

export function filterObjectOnKeys<T, K extends keyof T> (obj: T, keys: K[]): { [N in K]: T[N] } {
  const filtered = {} as { [N in K]: T[N] }

  for (let i = 0; i < keys.length; i++) {
    const key = keys[i]
    if (typeof obj[key] !== 'undefined') {
      filtered[key] = obj[key]
    }
  }

  return filtered
}

export function filterChildren (array: VNode[] = [], tag: string): VNode[] {
  return array.filter(child => {
    return child.componentOptions &&
      child.componentOptions.Ctor.options.name === tag
  })
}

export function convertToUnit (str: string | number | null | undefined, unit = 'px'): string | undefined {
  if (str == null || str === '') {
    return undefined
  } else if (isNaN(+str!)) {
    return String(str)
  } else {
    return `${Number(str)}${unit}`
  }
}

export function kebabCase (str: string): string {
  return (str || '').replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase()
}

export function isObject (obj: any): obj is object {
  return obj !== null && typeof obj === 'object'
}

// KeyboardEvent.keyCode aliases
export const keyCodes = Object.freeze({
  enter: 13,
  tab: 9,
  delete: 46,
  esc: 27,
  space: 32,
  up: 38,
  down: 40,
  left: 37,
  right: 39,
  end: 35,
  home: 36,
  del: 46,
  backspace: 8,
  insert: 45,
  pageup: 33,
  pagedown: 34
})

const ICONS_PREFIX = '$vuetify.icons.'

// This remaps internal names like '$vuetify.icons.cancel' to the current name
// for that icon.
export function remapInternalIcon (vm: Vue, iconName: string): string {
  if (!iconName.startsWith(ICONS_PREFIX)) {
    return iconName
  }

  // Now look up icon indirection name, e.g. '$vuetify.icons.cancel'
  return getObjectValueByPath(vm, iconName, iconName)
}

export function keys<O> (o: O) {
  return Object.keys(o) as (keyof O)[]
}

/**
 * Camelize a hyphen-delimited string.
 */
const camelizeRE = /-(\w)/g
export const camelize = (str: string): string => {
  return str.replace(camelizeRE, (_, c) => c ? c.toUpperCase() : '')
}


// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`VRadio.vue should not render aria-label attribute with no label value on input group 1`] = `

    <input aria-checked="false"
           role="radio"
           type="radio"
           name="name"
    >

      radio_button_unchecked

`;

exports[`VRadio.vue should render aria-label attribute with label value on input group 1`] = `

    <input aria-label="Test"
           aria-checked="false"
           role="radio"
           type="radio"
           name="name"
    >

      radio_button_unchecked

    Test

`;

exports[`VRadio.vue should render proper input name 1`] = `

    <input aria-checked="false"
           role="radio"
           type="radio"
           name="name"
    >

      radio_button_unchecked

`;

exports[`VRadio.vue should render role and aria-checked attributes on input group 1`] = `

    <input aria-checked="true"
           role="radio"
           type="radio"
           name="name"
    >

      radio_button_unchecked

`;

exports[`VRadio.vue should render themed component 1`] = `

    <input aria-checked="false"
           role="radio"
           type="radio"
    >

      radio_button_unchecked

`;

exports[`VRadio.vue should use custom icons 1`] = `

    <input aria-checked="false"
           role="radio"
           type="radio"
    >

      bar

`;

exports[`VRadio.vue should use custom icons 2`] = `

    <input aria-checked="true"
           role="radio"
           type="radio"
    >

      bar

`;


// Styles
import '../../stylus/components/_tabs.styl'

// Component level mixins
import TabsComputed from './mixins/tabs-computed'
import TabsGenerators from './mixins/tabs-generators'
import TabsProps from './mixins/tabs-props'
import TabsTouch from './mixins/tabs-touch'
import TabsWatchers from './mixins/tabs-watchers'

// Mixins
import Colorable from '../../mixins/colorable'
import SSRBootable from '../../mixins/ssr-bootable'
import Themeable from '../../mixins/themeable'
import {
  provide as RegistrableProvide
} from '../../mixins/registrable'

// Directives
import Resize from '../../directives/resize'
import Touch from '../../directives/touch'

/* @vue/component */
export default {
  name: 'v-tabs',

  directives: {
    Resize,
    Touch
  },

  mixins: [
    RegistrableProvide('tabs'),
    Colorable,
    SSRBootable,
    TabsComputed,
    TabsProps,
    TabsGenerators,
    TabsTouch,
    TabsWatchers,
    Themeable
  ],

  provide () {
    return {
      tabClick: this.tabClick,
      tabProxy: this.tabProxy,
      registerItems: this.registerItems,
      unregisterItems: this.unregisterItems
    }
  },

  data () {
    return {
      bar: [],
      content: [],
      isBooted: false,
      isOverflowing: false,
      lazyValue: this.value,
      nextIconVisible: false,
      prevIconVisible: false,
      resizeTimeout: null,
      reverse: false,
      scrollOffset: 0,
      sliderWidth: null,
      sliderLeft: null,
      startX: 0,
      tabsContainer: null,
      tabs: [],
      tabItems: null,
      transitionTime: 300,
      widths: {
        bar: 0,
        container: 0,
        wrapper: 0
      }
    }
  },

  watch: {
    tabs: 'onResize'
  },

  mounted () {
    this.checkIcons()
  },

  methods: {
    checkIcons () {
      this.prevIconVisible = this.checkPrevIcon()
      this.nextIconVisible = this.checkNextIcon()
    },
    checkPrevIcon () {
      return this.scrollOffset > 0
    },
    checkNextIcon () {
      // Check one scroll ahead to know the width of right-most item
      return this.widths.container > this.scrollOffset + this.widths.wrapper
    },
    callSlider () {
      if (this.hideSlider || !this.activeTab) return false

      // Give screen time to paint
      const action = (this.activeTab || {}).action
      const activeTab = action === this.activeTab
        ? this.activeTab
        : this.tabs.find(tab => tab.action === action)

      this.$nextTick(() => {
        if (!activeTab || !activeTab.$el) return
        this.sliderWidth = activeTab.$el.scrollWidth
        this.sliderLeft = activeTab.$el.offsetLeft
      })
    },
    /**
     * When v-navigation-drawer changes the
     * width of the container, call resize
     * after the transition is complete
     */
    onResize () {
      if (this._isDestroyed) return

      this.setWidths()

      clearTimeout(this.resizeTimeout)
      this.resizeTimeout = setTimeout(() => {
        this.callSlider()
        this.scrollIntoView()
        this.checkIcons()
      }, this.transitionTime)
    },
    overflowCheck (e, fn) {
      this.isOverflowing && fn(e)
    },
    scrollTo (direction) {
      this.scrollOffset = this.newOffset(direction)
    },
    setOverflow () {
      this.isOverflowing = this.widths.bar < this.widths.container
    },
    setWidths () {
      const bar = this.$refs.bar ? this.$refs.bar.clientWidth : 0
      const container = this.$refs.container ? this.$refs.container.clientWidth : 0
      const wrapper = this.$refs.wrapper ? this.$refs.wrapper.clientWidth : 0

      this.widths = { bar, container, wrapper }

      this.setOverflow()
    },
    findActiveLink () {
      if (!this.tabs.length) return

      const activeIndex = this.tabs.findIndex((tabItem, index) => {
        const id = tabItem.action === tabItem ? index : tabItem.action
        return id === this.lazyValue ||
          tabItem.$el.firstChild.className.indexOf(this.activeClass) > -1
      })

      const index = activeIndex > -1 ? activeIndex : 0
      const tab = this.tabs[index]

      /* istanbul ignore next */
      // There is not a reliable way to test
      this.inputValue = tab.action === tab ? index : tab.action
    },
    parseNodes () {
      const item = []
      const items = []
      const slider = []
      const tab = []
      const length = (this.$slots.default || []).length

      for (let i = 0; i < length; i++) {
        const vnode = this.$slots.default[i]

        if (vnode.componentOptions) {
          switch (vnode.componentOptions.Ctor.options.name) {
            case 'v-tabs-slider': slider.push(vnode)
              break
            case 'v-tabs-items': items.push(vnode)
              break
            case 'v-tab-item': item.push(vnode)
              break
            // case 'v-tab' - intentionally omitted
            default: tab.push(vnode)
          }
        } else {
          tab.push(vnode)
        }
      }

      return { tab, slider, items, item }
    },
    register (options) {
      this.tabs.push(options)
    },
    scrollIntoView () {
      if (!this.activeTab) return
      if (!this.isOverflowing) return (this.scrollOffset = 0)

      const totalWidth = this.widths.wrapper + this.scrollOffset
      const { clientWidth, offsetLeft } = this.activeTab.$el
      const itemOffset = clientWidth + offsetLeft
      let additionalOffset = clientWidth * 0.3
      if (this.activeIndex === this.tabs.length - 1) {
        additionalOffset = 0 // don't add an offset if selecting the last tab
      }

      /* istanbul ignore else */
      if (offsetLeft < this.scrollOffset) {
        this.scrollOffset = Math.max(offsetLeft - additionalOffset, 0)
      } else if (totalWidth < itemOffset) {
        this.scrollOffset -= totalWidth - itemOffset - additionalOffset
      }
    },
    tabClick (tab) {
      this.inputValue = tab.action === tab ? this.tabs.indexOf(tab) : tab.action
      this.scrollIntoView()
    },
    tabProxy (val) {
      this.inputValue = val
    },
    registerItems (fn) {
      this.tabItems = fn
    },
    unregisterItems () {
      this.tabItems = null
    },
    unregister (tab) {
      this.tabs = this.tabs.filter(o => o !== tab)
    },
    updateTabs () {
      for (let index = this.tabs.length; --index >= 0;) {
        this.tabs[index].toggle(this.target)
      }

      this.setOverflow()
    }
  },

  render (h) {
    const { tab, slider, items, item } = this.parseNodes()

    return h('div', {
      staticClass: 'v-tabs',
      directives: [{
        name: 'resize',
        arg: 400,
        modifiers: { quiet: true },
        value: this.onResize
      }]
    }, [
      this.genBar([this.hideSlider ? null : this.genSlider(slider), tab]),
      this.genItems(items, item)
    ])
  }
}


import VExpansionPanel from './VExpansionPanel'
import VExpansionPanelContent from './VExpansionPanelContent'

export { VExpansionPanel, VExpansionPanelContent }

export default {
  $_vuetify_subcomponents: {
    VExpansionPanel,
    VExpansionPanelContent
  }
}


// TODO: This breaks with shorthand property names (d40508db)

keep keep keep keep replace replace keep keep keep

<template>
  <v-container grid-list-md>
    <v-layout row wrap>
      <v-flex xs12 lg6>
        <v-menu
          ref="menu1"
          lazy
          :close-on-content-click="false"
          v-model="menu1"
          transition="scale-transition"
          offset-y
          full-width
          :nudge-right="40"
          max-width="290px"
          min-width="290px"
        >
          <v-text-field
            slot="activator"
            label="Date"
            hint="MM/DD/YYYY format"
            persistent-hint
            v-model="dateFormatted"
            prepend-icon="event"
            @blur="date = parseDate(dateFormatted)"
          ></v-text-field>
          <v-date-picker v-model="date" no-title @input="menu1 = false"></v-date-picker>
        </v-menu>

Date in ISO format: {{ date }}

      </v-flex>

      <v-flex xs12 lg6>
        <v-menu
          lazy
          :close-on-content-click="false"
          v-model="menu2"
          transition="scale-transition"
          offset-y
          full-width
          :nudge-right="40"
          max-width="290px"
          min-width="290px"
        >
          <v-text-field
            slot="activator"
            label="Date (read only text field)"
            hint="MM/DD/YYYY format"
            persistent-hint
            v-model="computedDateFormatted"
            prepend-icon="event"
            readonly
          ></v-text-field>
          <v-date-picker v-model="date" no-title @input="menu2 = false"></v-date-picker>
        </v-menu>

Date in ISO format: {{ date }}

      </v-flex>
    </v-layout>
  </v-container>
</template>


<template>
  <v-card>
    <v-card-title>
      Nutrition
      <v-spacer></v-spacer>
      <v-text-field
        append-icon="search"
        label="Search"
        single-line
        hide-details
        v-model="search"
      ></v-text-field>
    </v-card-title>
    <v-data-table
        v-bind:headers="headers"
        v-bind:items="items"
        v-bind:search="search"
      >
      <template slot="items" slot-scope="props">

          <v-edit-dialog
            lazy
          > {{ props.item.name }}
            <v-text-field
              slot="input"
              label="Edit"
              v-model="props.item.name"
              single-line
              counter
              :rules="[max25chars]"
            ></v-text-field>
          </v-edit-dialog>

        {{ props.item.calories }}
        {{ props.item.fat }}
        {{ props.item.carbs }}
        {{ props.item.protein }}
        {{ props.item.sodium }}
        {{ props.item.calcium }}

          <v-edit-dialog
            @open="tmp = props.item.iron"
            @save="props.item.iron = tmp || props.item.iron"
            large
            lazy
          >

{{ props.item.iron }}

Update Iron

            <v-text-field
              slot="input"
              label="Edit"
              v-model="tmp"
              single-line
              counter
              autofocus
              :rules="[max25chars]"
            ></v-text-field>
          </v-edit-dialog>

      </template>
      <template slot="pageText" slot-scope="{ pageStart, pageStop }">
        From {{ pageStart }} to {{ pageStop }}
      </template>
    </v-data-table>
  </v-card>
</template>


export default {
  props: {
    attach: 'Specifies which DOM element that this component should detach to. Use either a CSS selector string or an object reference to the element.',
    contentClass: 'Applies a custom class to the detached element. This is useful because the content is moved to the end of the app and is not targettable by classes passed directly on the component.'
  }
}


<template>
  <v-data-table
      v-bind:headers="headers"
      :items="items"
      class="elevation-1"
    >
    <template slot="headerCell" scope="props">

        {{ props.header.text }}

    </template>
    <template slot="items" scope="props">
      {{ props.item.name }}
      {{ props.item.calories }}
      {{ props.item.fat }}
      {{ props.item.carbs }}
      {{ props.item.protein }}
      {{ props.item.sodium }}
      {{ props.item.calcium }}
      {{ props.item.iron }}
    </template>
  </v-data-table>
</template>


"baseIndent": 1,
"switchCase": 1,
"ignores": []
}] */
}
},
{
files: 'examples/**/*.vue',
rules: {

keep keep keep replace keep keep keep keep keep


// Components
import VPicker from '../components/VPicker'

// Mixins
import Colorable from './colorable'
import Themeable from './themeable'

/* @vue/component */
export default {
  name: 'picker',

  mixins: [
    Colorable,
    Themeable
  ],

  props: {
    fullWidth: Boolean,
    headerColor: String,
    landscape: Boolean,
    noTitle: Boolean,
    width: {
      type: [Number, String],
      default: 290
    }
  },

  methods: {
    genPickerTitle () {},
    genPickerBody () {},
    genPickerActionsSlot () {
      return this.$scopedSlots.default ? this.$scopedSlots.default({
        save: this.save,
        cancel: this.cancel
      }) : this.$slots.default
    },
    genPicker (staticClass) {
      return this.$createElement(VPicker, {
        staticClass,
        props: {
          color: this.headerColor || this.color,
          dark: this.dark,
          fullWidth: this.fullWidth,
          landscape: this.landscape,
          light: this.light,
          width: this.width
        }
      }, [
        this.noTitle ? null : this.genPickerTitle(),
        this.genPickerBody(),
        this.$createElement('template', { slot: 'actions' }, [this.genPickerActionsSlot()])
      ])
    }
  }
}


<template>
  <v-container fluid grid-list-md>
    <v-layout row wrap>
      <v-flex d-flex xs12 sm6 md4>
        <v-card color="purple" dark>
          <v-card-title primary class="title">Lorem</v-card-title>
          <v-card-text>{{ lorem }}</v-card-text>
        </v-card>
      </v-flex>
      <v-flex d-flex xs12 sm6 md3>
        <v-layout row wrap>
          <v-flex d-flex>
            <v-card color="indigo" dark>
              <v-card-text>{{ lorem.slice(0, 70) }}</v-card-text>
            </v-card>
          </v-flex>
          <v-flex d-flex>
            <v-layout row wrap>
              <v-flex
                v-for="n in 2"
                :key="n"
                d-flex
                xs12
              >
                <v-card
                  color="red lighten-2"
                  dark
                >
                  <v-card-text>{{ lorem.slice(0, 40) }}</v-card-text>
                </v-card>
              </v-flex>
            </v-layout>
          </v-flex>
        </v-layout>
      </v-flex>
      <v-flex d-flex xs12 sm6 md2 child-flex>
        <v-card color="green lighten-2" dark>
          <v-card-text>{{ lorem.slice(0, 90) }}</v-card-text>
        </v-card>
      </v-flex>
      <v-flex d-flex xs12 sm6 md3>
        <v-card color="blue lighten-2" dark>
          <v-card-text>{{ lorem.slice(0, 100) }}</v-card-text>
        </v-card>
      </v-flex>
    </v-layout>
  </v-container>
</template>

<script>
  export default {
    data: () => ({
      lorem: `Lorem ipsum dolor sit amet, mel at clita quando. Te sit oratio vituperatoribus, nam ad ipsum posidonium mediocritatem, explicari dissentiunt cu mea. Repudiare disputationi vim in, mollis iriure nec cu, alienum argumentum ius ad. Pri eu justo aeque torquatos.`
    })
  }
</script>


export default {
  header: '扩展面板',
  headerText: '`v-expansion-panel`组件对于减少大量信息的垂直空间非常有用。该组件的默认功能是一次仅显示一个展开面板主题。但是使用`expandable`属性后，扩展面板会保持打开状态，直到被显式关闭。',
  components: ['v-expansion-panel', 'v-expansion-panel-content'],
  examples: [{
    accordion: {
      header: '手风琴',
      desc: '手风琴面板一次只能打开一个面板。'
    },
    expand: {
      header: '扩展',
      desc: '扩展面板将保持打开知道被关闭。',
      uninverted: true
    },
    popout: {
      header: '弹出与嵌入',
      desc: '扩展面板还有两种可以用属性`popout`和`inset`激活的替代设计',
      inverted: true
    },
    customIcons: {
      header: 'Custom icon',
      desc: 'Expand action icon can be customized with `expand-icon` prop.'
    },
    focusable: {
      header: '调焦',
      desc: '扩展面板头部可以通过`focusable`属性进行调焦。',
      uninverted: true
    }
  }],
  props: {
    'v-expansion-panel': {
      expand: '选择另一个时，将扩展面板打开',
      focusable: '使扩展面板标题可以调焦',
      inset: '使扩展面板以嵌入的样式打开',
      popout: '使扩展面板以弹出的样式打开'
    },
    'v-expansion-panel-content': {
      hideActions: '隐藏内容标题中的展开图标',
      expandIcon: 'Set the expand action icon'
    }
  }
}


module.exports = {
  root: true,
  parserOptions: {
    parser: 'babel-eslint',
    ecmaVersion: 2017,
    sourceType: 'module'
  },
  env: {
    node: true,
    browser: true
  },
  extends: [
    'plugin:vue/recommended',
    'standard'
  ],
  globals: {
    docsearch: true
  },
  rules: {
    "vue/max-attributes-per-line": [2, {
      "singleline": 5,
      "multiline": {
        "max": 1,
        "allowFirstLine": false
      }
    }],
    "prefer-promise-reject-errors": 0
  },
  overrides: [
    {
      files: '**/*.vue',
      rules: {
        indent: false,
        // TODO: This breaks with shorthand property names (d40508db)
        /* "vue/script-indent": ["error", 2, {
          "baseIndent": 1,
          "switchCase": 1,
          "ignores": []
        }] */
      }
    },
    {
      files: 'examples/**/*.vue',
      rules: {
        "vue/valid-v-on": false,
        "vue/no-parsing-error": false, // This rule doesn't allow empty event listeners
        "vue/html-self-closing": ["error", {
          "html": {
            "void": "never",
            "normal": "never",
            "component": "never"
          },
          "svg": "always",
          "math": "always"
        }]
      }
    },
    {
      files: 'examples/layouts/**/*.vue',
      rules: {
        "vue/order-in-components": false,
        "vue/require-default-prop": false
      }
    }
  ]
}


import { test } from '@/test'
import VTimelineItem from '@/components/VTimeline/VTimelineItem'

test('VTimelineItem.js', ({ mount }) => {
  it('should conditionally render dot', () => {
    const wrapper = mount(VTimelineItem, {
      propsData: {
        hideDot: true
      }
    })

    expect(wrapper.html()).toMatchSnapshot()

    wrapper.setProps({ hideDot: false })

    expect(wrapper.html()).toMatchSnapshot()
  })

  it('should conditionally render an icon or icon slot', () => {
    expect(mount(VTimelineItem, {
      slots: {
        icon: [{
          render: h => h('div', 'foo')
        }]
      }
    }).html()).toMatchSnapshot()

    expect(mount(VTimelineItem, {
      propsData: { icon: 'foo' }
    }).html()).toMatchSnapshot()
  })

  it('should render opposite slot', () => {
    expect(mount(VTimelineItem, {
      slots: {
        opposite: [{
          render: h => h('div', 'foo')
        }]
      }
    }).html())
  })
})


<template>
  <v-tabs :scrollable="false">
    <v-tabs-bar dark color="cyan">
      <v-tabs-slider color="yellow"></v-tabs-slider>
      <v-tabs-item
        v-for="i in 5"
        :key="i"
        :href="'#tab-' + i"
      >
        Item {{ i }}
      </v-tabs-item>
      <v-menu>
        <v-tabs-item slot="activator">
          Menu
          <v-icon>arrow_drop_down</v-icon>
        </v-tabs-item>
        <v-list v-for="n in 4" v-bind:key="n">
          <v-list-tile @click="">Item {{ n }}</v-list-tile>
        </v-list>
      </v-menu>
    </v-tabs-bar>
    <v-tabs-items>
      <v-tabs-content
        v-for="i in 5"
        :key="i"
        :id="'tab-' + i"
      >
        <v-card flat>
          <v-card-text>{{ text }}</v-card-text>
        </v-card>
      </v-tabs-content>
    </v-tabs-items>
  </v-tabs>
</template>

<script>
  export default {
    data () {
      return {
        text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.'
      }
    }
  }
</script>


<template>
  <v-layout row wrap>
    <v-flex md12 lg4>
      <v-date-picker v-model="picker"></v-date-picker>
    </v-flex>
    <v-flex md12 lg8 class="hidden-xs-only">
      <v-date-picker v-model="picker2" landscape></v-date-picker>
    </v-flex>
  </v-layout>
</template>

<script>
  export default {
    data () {
      return {
        picker: null,
        picker2: null
      }
    }
  }
</script>


<template>
  <div class="text-xs-center">
    <v-pagination :length="4" v-model="page" circle></v-pagination>
  </div>
</template>

<script>
  export default {
    data () {
      return {
        page: 1
      }
    }
  }
</script>


import VSpeedDial from '@/components/VSpeedDial'
import { test } from '@/test'
import { compileToFunctions } from 'vue-template-compiler'

test('VSpeedDial.js', ({ mount }) => {
  it('should render component and match snapshot', () => {
    const wrapper = mount(VSpeedDial)

    expect(wrapper.html()).toMatchSnapshot()
  })

  it('should render active component and match snapshot', () => {
    const wrapper = mount(VSpeedDial, {
      slots: {
        default: [compileToFunctions('test')]
      },
      data: {
        isActive: true
      }
    })

    expect(wrapper.html()).toMatchSnapshot()
  })

  it('should render component with custom direction and match snapshot', () => {
    const wrapper = mount(VSpeedDial, {
      propsData: {
        direction: 'right'
      }
    })

    expect(wrapper.html()).toMatchSnapshot()
  })

  it('should activate on click', () => {
    const wrapper = mount(VSpeedDial)

    expect(wrapper.vm.isActive).toBe(false)
    wrapper.trigger('click')
    expect(wrapper.vm.isActive).toBe(true)
  })

  it('should activate on hover', () => {
    const wrapper = mount(VSpeedDial, {
      propsData: {
        openOnHover: true
      }
    })

    expect(wrapper.vm.isActive).toBe(false)
    wrapper.trigger('mouseenter')
    expect(wrapper.vm.isActive).toBe(true)
    wrapper.trigger('mouseleave')
    expect(wrapper.vm.isActive).toBe(false)
  })
})


<template>
  <v-expansion-panel>
    <v-expansion-panel-content v-for="(item,i) in 5" :key="i">

Item

      <v-card>
        <v-card-text class="grey lighten-3">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</v-card-text>
      </v-card>
    </v-expansion-panel-content>
  </v-expansion-panel>
</template>


<template lang="pug">
  doc-view(id="colors-view")
    v-layout(row wrap)
      v-flex(xs12 sm8 md12)
        section-def
          dt(slot="title") {{ doc.title }}
          dd(slot="desc") {{ doc.desc }}
      ad
    section.mb-5
      section-header Classes
      section-text You can change a background or text color by adding a class to the element. For background, use just the name, for example, <div class="red">. To use a shade, just add the modifying type, such as, darken-3. Text is very similar, adding a modification class, red--text, you can change the color of text, or change the type with adding text--lighten-2. For some elements like the v-badge, you can use the --after type for the background, <span class="green--after" v-badge:5>.
      div.colors
        v-container(fluid).pa-0
          v-layout(row wrap)
            v-flex(xs6 sm6 md4 lg3 v-for="color in colors" v-bind:key="color")
              v-card(v-bind:class="[color]" height="100px")
                v-card-text
                  h3 {{ color }}
              v-card(
                v-for="n in [4,3,2,1]"
                v-bind:class="[color, 'lighten-' + n]"
                class="black--text"
                v-bind:key="n"
              )
                v-card-text {{ color }} lighten-{{ n }}
              v-card(
                v-for="n in 4"
                v-bind:class="[color, 'darken-' + n]"
                v-bind:key="n"
              )
                v-card-text {{ color }} darken-{{ n }}
              v-card(
                v-for="n in 4"
                v-bind:class="[color, 'accent-' + n]"
                v-if="['grey', 'blue-grey', 'brown'].indexOf(color) === -1"
                class="black--text"
                v-bind:key="n"
              )
                v-card-text {{ color }} accent-{{ n }}

    v-divider.my-5

    section#color-pack
      section-header Color Pack
      section-text Vuetify comes pre-built with a Material Design Color Pack (thanks Materialize.css) by default. While convenient, this also increases the css export size by ~30kb. This can be disabled in both the webpack and webpack-ssr Vue cli templates.
      div(class="title pt-3 pb-3") Webpack
      section-text Navigate to src/App.vue. Scroll to the style element and set $color-pack = false above the Vuetify css import.

      div(class="title pt-3 pb-3") Webpack-SSR
      section-text Navigate to src/stylus/main.styl. At the top of the file, declare $color-pack = false.
</template>


<template>
  <v-container grid-list-xl>
    <v-layout v-bind="binding">
      <v-flex>
        <v-card dark color="primary">
          <v-card-text>one</v-card-text>
        </v-card>
      </v-flex>
      <v-flex>
        <v-card dark color="secondary">
          <v-card-text>two</v-card-text>
        </v-card>
      </v-flex>
      <v-flex>
        <v-card dark color="accent">
          <v-card-text>three</v-card-text>
        </v-card>
      </v-flex>
    </v-layout>
  </v-container>
</template>

<script>
  export default {
    computed: {
      binding () {
        const binding = {}

        if (this.$vuetify.breakpoint.mdAndUp) binding.column = true

        return binding
      }
    }
  }
</script>


>
<v-text-field
slot="activator"
label="Date"
hint="MM/DD/YYYY format"
persistent-hint


.blockquote
  padding: $spacers.three.y 0 $spacers.three.y $spacers.four.x
  font-size: 18px
  font-weight: 300


import { test } from '@/test'
import VDatePicker from '@/components/VDatePicker/VDatePicker'

test('VDatePicker.js', ({ mount, compileToFunctions }) => {
  it('should emit input event on year click (reactive picker)', async () => {
    const wrapper = mount(VDatePicker, {
      propsData: {
        value: '2013-05',
        type: 'month',
        reactive: true
      },
      data: {
        activePicker: 'YEAR'
      }
    })

    const input = jest.fn()
    wrapper.vm.$on('input', input);

    const change = jest.fn()
    wrapper.vm.$on('change', input);

    wrapper.find('.v-date-picker-years li.active + li')[0].trigger('click')
    expect(input).toBeCalledWith('2012-05')
    expect(change).not.toBeCalled()
  })

  it('should not emit input event on year click if month is not allowed', async () => {
    const cb = jest.fn()
    const wrapper = mount(VDatePicker, {
      propsData: {
        value: '2013-05',
        type: 'month',
        allowedDates: () => false
      },
      data: {
        activePicker: 'YEAR'
      }
    })

    wrapper.vm.$on('input', cb);
    wrapper.find('.v-date-picker-years li.active + li')[0].trigger('click')
    expect(cb).not.toBeCalled()
  })

  it('should emit input event on month click', async () => {
    const cb = jest.fn()
    const wrapper = mount(VDatePicker, {
      propsData: {
        value: '2013-05',
        type: 'month'
      }
    })

    wrapper.vm.$on('input', cb);
    wrapper.find('.v-date-picker-table--month button')[0].trigger('click')
    expect(cb).toBeCalledWith('2013-01')
  })

  it('should be scrollable', async () => {
    const wrapper = mount(VDatePicker, {
      propsData: {
        value: '2013-05',
        type: 'month',
        scrollable: true
      }
    })

    wrapper.find('.v-date-picker-table--month')[0].trigger('wheel')
    await wrapper.vm.$nextTick()
    expect(wrapper.vm.tableDate).toBe('2014')
  })

  it('should match snapshot with pick-month prop', () => {
    const wrapper = mount(VDatePicker, {
      propsData: {
        value: '2013-05-07',
        type: 'month'
      }
    })

    expect(wrapper.html()).toMatchSnapshot()
  })

  it('should match snapshot with allowed dates as array', () => {
    const wrapper = mount(VDatePicker, {
      propsData: {
        value: '2013-05',
        type: 'month',
        allowedDates: value => ['2013-01', '2013-03', '2013-05', '2013-07'].includes(value)
      }
    })

    expect(wrapper.find('.v-date-picker-table--month tbody')[0].html()).toMatchSnapshot()
  })

  it('should match snapshot with month formatting functions', () => {
    const wrapper = mount(VDatePicker, {
      propsData: {
        value: '2005-11-01',
        type: 'month',
        monthFormat: date => `(${date.split('-')[1]})`
      }
    })

    expect(wrapper.find('.v-date-picker-table--month tbody')[0].html()).toMatchSnapshot()
  })

  it('should match snapshot with colored picker', () => {
    const wrapper = mount(VDatePicker, {
      propsData: {
        type: 'month',
        value: '2005-11-01',
        color: 'primary',
        headerColor: 'orange darken-1'
      }
    })

    expect(wrapper.html()).toMatchSnapshot()
  })

  it('should match snapshot with colored picker', () => {
    const wrapper = mount(VDatePicker, {
      propsData: {
        type: 'month',
        value: '2005-11-01',
        color: 'orange darken-1'
      }
    })

    expect(wrapper.html()).toMatchSnapshot()
  })

  it('should match change month when clicked on header arrow buttons', () => {
    const wrapper = mount(VDatePicker, {
      propsData: {
        value: '2005-11',
        type: 'month'
      }
    })

    const [leftButton, rightButton] = wrapper.find('.v-date-picker-header button')

    leftButton.trigger('click')
    expect(wrapper.vm.tableDate).toBe('2004')

    rightButton.trigger('click')
    expect(wrapper.vm.tableDate).toBe('2006')
  })

  it('should match change active picker when clicked on month button', () => {
    const wrapper = mount(VDatePicker, {
      propsData: {
        value: '2005-11-01',
        type: 'month'
      }
    })

    const button = wrapper.find('.v-date-picker-header strong')[0]

    button.trigger('click')
    expect(wrapper.vm.activePicker).toBe('YEAR')
  })

  it('should select year', async () => {
    const wrapper = mount(VDatePicker, {
      data: {
        activePicker: 'YEAR'
      },
      propsData: {
        type: 'month',
        value: '2005-11'
      }
    })

    wrapper.find('.v-date-picker-years li.active + li')[0].trigger('click')
    expect(wrapper.vm.activePicker).toBe('MONTH')
    expect(wrapper.vm.tableDate).toBe('2004')
  })

  it('should set the table date when value has changed', () => {
    const wrapper = mount(VDatePicker, {
      propsData: {
        value: null,
        type: 'month'
      }
    })

    wrapper.setProps({ value: '2005-11' })
    expect(wrapper.vm.tableDate).toBe('2005')
  })

  it('should use prev and next icons', () => {
    const wrapper = mount(VDatePicker, {
      propsData: {
        type: 'month',
        prevIcon: 'block',
        nextIcon: 'check'
      }
    })

    const icons = wrapper.find('.v-date-picker-header .v-icon')
    expect(icons[0].element.textContent).toBe('block')
    expect(icons[1].element.textContent).toBe('check')
  })
})


<template>
  <v-card>
    <v-card-text>
      <v-layout align-center>
        <v-checkbox v-model="includeFiles" hide-details class="shrink mr-2"></v-checkbox>
        <v-text-field label="Include files"></v-text-field>
      </v-layout>
      <v-layout align-center>
        <v-checkbox v-model="enabled" hide-details class="shrink mr-2"></v-checkbox>
        <v-text-field :disabled="!enabled" label="I only work if you check the box"></v-text-field>
      </v-layout>
    </v-card-text>
  </v-card>
</template>

<script>
  export default {
    data: () => ({
      includeFiles: true,
      enabled: false
    })
  }
</script>


keep keep keep replace keep keep keep keep

<template>
  <v-container grid-list-md>
    <v-layout row wrap>
      <v-flex xs12 lg6>
        <v-menu
          ref="menu1"
          lazy
          :close-on-content-click="false"
          v-model="menu1"
          transition="scale-transition"
          offset-y
          full-width
          :nudge-right="40"
          max-width="290px"
          min-width="290px"
        >
          <v-text-field
            slot="activator"
            label="Date"
            hint="MM/DD/YYYY format"
            persistent-hint
            v-model="dateFormatted"
            prepend-icon="event"
            @blur="date = parseDate(dateFormatted)"
          ></v-text-field>
          <v-date-picker v-model="date" no-title @input="menu1 = false"></v-date-picker>
        </v-menu>

Date in ISO format: {{ date }}

      </v-flex>

      <v-flex xs12 lg6>
        <v-menu
          lazy
          :close-on-content-click="false"
          v-model="menu2"
          transition="scale-transition"
          offset-y
          full-width
          :nudge-right="40"
          max-width="290px"
          min-width="290px"
        >
          <v-text-field
            slot="activator"
            label="Date (read only text field)"
            hint="MM/DD/YYYY format"
            persistent-hint
            v-model="computedDateFormatted"
            prepend-icon="event"
            readonly
          ></v-text-field>
          <v-date-picker v-model="date" no-title @input="menu2 = false"></v-date-picker>
        </v-menu>

Date in ISO format: {{ date }}

      </v-flex>
    </v-layout>
  </v-container>
</template>


<template>
  <div>
    <v-alert color="success" icon="new_releases" :value="true">
      This is a success alert with a custom icon.
    </v-alert>

    <v-alert color="error" :value="true">
      This is an error alert with no icon.
    </v-alert>
  </div>
</template>


<template lang="pug">
  component-view(v-bind:doc="doc")
    v-alert(color="info" icon="info" value="true" slot="top") If you are looking for Grid lists, please navigate <router-link class="white--text" to="/components/grid-lists">here</router-link>.
    grid(slot="top").mt-5
    v-alert(color="info" icon="info" value).mb-4 Vuetify breakpoint functionality requires the use of the v-app component.
    section-header Breakpoint object
    section-text Vuetify converts the available breakpoints into an accessible object from within your application. This will allow you to assign/apply specific properties and attributes based upon viewport size. The object can be accessed from:
    markup(lang="js")
      |export default {
      |    mounted () {
      |      console.log(this.$vuetify.breakpoint)
      |    },
      |    computed: {
      |      imageHeight () {
      |        switch (this.$vuetify.breakpoint.name) {
      |          case 'xs': return '220px'
      |          case 'sm': return '400px'
      |          case 'md': return '500px'
      |          case 'lg': return '600px'
      |          case 'xl': return '800px'
      |        }
      |      }
      |    }
      |}
    section-text This object contains the same semantic properties that you are already used to using from the grid system. Let's try a real world example. You have a v-dialog component that you want to convert to a full-screen dialog on mobile devices. Normally you would need to bind watchers for the viewport size, and/or check whenever the page loads.
    markup(lang="js")
      |export default {
      |    data: () => ({
      |       isMobile: false
      |    }),
      |    mounted () {
      |      this.$vuetify.load(this.init)
      |    },
      |    beforeDestroy () {
      |      if (typeof window !== 'undefined') {
      |         window.removeEventListener('resize', this.onResize, { passive: true })
      |      }
      |    },
      |    methods: {
      |      init () {
      |         this.onResize()
      |         window.addEventListener('resize', this.onResize, { passive: true })
      |      },
      |      onResize () {
      |         this.isMobile = window.innerWidth < 600
      |      }
      |    }
      |}
    section-text That's a lot of boilerplate to write. Even if you opt to use the built in <router-link to="/directives/resizing">v-resize</router-link> directive, you are still going to have to define a resize method. With the breakpoint object you can completely skip this logic and get back to building your application.
    markup(lang="html")
      |<v-dialog :fullscreen="$vuetify.breakpoint.xsOnly">
      |    ...
      |</v-dialog>
</template>


keep keep keep keep keep replace keep keep


<template>
  <v-stepper
    v-model="stepper"
    class="elevation-0"
  >
    <v-stepper-header>
      <template v-for="(step, i) in steps">
        <v-stepper-step
          :editable="i + 1 < stepper"

          :key="i"
          :step="i + 1"
        >
          {{ step.step }}
        </v-stepper-step>
        <v-divider
          v-if="i !== steps.length - 1"
          :key="`divider-${i}`"
        />
      </template>
    </v-stepper-header>
    <v-stepper-items>
      <v-stepper-content
        v-for="(step, i) in steps"
        :key="i"
        :step="i + 1"
      >
        <v-card flat>
          <v-card-title class="justify-center subheading">
            {{ step.question }}
          </v-card-title>
          <v-card-text class="text-xs-center">
            <v-btn
              v-for="(option, j) in step.options"
              :key="j"
              large
              @click="next(step, option)"
            >
              <v-icon
                v-if="option.icon"
                left
                v-text="option.icon"
              />
              {{ option.action }}
            </v-btn>
          </v-card-text>
        </v-card>
      </v-stepper-content>
    </v-stepper-items>
  </v-stepper>
</template>

<script>
  export default {
    props: {
      value: {
        type: String,
        default: ''
      }
    },

    data: vm => ({
      complete: false,
      suggestion: {
        experience: null,
        application: null,
        tests: null,
        seo: null
      },
      stepper: null,
      steps: [
        {
          step: vm.$t('Components.HelpMeChoose.experience'),
          question: vm.$t('Components.HelpMeChoose.question1'),
          target: 'experience',
          options: [
            {
              action: vm.$t('Components.HelpMeChoose.beginner'),
              icon: 'mdi-account',
              value: 'b'
            },
            {
              action: vm.$t('Components.HelpMeChoose.intermediate'),
              icon: 'mdi-account-plus',
              value: 'i'
            },
            {
              action: vm.$t('Components.HelpMeChoose.advanced'),
              icon: 'mdi-account-star',
              value: 'a'
            }
          ]
        },
        {
          step: vm.$t('Components.HelpMeChoose.application'),
          question: vm.$t('Components.HelpMeChoose.question2'),
          target: 'application',
          options: [
            {
              action: vm.$t('Components.HelpMeChoose.web'),
              icon: 'mdi-web',
              value: 'w'
            },
            {
              action: vm.$t('Components.HelpMeChoose.desktop'),
              icon: 'mdi-monitor',
              value: 'd'
            },
            {
              action: vm.$t('Components.HelpMeChoose.mobile'),
              icon: 'mdi-cellphone-android',
              value: 'm'
            }
          ]
        },
        {
          step: vm.$t('Components.HelpMeChoose.tests'),
          question: vm.$t('Components.HelpMeChoose.question3'),
          target: 'tests',
          options: [
            {
              action: vm.$t('Components.HelpMeChoose.yes'),
              value: 'y'
            },
            {
              action: vm.$t('Components.HelpMeChoose.no'),
              value: 'n'
            }
          ]
        },
        {
          step: vm.$t('Components.HelpMeChoose.seo'),
          question: vm.$t('Components.HelpMeChoose.question4'),
          target: 'seo',
          options: [
            {
              action: vm.$t('Components.HelpMeChoose.yes'),
              value: 'y'
            },
            {
              action: vm.$t('Components.HelpMeChoose.no'),
              value: 'n'
            }
          ]
        },
        {
          step: vm.$t('Components.HelpMeChoose.suggestion'),
          question: vm.$t('Components.HelpMeChoose.question5'),
          options: [
            {
              action: vm.$t('Components.HelpMeChoose.reset'),
              value: 'r'
            }
          ]
        }
      ]
    }),

    computed: {
      pattern () {
        return Object.values(this.suggestion).join('')
      }
    },

    watch: {
      pattern (val) {
        this.$emit('input', val)
      }
    },

    methods: {
      next (step, option) {
        if (this.stepper + 1 > this.steps.length) return this.reset()

        if (option.value) {
          this.suggestion[step.target] = option.value
        }

        this.stepper++
      },
      reset () {
        this.stepper = 1
        this.complete = 0

        Object.keys(this.suggestion).forEach(key => {
          this.suggestion[key] = null
        })
      }
    }
  }
</script>


/* @vue/component */
export default {
  name: 'v-list-tile-action',

  functional: true,

  render (h, { data, children = [] }) {
    data.staticClass = data.staticClass ? `v-list__tile__action ${data.staticClass}` : 'v-list__tile__action'
    const filteredChild = children.filter(VNode => {
      return VNode.isComment === false && VNode.text !== ' '
    })
    if (filteredChild.length > 1) data.staticClass += ' v-list__tile__action--stack'

    return h('div', data, children)
  }
}


<template lang="pug">
  component-view(v-bind:doc="doc")
</template>


<template>
  <v-container fluid>
    <v-layout row>
      <v-flex xs4>
        <v-subheader>Normal with hint text/label</v-subheader>
      </v-flex>
      <v-flex xs8>
        <v-text-field
          id="testing"
          name="input-1"
          label="Label Text"
        ></v-text-field>
      </v-flex>
    </v-layout>
    <v-layout row>
      <v-flex xs4>
        <v-subheader>Focus</v-subheader>
      </v-flex>
      <v-flex xs8>
        <v-text-field
          name="input-2"
          label="Label Text"
          value="Input text"
          class="input-group--focused"
        ></v-text-field>
      </v-flex>
    </v-layout>
    <v-layout row>
      <v-flex xs4>
        <v-subheader>Normal with input text + label</v-subheader>
      </v-flex>
      <v-flex xs8>
        <v-text-field
          name="input-3"
          label="Label Text"
          value="Input text"
        ></v-text-field>
      </v-flex>
    </v-layout>
    <v-layout row>
      <v-flex xs4>
        <v-subheader>Disabled</v-subheader>
      </v-flex>
      <v-flex xs8>
        <v-text-field
          name="input-3"
          label="Label Text"
          value="Input text"
          disabled
        ></v-text-field>
      </v-flex>
    </v-layout>
  </v-container>
</template>


<template lang="pug">
  v-container(pt-5)#store-thank-you
    v-layout
      v-flex.text-xs-center
        store-header(
          :header="$t('Vuetify.Store.thankYouHeader')"
          :sub-header="$t('Vuetify.Store.thankYouSubheader')"
        )

        v-btn(
          large
          color="primary"
          :to="{ name: 'store/Index' }"
        ).mb-4.px-5
          span {{ $t('Vuetify.Store.backToStore') }}
          v-icon(right) mdi-arrow-right
        markdown(:source="$t('Vuetify.Store.thankYouBack')").caption
</template>

<script>
  // Components
  import StoreHeader from '@/components/store/StoreHeader'

  export default {
    components: {
      StoreHeader
    },

    mounted () {
      this.$store.dispatch('store/getCheckout')
    }
  }
</script>


<template>
  <div class="text-xs-center">
    <v-btn fab dark small color="primary">
      <v-icon dark>remove</v-icon>
    </v-btn>
    <v-btn fab dark small color="pink">
      <v-icon dark>favorite</v-icon>
    </v-btn>
    <v-btn fab dark color="indigo">
      <v-icon dark>add</v-icon>
    </v-btn>
    <v-btn fab dark color="teal">
      <v-icon dark>list</v-icon>
    </v-btn>
    <v-btn fab dark large color="cyan">
      <v-icon dark>edit</v-icon>
    </v-btn>
    <v-btn fab dark large color="purple">
      <v-icon dark>android</v-icon>
    </v-btn>
  </div>
</template>


import Vue from 'vue'
import * as allComponents from '@/components'
import Vuetify, {
  VApp,
  VAlert,
  VAutocomplete,
  VAvatar,
  VBadge,
  VBottomNav,
  VBottomSheet,
  VBreadcrumbs,
  VBreadcrumbsItem,
  VBreadcrumbsDivider,
  VBtn,
  VBtnToggle,
  VCard,
  VCardMedia,
  VCardTitle,
  VCardActions,
  VCardText,
  VCarousel,
  VCarouselItem,
  VCheckbox,
  VChip,
  VCombobox,
  VCounter,
  VDataIterator,
  VDataTable,
  VEditDialog,
  VTableOverflow,
  VDatePicker,
  VDatePickerTitle,
  VDatePickerHeader,
  VDatePickerDateTable,
  VDatePickerMonthTable,
  VDatePickerYears,
  VDialog,
  VDivider,
  VExpansionPanel,
  VExpansionPanelContent,
  VFooter,
  VForm,
  VContainer,
  VContent,
  VFlex,
  VLayout,
  VSpacer,
  VHover,
  VIcon,
  VImg,
  VInput,
  VItem,
  VItemGroup,
  VJumbotron,
  VLabel,
  VList,
  VListGroup,
  VListTile,
  VListTileAction,
  VListTileAvatar,
  VListTileActionText,
  VListTileContent,
  VListTileTitle,
  VListTileSubTitle,
  VMenu,
  VMessages,
  VNavigationDrawer,
  VOverflowBtn,
  VPagination,
  VPaper,
  VParallax,
  VPicker,
  VProgressCircular,
  VProgressLinear,
  VRadioGroup,
  VRadio,
  VRangeSlider,
  VRating,
  VResponsive,
  VSelect,
  VSlider,
  VSnackbar,
  VSpeedDial,
  VStepper,
  VStepperContent,
  VStepperStep,
  VStepperHeader,
  VStepperItems,
  VSubheader,
  VSwitch,
  VSystemBar,
  VTabs,
  VTab,
  VTabItem,
  VTabsItems,
  VTabsSlider,
  VTextarea,
  VTextField,
  VTimeline,
  VTimelineItem,
  VTimePicker,
  VTimePickerClock,
  VTimePickerTitle,
  VToolbar,
  VToolbarSideIcon,
  VToolbarTitle,
  VToolbarItems,
  VTooltip,
  VTreeview,
  VTreeviewNode,
  VWindow,
  VWindowItem,
  VBottomSheetTransition,
  VCarouselTransition,
  VCarouselReverseTransition,
  VTabTransition,
  VTabReverseTransition,
  VMenuTransition,
  VFabTransition,
  VDialogTransition,
  VDialogBottomTransition,
  VFadeTransition,
  VScaleTransition,
  VScrollXTransition,
  VScrollXReverseTransition,
  VScrollYTransition,
  VScrollYReverseTransition,
  VSlideXTransition,
  VSlideXReverseTransition,
  VSlideYTransition,
  VSlideYReverseTransition,
  VExpandTransition,
  VRowExpandTransition
} from '@/entry-lib'

const components = {
  VApp,
  VAlert,
  VAutocomplete,
  VAvatar,
  VBadge,
  VBottomNav,
  VBottomSheet,
  VBreadcrumbs,
  VBreadcrumbsItem,
  VBreadcrumbsDivider,
  VBtn,
  VBtnToggle,
  VCard,
  VCardMedia,
  VCardTitle,
  VCardActions,
  VCardText,
  VCarousel,
  VCarouselItem,
  VCheckbox,
  VChip,
  VCombobox,
  VCounter,
  VDataIterator,
  VDataTable,
  VEditDialog,
  VTableOverflow,
  VDatePicker,
  VDatePickerTitle,
  VDatePickerHeader,
  VDatePickerDateTable,
  VDatePickerMonthTable,
  VDatePickerYears,
  VDialog,
  VDivider,
  VExpansionPanel,
  VExpansionPanelContent,
  VFooter,
  VForm,
  VContainer,
  VContent,
  VFlex,
  VLayout,
  VSpacer,
  VHover,
  VIcon,
  VImg,
  VInput,
  VItem,
  VItemGroup,
  VJumbotron,
  VLabel,
  VList,
  VListGroup,
  VListTile,
  VListTileAction,
  VListTileAvatar,
  VListTileActionText,
  VListTileContent,
  VListTileTitle,
  VListTileSubTitle,
  VMenu,
  VMessages,
  VNavigationDrawer,
  VOverflowBtn,
  VPagination,
  VPaper,
  VParallax,
  VPicker,
  VProgressCircular,
  VProgressLinear,
  VRadioGroup,
  VRadio,
  VRangeSlider,
  VRating,
  VResponsive,
  VSelect,
  VSlider,
  VSnackbar,
  VSpeedDial,
  VStepper,
  VStepperContent,
  VStepperStep,
  VStepperHeader,
  VStepperItems,
  VSubheader,
  VSwitch,
  VSystemBar,
  VTabs,
  VTab,
  VTabItem,
  VTabsItems,
  VTabsSlider,
  VTextarea,
  VTextField,
  VTimeline,
  VTimelineItem,
  VTimePicker,
  VTimePickerClock,
  VTimePickerTitle,
  VToolbar,
  VToolbarSideIcon,
  VToolbarTitle,
  VToolbarItems,
  VTooltip,
  VTreeview,
  VTreeviewNode,
  VWindow,
  VWindowItem,
  VBottomSheetTransition,
  VCarouselTransition,
  VCarouselReverseTransition,
  VTabTransition,
  VTabReverseTransition,
  VMenuTransition,
  VFabTransition,
  VDialogTransition,
  VDialogBottomTransition,
  VFadeTransition,
  VScaleTransition,
  VScrollXTransition,
  VScrollXReverseTransition,
  VScrollYTransition,
  VScrollYReverseTransition,
  VSlideXTransition,
  VSlideXReverseTransition,
  VSlideYTransition,
  VSlideYReverseTransition,
  VExpandTransition,
  VRowExpandTransition
}

delete allComponents.default // TODO: update ts-jest

describe('a-la-carte import - from /lib', () => {
  Vue.use(Vuetify, {
    components
  })
  const registeredComponents = Object.keys(Vue.options.components).sort()

  // remove vue builtins
  registeredComponents.splice(0, 3)

  it('should register all subcomponents', () => {
    expect(registeredComponents).toMatchSnapshot()
  })

  it('should register all names in PascalCase', () => {
    registeredComponents.forEach(name =>
      expect(name).toMatch(/^(?:[A-Z][a-z]*)+$/)
    )
  })

  it('should check all components', () => {
    expect(registeredComponents).toEqual(Object.keys(allComponents).sort())
  })
})


<template>
  <v-card flat>
    <v-card-text>
      <v-container fluid>
        <v-layout row wrap>
          <v-flex xs12 sm4 md4>
            <v-checkbox
              v-model="ex4"
              label="red"
              color="red"
              value="red"
              hide-details
            ></v-checkbox>
            <v-checkbox
              v-model="ex4"
              label="red darken-3"
              color="red darken-3"
              value="red darken-3"
              hide-details
            ></v-checkbox>
          </v-flex>
          <v-flex xs12 sm4 md4>
            <v-checkbox
              v-model="ex4"
              label="indigo"
              color="indigo"
              value="indigo"
              hide-details
            ></v-checkbox>
            <v-checkbox
              v-model="ex4"
              label="indigo darken-3"
              color="indigo darken-3"
              value="indigo darken-3"
              hide-details
            ></v-checkbox>
          </v-flex>
          <v-flex xs12 sm4 md4>
            <v-checkbox
              v-model="ex4"
              label="orange"
              color="orange"
              value="orange"
              hide-details
            ></v-checkbox>
            <v-checkbox
              v-model="ex4"
              label="orange darken-3"
              color="orange darken-3"
              value="orange darken-3"
              hide-details
            ></v-checkbox>
          </v-flex>
        </v-layout>

        <v-layout row wrap class="mt-5">
          <v-flex xs12 sm4 md4>
            <v-checkbox
              v-model="ex4"
              label="primary"
              color="primary"
              value="primary"
              hide-details
            ></v-checkbox>
            <v-checkbox
              v-model="ex4"
              label="secondary"
              color="secondary"
              value="secondary"
              hide-details
            ></v-checkbox>
          </v-flex>
          <v-flex xs12 sm4 md4>
            <v-checkbox
              v-model="ex4"
              label="success"
              color="success"
              value="success"
              hide-details
            ></v-checkbox>
            <v-checkbox
              v-model="ex4"
              label="info"
              color="info"
              value="info"
              hide-details
            ></v-checkbox>
          </v-flex>
          <v-flex xs12 sm4 md4>
            <v-checkbox
              v-model="ex4"
              label="warning"
              color="warning"
              value="warning"
              hide-details
            ></v-checkbox>
            <v-checkbox
              v-model="ex4"
              label="error"
              color="error"
              value="error"
              hide-details
            ></v-checkbox>
          </v-flex>
        </v-layout>
      </v-container>
    </v-card-text>
  </v-card>
</template>

<script>
  export default {
    data () {
      return {
        ex4: ['red', 'indigo', 'orange', 'primary', 'secondary', 'success', 'info', 'warning', 'error', 'red darken-3', 'indigo darken-3', 'orange darken-3']
      }
    }
  }
</script>


module.exports = {
  root: true,
  parserOptions: {
    parser: 'babel-eslint',
    ecmaVersion: 2017,
    sourceType: 'module'
  },
  env: {
    node: true,
    browser: true
  },
  extends: [
    'plugin:vue/recommended',
    'standard'
  ],
  globals: {
    docsearch: true
  },
  rules: {
    "vue/max-attributes-per-line": [2, {
      "singleline": 5,
      "multiline": {
        "max": 1,
        "allowFirstLine": false
      }
    }],
    "prefer-promise-reject-errors": 0
  },
  overrides: [
    {
      files: '**/*.vue',
      rules: {
        indent: false,
        // TODO: This breaks with shorthand property names (d40508db)
        /* "vue/script-indent": ["error", 2, {
          "baseIndent": 1,
          "switchCase": 1,
          "ignores": []
        }] */
      }
    },
    {
      files: 'examples/**/*.vue',
      rules: {
        "vue/valid-v-on": false,
        "vue/no-parsing-error": false, // This rule doesn't allow empty event listeners
        "vue/html-self-closing": ["error", {
          "html": {
            "void": "never",
            "normal": "never",
            "component": "never"
          },
          "svg": "always",
          "math": "always"
        }]
      }
    },
    {
      files: 'examples/layouts/**/*.vue',
      rules: {
        "vue/order-in-components": false,
        "vue/require-default-prop": false
      }
    }
  ]
}


@import '../bootstrap'
@import '../theme'

v-divider($material)
  border-color: $material.dividers

theme(v-divider, "v-divider")

.v-divider
  display: block
  flex: 1 1 0px
  max-width: 100%
  height: 0px
  max-height: 0px
  border: solid
  border-width: thin 0 0 0
  transition: inherit

  &--inset:not(.v-divider--vertical)
    margin-left: 72px
    max-width: calc(100% - 72px)

  &--vertical
    align-self: stretch
    border: solid
    border-width: 0 thin 0 0
    display: inline-flex
    height: inherit
    min-height: 100%
    max-height: 100%
    max-width: 0px
    width: 0px
    vertical-align: text-bottom

    &.v-divider--inset
      margin-top: 8px
      min-height: 0
      max-height: calc(100% - 16px)


// Utilities
import { getLongId, findProduct } from '@/util/helpers'

export default {
  data: () => ({
    meta: {},
    _description: {},
    _keywords: {}
  }),

  computed: {
    title () {
      return this.meta.title
    },
    description () {
      return this.meta.description
    },
    keywords () {
      return this.meta.keywords
    }
  },

  watch: {
    $route () {
      this.setMeta()
    },
    meta: {
      deep: true,
      handler () {
        document.title = `${this.title} — Vuetify.js`
        this._description.setAttribute('content', this.description)
        this._keywords.setAttribute('content', this.keywords)
      }
    }
  },

  created () {
    if (process.env.VUE_ENV === 'client') return

    this.setMeta()

    this.$ssrContext.title = `${this.title} — Vuetify.js`
    this.$ssrContext.description = this.description
    this.$ssrContext.keywords = this.keywords
  },

  mounted () {
    this.bootstrapMeta()
  },

  methods: {
    bootstrapMeta () {
      if (typeof document === 'undefined') return

      this._title = document.title
      this._description = document.querySelector('meta[name="description"]')
      this._keywords = document.querySelector('meta[name="keywords"]')

      this.setMeta()
    },
    getProductMeta () {
      const longId = getLongId(this.$route.params.id)
      const product = findProduct(this.$store, longId)

      return {
        title: product.title,
        description: product.description,
        keywords: `vuetify store, ${product.title}`
      }
    },
    setMeta () {
      const path = this.$route.path.split('/').slice(2).join('/')
      const lang = this.$route.path.split('/')[1]
      const meta = this.$i18n.getLocaleMessage(lang).meta || {}

      if (this.$route.path.indexOf('product') > -1) {
        return (this.meta = this.getProductMeta())
      }

      this.meta = meta[path] || this.getFallbackMeta(path) || {}
    },
    getFallbackMeta (path) {
      const fallbackmeta = this.$i18n.getLocaleMessage('en').meta
      if (process.env.NODE_ENV === 'development') {
        console.warn('Falling back to english meta for ' + (path || '/'))
      }
      return fallbackmeta[path]
    }
  }
}


<template>
  <playground></playground>
</template>

<script>
  import Playground from './Playground'

  export default {
    components: {
      Playground
    }
  }
</script>


// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`VTimePicker.js should accept a date object for a value 1`] = `

          12

          :

          00

          am

          pm

              12

              1

              2

              3

              4

              5

              6

              7

              8

              9

              10

              11

`;

exports[`VTimePicker.js should accept a value 1`] = `

          9

          :

          12

          am

          pm

              12

              1

              2

              3

              4

              5

              6

              7

              8

              9

              10

              11

`;

exports[`VTimePicker.js should change am/pm when updated from model 1`] = `

          9

          :

          00

          am

          pm

              12

              1

              2

              3

              4

              5

              6

              7

              8

              9

              10

              11

`;

exports[`VTimePicker.js should render colored time picker 1`] = `

          9

          :

          00

          am

          pm

              12

              1

              2

              3

              4

              5

              6

              7

              8

              9

              10

              11

`;

exports[`VTimePicker.js should render colored time picker 2`] = `

          9

          :

          00

          am

          pm

              12

              1

              2

              3

              4

              5

              6

              7

              8

              9

              10

              11

`;

exports[`VTimePicker.js should render dark time picker 1`] = `

          --

          :

          --

          am

          pm

              12

              1

              2

              3

              4

              5

              6

              7

              8

              9

              10

              11

`;

exports[`VTimePicker.js should render landscape component 1`] = `

          9

          :

          12

          am

          pm

              12

              1

              2

              3

              4

              5

              6

              7

              8

              9

              10

              11

`;


import { test } from '@/test'
import VSnackbar from '@/components/VSnackbar'

test('VSnackbar.vue', ({ mount }) => {
  it('should have a v-snack class', () => {
    const wrapper = mount(VSnackbar, {
      propsData: {
        value: true
      }
    })

    expect(wrapper.hasClass('v-snack')).toBe(true)
  })

  it('should have a v-snack__wrapper with a color class', () => {
    const wrapper = mount(VSnackbar, {
      propsData: {
        value: true,
        color: 'orange lighten-2'
      }
    })

    expect(wrapper.find('.v-snack__wrapper.orange')).toHaveLength(1)
    expect(wrapper.find('.v-snack__wrapper.lighten-2')).toHaveLength(1)
  })

  it('should have a v-snack__content class only when active', async () => {
    const wrapper = mount(VSnackbar, {
      propsData: {
        value: false,
        timeout: 1000
      }
    })

    expect(wrapper.find('div .v-snack__content')).toHaveLength(0)

    wrapper.setProps({ value: true })

    await wrapper.vm.$nextTick()

    expect(wrapper.find('div .v-snack__content')).toHaveLength(1)
  })

  it('should timeout correctly', async () => {
    jest.useFakeTimers()
    const wrapper = mount(VSnackbar, {
      propsData: {
        value: false,
        timeout: 3141
      }
    })

    const value = jest.fn()

    wrapper.instance().$on('input', value)
    wrapper.setProps({ value: true })
    wrapper.update()

    await wrapper.vm.$nextTick()

    expect(setTimeout.mock.calls).toHaveLength(1)
    expect(setTimeout.mock.calls[0][1]).toBe(3141)

    jest.runAllTimers()

    await wrapper.vm.$nextTick()

    expect(wrapper.data().isActive).toBe(false)
    expect(value).toBeCalledWith(false)
  })

  it('should timeout correctly when initial value is true', async () => {
    jest.useFakeTimers()
    const wrapper = mount(VSnackbar, {
      propsData: {
        value: true,
        timeout: 3141
      }
    })

    const value = jest.fn()

    wrapper.instance().$on('input', value)

    await wrapper.vm.$nextTick()

    expect(setTimeout.mock.calls).toHaveLength(1)
    expect(setTimeout.mock.calls[0][1]).toBe(3141)

    jest.runAllTimers()

    await wrapper.vm.$nextTick()

    expect(wrapper.data().isActive).toBe(false)
    expect(value).toBeCalledWith(false)
  })
})


keep keep keep keep replace keep keep keep keep

const onSubmit: SubmitHandler<WrapUpCallPayload> = (data: { comment?: string; tags?: string[] }): void => {

import { Button, ButtonGroup, Field, Modal, TextAreaInput } from '@rocket.chat/fuselage';
import React, { ReactElement, useEffect } from 'react';
import { useForm, SubmitHandler } from 'react-hook-form';

import { useCallCloseRoom } from '../../../contexts/CallContext';
import { useSetModal } from '../../../contexts/ModalContext';
import { useTranslation } from '../../../contexts/TranslationContext';
import Tags from '../../Omnichannel/Tags';

type WrapUpCallPayload = {
	comment: string;
	tags?: string[];
};

export const WrapUpCallModal = (): ReactElement => {
	const setModal = useSetModal();
	const closeRoom = useCallCloseRoom();

	const closeModal = (): void => setModal(null);
	const t = useTranslation();

	const { register, handleSubmit, setValue, watch } = useForm<WrapUpCallPayload>();

	const tags = watch('tags');

	useEffect(() => {
		register('tags');
	}, [register]);

	const handleTags = (value: string[]): void => {
		setValue('tags', value);
	};

	const onSubmit: SubmitHandler<WrapUpCallPayload> = (data): void => {
		closeRoom(data);
		closeModal();
	};

	const onCancel = (): void => {
		closeRoom({});
		closeModal();
	};

	return (
		<Modal is='form' onSubmit={handleSubmit(onSubmit)}>
			<Modal.Header>
				<Modal.Title>{t('Wrap_up_the_call')}</Modal.Title>
				<Modal.Close onClick={closeModal} />
			</Modal.Header>
			<Modal.Content>
				<Field mbe='24px'>
					<Field.Label>{t('Notes')}</Field.Label>
					<Field.Row>
						<TextAreaInput placeholder={t('Do_you_have_any_notes_for_this_conversation')} {...register('comment')} />
					</Field.Row>
					<Field.Hint>{t('These_notes_will_be_available_in_the_call_summary')}</Field.Hint>
				</Field>
				<Tags tags={tags} handler={handleTags as () => void} />
			</Modal.Content>
			<Modal.Footer>
				<ButtonGroup align='end'>
					<Button ghost onClick={onCancel}>
						{t('Cancel')}
					</Button>
					<Button type='submit' primary>
						{t('Save')}
					</Button>
				</ButtonGroup>
			</Modal.Footer>
		</Modal>
	);
};


export type IceServer = {
	urls: string;
	username?: string;
	credential?: string;
};


import { Meteor } from 'meteor/meteor';
import { createClient } from 'webdav';

import { settings } from '../../../settings/server';
import { getWebdavCredentials } from './getWebdavCredentials';
import { WebdavAccounts } from '../../../models/server/raw';

Meteor.methods({
	async getWebdavFilePreview(accountId, path) {
		const userId = Meteor.userId();

		if (!userId) {
			throw new Meteor.Error('error-invalid-user', 'Invalid User', {
				method: 'getWebdavFilePreview',
			});
		}

		if (!settings.get('Webdav_Integration_Enabled')) {
			throw new Meteor.Error('error-not-allowed', 'WebDAV Integration Not Allowed', {
				method: 'getWebdavFilePreview',
			});
		}

		const account = await WebdavAccounts.findOneByIdAndUserId(accountId, userId, {});
		if (!account) {
			throw new Meteor.Error('error-invalid-account', 'Invalid WebDAV Account', {
				method: 'getWebdavFilePreview',
			});
		}

		try {
			const cred = getWebdavCredentials(account);
			const client = createClient(account.serverURL, cred);
			const serverURL = settings.get('Accounts_OAuth_Nextcloud_URL');
			const res = await client.customRequest(`${serverURL}/index.php/core/preview.png?file=${path}&x=64&y=64`, {
				method: 'GET',
				responseType: 'arraybuffer',
			});
			return { success: true, data: res.data };
		} catch (error) {
			// ignore error
		}
	},
});


import { Box, Icon, Margins, Pagination, Skeleton, Table, Tile } from '@rocket.chat/fuselage';
import moment from 'moment';
import React, { ReactElement, useMemo, useState } from 'react';

import Growth from '../../../../../../client/components/data/Growth';
import { useTranslation } from '../../../../../../client/contexts/TranslationContext';
import Section from '../Section';
import DownloadDataButton from '../data/DownloadDataButton';
import PeriodSelector from '../data/PeriodSelector';
import { usePeriodSelectorState } from '../data/usePeriodSelectorState';
import { useChannelsList } from './useChannelsList';

const ChannelsTab = (): ReactElement => {
	const [period, periodSelectorProps] = usePeriodSelectorState('last 7 days', 'last 30 days', 'last 90 days');

	const t = useTranslation();

	const [current, setCurrent] = useState(0);
	const [itemsPerPage, setItemsPerPage] = useState<25 | 50 | 100>(25);

	const { data } = useChannelsList({
		period,
		offset: current,
		count: itemsPerPage,
	});

	const channels = useMemo(() => {
		if (!data) {
			return;
		}

		return data?.channels?.map(({ room: { t, name, usernames, ts, _updatedAt }, messages, diffFromLastWeek }) => ({
			t,
			name: name || usernames?.join(' × '),
			createdAt: ts,
			updatedAt: _updatedAt,
			messagesCount: messages,
			messagesVariation: diffFromLastWeek,
		}));
	}, [data]);

	return (
		<Section
			filter={
				<>
					<PeriodSelector {...periodSelectorProps} />
					<DownloadDataButton
						attachmentName={`Channels_start_${data?.start}_end_${data?.end}`}
						headers={['Room type', 'Name', 'Messages', 'Last Update Date', 'Creation Date']}
						dataAvailable={!!data}
						dataExtractor={(): unknown[][] | undefined =>
							data?.channels?.map(({ room: { t, name, usernames, ts, _updatedAt }, messages }) => [
								t,
								name || usernames?.join(' × '),
								messages,
								_updatedAt,
								ts,
							])
						}
					/>
				</>
			}
		>
			<Box>
				{channels && !channels.length && (
					<Tile fontScale='p1' color='info' style={{ textAlign: 'center' }}>
						{t('No_data_found')}
					</Tile>
				)}
				{(!channels || channels.length) && (
					<Table>
						<Table.Head>
							<Table.Row>
								<Table.Cell>{'#'}</Table.Cell>
								<Table.Cell>{t('Channel')}</Table.Cell>
								<Table.Cell>{t('Created')}</Table.Cell>
								<Table.Cell>{t('Last_active')}</Table.Cell>
								<Table.Cell>{t('Messages_sent')}</Table.Cell>
							</Table.Row>
						</Table.Head>
						<Table.Body>
							{channels?.map(({ t, name, createdAt, updatedAt, messagesCount, messagesVariation }, i) => (
								<Table.Row key={i}>
									<Table.Cell>{i + 1}.</Table.Cell>
									<Table.Cell>
										<Margins inlineEnd='x4'>
											{(t === 'd' && <Icon name='at' />) || (t === 'c' && <Icon name='lock' />) || (t === 'p' && <Icon name='hashtag' />)}
										</Margins>
										{name}
									</Table.Cell>
									<Table.Cell>{moment(createdAt).format('L')}</Table.Cell>
									<Table.Cell>{moment(updatedAt).format('L')}</Table.Cell>
									<Table.Cell>
										{messagesCount} <Growth>{messagesVariation}</Growth>
									</Table.Cell>
								</Table.Row>
							))}
							{!channels &&
								Array.from({ length: 5 }, (_, i) => (
									<Table.Row key={i}>
										<Table.Cell>
											<Skeleton width='100%' />
										</Table.Cell>
										<Table.Cell>
											<Skeleton width='100%' />
										</Table.Cell>
										<Table.Cell>
											<Skeleton width='100%' />
										</Table.Cell>
										<Table.Cell>
											<Skeleton width='100%' />
										</Table.Cell>
										<Table.Cell>
											<Skeleton width='100%' />
										</Table.Cell>
									</Table.Row>
								))}
						</Table.Body>
					</Table>
				)}
				<Pagination
					current={current}
					itemsPerPage={itemsPerPage}
					itemsPerPageLabel={(): string => t('Items_per_page:')}
					showingResultsLabel={({ count, current, itemsPerPage }): string =>
						t('Showing_results_of', current + 1, Math.min(current + itemsPerPage, count), count)
					}
					count={data?.total || 0}
					onSetItemsPerPage={setItemsPerPage}
					onSetCurrent={setCurrent}
				/>
			</Box>
		</Section>
	);
};

export default ChannelsTab;


closeRoom(data);
closeModal();
};
const onCancel = (): void => {
closeRoom({});
closeModal();
};

keep keep keep keep keep replace keep keep keep


import { Meteor } from 'meteor/meteor';

import { slashCommands } from '../../utils';
/*
 * Unflip is a named function that will replace /unflip commands
 * @param {Object} message - The message object
 */

function Unflip(command, params, item) {
	if (command === 'unflip') {
		const msg = item;
		msg.msg = `${params} ┬─┬ ノ( ゜-゜ノ)`;
		Meteor.call('sendMessage', msg);
	}
}

slashCommands.add('unflip', Unflip, {
	description: 'Slash_TableUnflip_Description',
	params: 'your_message_optional',
});


//! moment.js locale configuration
//! locale : Belarusian [be]
//! author : Dmitry Demidov : https://github.com/demidov91
//! author: Praleska: http://praleska.pro/
//! Author : Menelion Elensúle : https://github.com/Oire

;(function (global, factory) {
   typeof exports === 'object' && typeof module !== 'undefined'
       && typeof require === 'function' ? factory(require('../moment')) :
   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
   factory(global.moment)
}(this, function (moment) { 'use strict';

    function plural(word, num) {
        var forms = word.split('_');
        return num % 10 === 1 && num % 100 !== 11 ? forms[0] : (num % 10 >= 2 && num % 10 <= 4 && (num % 100 < 10 || num % 100 >= 20) ? forms[1] : forms[2]);
    }
    function relativeTimeWithPlural(number, withoutSuffix, key) {
        var format = {
            'mm': withoutSuffix ? 'хвіліна_хвіліны_хвілін' : 'хвіліну_хвіліны_хвілін',
            'hh': withoutSuffix ? 'гадзіна_гадзіны_гадзін' : 'гадзіну_гадзіны_гадзін',
            'dd': 'дзень_дні_дзён',
            'MM': 'месяц_месяцы_месяцаў',
            'yy': 'год_гады_гадоў'
        };
        if (key === 'm') {
            return withoutSuffix ? 'хвіліна' : 'хвіліну';
        }
        else if (key === 'h') {
            return withoutSuffix ? 'гадзіна' : 'гадзіну';
        }
        else {
            return number + ' ' + plural(format[key], +number);
        }
    }

    var be = moment.defineLocale('be', {
        months : {
            format: 'студзеня_лютага_сакавіка_красавіка_траўня_чэрвеня_ліпеня_жніўня_верасня_кастрычніка_лістапада_снежня'.split('_'),
            standalone: 'студзень_люты_сакавік_красавік_травень_чэрвень_ліпень_жнівень_верасень_кастрычнік_лістапад_снежань'.split('_')
        },
        monthsShort : 'студ_лют_сак_крас_трав_чэрв_ліп_жнів_вер_каст_ліст_снеж'.split('_'),
        weekdays : {
            format: 'нядзелю_панядзелак_аўторак_сераду_чацвер_пятніцу_суботу'.split('_'),
            standalone: 'нядзеля_панядзелак_аўторак_серада_чацвер_пятніца_субота'.split('_'),
            isFormat: /\[ ?[Вв] ?(?:мінулую|наступную)? ?\] ?dddd/
        },
        weekdaysShort : 'нд_пн_ат_ср_чц_пт_сб'.split('_'),
        weekdaysMin : 'нд_пн_ат_ср_чц_пт_сб'.split('_'),
        longDateFormat : {
            LT : 'HH:mm',
            LTS : 'HH:mm:ss',
            L : 'DD.MM.YYYY',
            LL : 'D MMMM YYYY г.',
            LLL : 'D MMMM YYYY г., HH:mm',
            LLLL : 'dddd, D MMMM YYYY г., HH:mm'
        },
        calendar : {
            sameDay: '[Сёння ў] LT',
            nextDay: '[Заўтра ў] LT',
            lastDay: '[Учора ў] LT',
            nextWeek: function () {
                return '[У] dddd [ў] LT';
            },
            lastWeek: function () {
                switch (this.day()) {
                    case 0:
                    case 3:
                    case 5:
                    case 6:
                        return '[У мінулую] dddd [ў] LT';
                    case 1:
                    case 2:
                    case 4:
                        return '[У мінулы] dddd [ў] LT';
                }
            },
            sameElse: 'L'
        },
        relativeTime : {
            future : 'праз %s',
            past : '%s таму',
            s : 'некалькі секунд',
            m : relativeTimeWithPlural,
            mm : relativeTimeWithPlural,
            h : relativeTimeWithPlural,
            hh : relativeTimeWithPlural,
            d : 'дзень',
            dd : relativeTimeWithPlural,
            M : 'месяц',
            MM : relativeTimeWithPlural,
            y : 'год',
            yy : relativeTimeWithPlural
        },
        meridiemParse: /ночы|раніцы|дня|вечара/,
        isPM : function (input) {
            return /^(дня|вечара)$/.test(input);
        },
        meridiem : function (hour, minute, isLower) {
            if (hour < 4) {
                return 'ночы';
            } else if (hour < 12) {
                return 'раніцы';
            } else if (hour < 17) {
                return 'дня';
            } else {
                return 'вечара';
            }
        },
        ordinalParse: /\d{1,2}-(і|ы|га)/,
        ordinal: function (number, period) {
            switch (period) {
                case 'M':
                case 'd':
                case 'DDD':
                case 'w':
                case 'W':
                    return (number % 10 === 2 || number % 10 === 3) && (number % 100 !== 12 && number % 100 !== 13) ? number + '-і' : number + '-ы';
                case 'D':
                    return number + '-га';
                default:
                    return number;
            }
        },
        week : {
            dow : 1, // Monday is the first day of the week.
            doy : 7  // The week that contains Jan 1st is the first week of the year.
        }
    });

    return be;

}));


<template name="userActionIndicator" args="rid, tmid">
	{{#if data}}

			{{#each data}}
				{{ users }}
				{{#if multi}}
					{{_ "are" }} {{_ action}}{{#unless end}},{{/unless}}
				{{else}}
					{{_ "is" }} {{_ action}}{{#unless end}},{{/unless}}
				{{/if}}
			{{/each}}

	{{/if}}
</template>


useEffect(() => closeRoom, [closeRoom]);


import { Meteor } from 'meteor/meteor';
import { ReactiveVar } from 'meteor/reactive-var';
import { Blaze } from 'meteor/blaze';
import { Session } from 'meteor/session';
import { Template } from 'meteor/templating';
import { TAPi18n } from 'meteor/rocketchat:tap-i18n';

import { auth } from '../oauth.js';
import { RocketChatAnnouncement } from '../../../lib';
import { popout } from '../../../ui-utils';
import { t } from '../../../utils';
import { settings } from '../../../settings';
import { callbacks } from '../../../../lib/callbacks';
import { hasAllPermission } from '../../../authorization';
import { Users, Rooms } from '../../../models';
import { handleError } from '../../../../client/lib/utils/handleError';
import { dispatchToastMessage } from '../../../../client/lib/toast';

export const call = (...args) =>
	new Promise(function (resolve, reject) {
		Meteor.call(...args, function (err, result) {
			if (err) {
				handleError(err);
				reject(err);
			}
			resolve(result);
		});
	});

export const close = (popup) =>
	new Promise(function (resolve) {
		const checkInterval = setInterval(() => {
			if (popup.closed) {
				clearInterval(checkInterval);
				resolve();
			}
		}, 300);
	});

function optionsFromUrl(url) {
	const options = {};
	const parsedUrl = url.match(
		/(http:|https:|)\/\/(www.)?(youtu(be\.com|\.be|be\.googleapis\.com))\/(video\/|embed\/|watch\?v=|v\/|embed\?clip=)?([A-Za-z0-9._%-]*)(\&\S+)?/,
	);
	options.url = url;
	if (parsedUrl != null) {
		options.id = parsedUrl[6];
		if (parsedUrl[3].includes('youtu')) {
			options.url = `https://www.youtube.com/embed/${parsedUrl[6]}`;
			options.thumbnail = `https://img.youtube.com/vi/${parsedUrl[6]}/0.jpg`;
		}
		// @TODO add support for other urls
	}
	return options;
}

Template.liveStreamTab.helpers({
	broadcastEnabled() {
		return !!settings.get('Broadcasting_enabled');
	},
	streamingSource() {
		return Template.instance().streamingOptions.get() ? Template.instance().streamingOptions.get().url : '';
	},
	streamingUnavailableMessage() {
		return Template.instance().streamingOptions.get() &&
			Template.instance().streamingOptions.get().message &&
			Template.instance().streamingOptions.get().message !== ''
			? Template.instance().streamingOptions.get().message
			: t('Livestream_not_found');
	},
	thumbnailUrl() {
		return Template.instance().streamingOptions.get() ? Template.instance().streamingOptions.get().thumbnail : '';
	},
	hasThumbnail() {
		return (
			!!Template.instance().streamingOptions.get() &&
			!!Template.instance().streamingOptions.get().thumbnail &&
			Template.instance().streamingOptions.get().thumbnail !== ''
		);
	},
	hasSource() {
		return (
			!!Template.instance().streamingOptions.get() &&
			!!Template.instance().streamingOptions.get().url &&
			Template.instance().streamingOptions.get().url !== ''
		);
	},
	canEdit() {
		return hasAllPermission('edit-room', this.rid);
	},
	editing() {
		return (
			Template.instance().editing.get() ||
			Template.instance().streamingOptions.get() == null ||
			(Template.instance().streamingOptions.get() != null &&
				(Template.instance().streamingOptions.get().url == null || Template.instance().streamingOptions.get().url === ''))
		);
	},
	canDock() {
		const livestreamTabSource = Template.instance().streamingOptions.get().url;
		let popoutSource = null;
		try {
			if (popout.context) {
				popoutSource = Blaze.getData(popout.context).data && Blaze.getData(popout.context).data.streamingSource;
			}
			if (popoutSource != null && livestreamTabSource === popoutSource) {
				return true;
			}
		} catch (e) {
			return false;
		}
		return false;
	},
	isPopoutOpen() {
		return Template.instance().popoutOpen.get();
	},
	isAudioOnly() {
		return Template.instance().streamingOptions.get() ? Template.instance().streamingOptions.get().isAudioOnly : false;
	},
});

Template.liveStreamTab.onCreated(function () {
	this.editing = new ReactiveVar(false);
	this.streamingOptions = new ReactiveVar();
	this.popoutOpen = new ReactiveVar(popout.context != null);

	this.autorun(() => {
		const room = Rooms.findOne(this.data.rid, { fields: { streamingOptions: 1 } });
		this.streamingOptions.set(room.streamingOptions);
	});
});

Template.liveStreamTab.onDestroyed(function () {
	if (popout.docked) {
		popout.close();
	}
});

Template.liveStreamTab.events({
	'click .js-cancel'(e, i) {
		e.preventDefault();
		i.editing.set(false);
	},
	'click .js-clear'(e, i) {
		e.preventDefault();

		const clearedObject = {};

		Meteor.call('saveRoomSettings', this.rid, 'streamingOptions', clearedObject, function (err) {
			if (err) {
				return handleError(err);
			}
			i.editing.set(false);
			i.streamingOptions.set(clearedObject);
			const roomAnnouncement = new RocketChatAnnouncement().getByRoom(i.data.rid);
			if (roomAnnouncement.getMessage() !== '') {
				roomAnnouncement.clear();
			}
			return dispatchToastMessage({
				type: 'success',
				message: TAPi18n.__('Livestream_source_changed_succesfully'),
			});
		});
	},
	'click .js-save'(e, i) {
		e.preventDefault();

		const streamingOptions = {
			...optionsFromUrl(i.find('[name=streaming-source]').value),
			isAudioOnly: i.find('[name=streaming-audio-only]').checked,
			message: i.find('[name=streaming-message]').value,
			type: 'livestream',
		};

		Meteor.call('saveRoomSettings', this.rid, 'streamingOptions', streamingOptions, function (err) {
			if (err) {
				return handleError(err);
			}
			i.editing.set(false);
			i.streamingOptions.set(streamingOptions);
			if (streamingOptions.url !== '') {
				new RocketChatAnnouncement({
					room: i.data.rid,
					message: 'Broadcast is now live. Click here to watch!',
					callback: 'openBroadcast',
				}).save();
			} else {
				const roomAnnouncement = new RocketChatAnnouncement().getByRoom(i.data.rid);
				if (roomAnnouncement.getMessage() !== '') {
					roomAnnouncement.clear();
				}
			}

			return dispatchToastMessage({
				type: 'success',
				message: TAPi18n.__('Livestream_source_changed_succesfully'),
			});
		});
	},
	'click .streaming-source-settings'(e, i) {
		e.preventDefault();
		i.editing.set(true);
	},
	'click .js-dock'(e) {
		e.stopPropagation();
		popout.docked = true;
	},
	'click .js-close'(e, i) {
		e.stopPropagation();
		let popoutSource = '';
		if (popout.context) {
			popoutSource = Blaze.getData(popout.context).data && Blaze.getData(popout.context).data.streamingSource;
		}
		popout.close();
		if (popoutSource !== Template.instance().streamingOptions.get().url) {
			popout.open({
				content: 'liveStreamView',
				data: {
					streamingSource: i.streamingOptions.get().url,
					isAudioOnly: i.streamingOptions.get().isAudioOnly,
					showVideoControls: true,
					streamingOptions: i.streamingOptions.get(),
				},
				onCloseCallback: () => i.popoutOpen.set(false),
			});
		}
	},
	'submit .liveStreamTab__form'(e, i) {
		e.preventDefault();
		e.stopPropagation();

		const streamingOptions = {
			...optionsFromUrl(i.find('[name=streaming-source]').value),
			isAudioOnly: i.find('[name=streaming-audio-only]').checked,
			message: i.find('[name=streaming-message]').value,
			type: 'livestream',
		};

		Meteor.call('saveRoomSettings', this.rid, 'streamingOptions', streamingOptions, function (err) {
			if (err) {
				return handleError(err);
			}
			i.editing.set(false);
			i.streamingOptions.set(streamingOptions);
			if (streamingOptions.url !== '') {
				new RocketChatAnnouncement({
					room: i.data.rid,
					message: 'Broadcast is now live. Click here to watch!',
					callback: 'openBroadcast',
				}).save();
			} else {
				const roomAnnouncement = new RocketChatAnnouncement().getByRoom(i.data.rid);
				if (roomAnnouncement.getMessage() !== '') {
					roomAnnouncement.clear();
				}
			}
			return dispatchToastMessage({
				type: 'success',
				message: TAPi18n.__('Livestream_source_changed_succesfully'),
			});
		});
	},
	'click .js-popout'(e, i) {
		e.preventDefault();
		popout.open({
			content: 'liveStreamView',
			data: {
				streamingSource: i.streamingOptions.get().url,
				isAudioOnly: i.streamingOptions.get().isAudioOnly,
				showVideoControls: true,
				streamingOptions: i.streamingOptions.get(),
			},
			onCloseCallback: () => i.popoutOpen.set(false),
		});
		i.popoutOpen.set(true);
	},
	async 'click .js-broadcast'(e, i) {
		e.preventDefault();
		e.currentTarget.classList.add('loading');
		try {
			const user = Users.findOne({ _id: Meteor.userId() }, { fields: { 'settings.livestream': 1 } });
			if (!user.settings || !user.settings.livestream) {
				await auth();
			}
			const result = await call('livestreamGet', { rid: i.data.rid });
			popout.open({
				content: 'broadcastView',
				data: {
					...result,
					showVideoControls: false,
					showStreamControls: true,
				},
				onCloseCallback: () => i.popoutOpen.set(false),
			});
		} catch (e) {
			console.log(e);
		} finally {
			e.currentTarget.classList.remove('loading');
		}
	},
});

callbacks.add('openBroadcast', (rid) => {
	const roomData = Session.get(`roomData${rid}`);
	if (!roomData) {
		return;
	}
	popout.open({
		content: 'liveStreamView',
		data: {
			streamingSource: roomData.streamingOptions.url,
			isAudioOnly: roomData.streamingOptions.isAudioOnly,
			showVideoControls: true,
			streamingOptions: roomData.streamingOptions,
		},
	});
});


export { createHexColorPreviewMessageRenderer } from './client';


openRoom: (rid: IVoipRoom['_id']) => void;

createRoom: (caller: ICallerInfo) => IVoipRoom['_id'];

closeRoom: (data: { comment?: string; tags?: string[] }) => void;

closeRoom: (data?: { comment?: string; tags?: string[] }) => void;


import { Meteor } from 'meteor/meteor';
import type { IMessage, IUser } from '@rocket.chat/core-typings';

import { FileUpload } from '../../../file-upload/server';
import { settings } from '../../../settings/server';
import { Messages, Rooms } from '../../../models/server';
import { Uploads } from '../../../models/server/raw';
import { api } from '../../../../server/sdk/api';
import { callbacks } from '../../../../lib/callbacks';
import { Apps } from '../../../apps/server';

export const deleteMessage = async function (message: IMessage, user: IUser): Promise<void> {
	const deletedMsg = Messages.findOneById(message._id);
	const isThread = deletedMsg.tcount > 0;
	const keepHistory = settings.get('Message_KeepHistory') || isThread;
	const showDeletedStatus = settings.get('Message_ShowDeletedStatus') || isThread;
	const bridges = Apps?.isLoaded() && Apps.getBridges();

	if (deletedMsg && bridges) {
		const prevent = Promise.await(bridges.getListenerBridge().messageEvent('IPreMessageDeletePrevent', deletedMsg));
		if (prevent) {
			throw new Meteor.Error('error-app-prevented-deleting', 'A Rocket.Chat App prevented the message deleting.');
		}
	}

	if (deletedMsg.tmid) {
		Messages.decreaseReplyCountById(deletedMsg.tmid, -1);
	}

	const files = (message.files || [message.file]).filter(Boolean); // Keep compatibility with old messages

	if (keepHistory) {
		if (showDeletedStatus) {
			Messages.cloneAndSaveAsHistoryById(message._id, user);
		} else {
			Messages.setHiddenById(message._id, true);
		}

		for await (const file of files) {
			file?._id && (await Uploads.update({ _id: file._id }, { $set: { _hidden: true } }));
		}
	} else {
		if (!showDeletedStatus) {
			Messages.removeById(message._id);
		}

		files.forEach((file) => {
			file?._id && FileUpload.getStore('Uploads').deleteById(file._id);
		});
	}

	const room = Rooms.findOneById(message.rid, { fields: { lastMessage: 1, prid: 1, mid: 1 } });
	callbacks.run('afterDeleteMessage', deletedMsg, room);

	// update last message
	if (settings.get('Store_Last_Message')) {
		if (!room.lastMessage || room.lastMessage._id === message._id) {
			Rooms.resetLastMessageById(message.rid, message._id);
		}
	}

	// decrease message count
	Rooms.decreaseMessageCountById(message.rid, 1);

	if (showDeletedStatus) {
		Messages.setAsDeletedByIdAndUser(message._id, user);
	} else {
		api.broadcast('notify.deleteMessage', message.rid, { _id: message._id });
	}

	if (bridges) {
		bridges.getListenerBridge().messageEvent('IPostMessageDeleted', deletedMsg);
	}
};


import React, { useContext, FC, ComponentProps } from 'react';

import PageContext from './PageContext';
import PageScrollableContent from './PageScrollableContent';

type PageScrollableContentWithShadowProps = ComponentProps<typeof PageScrollableContent>;

const PageScrollableContentWithShadow: FC<PageScrollableContentWithShadowProps> = ({ onScrollContent, ...props }) => {
	const [, setBorder] = useContext(PageContext);
	return (
		<PageScrollableContent
			onScrollContent={({ top, ...args }: { top: boolean }): void => {
				setBorder(!!top);
				onScrollContent?.({ top, ...args });
			}}
			{...props}
		/>
	);
};

export default PageScrollableContentWithShadow;


const restrictedRolePermissions = new Map();

export const AuthorizationUtils = class {
	static addRolePermissionWhiteList(roleId: string, list: string[]): void {
		if (!roleId) {
			throw new Error('invalid-param');
		}

		if (!list) {
			throw new Error('invalid-param');
		}

		if (!restrictedRolePermissions.has(roleId)) {
			restrictedRolePermissions.set(roleId, new Set());
		}

		const rules = restrictedRolePermissions.get(roleId);

		for (const permissionId of list) {
			rules.add(permissionId);
		}
	}

	static isPermissionRestrictedForRole(permissionId: string, roleId: string): boolean {
		if (!roleId || !permissionId) {
			throw new Error('invalid-param');
		}

		if (!restrictedRolePermissions.has(roleId)) {
			return false;
		}

		const rules = restrictedRolePermissions.get(roleId);
		if (!rules || !rules.size) {
			return false;
		}

		return !rules.has(permissionId);
	}

	static isPermissionRestrictedForRoleList(permissionId: string, roleList: string[]): boolean {
		if (!roleList || !permissionId) {
			throw new Error('invalid-param');
		}

		for (const roleId of roleList) {
			if (this.isPermissionRestrictedForRole(permissionId, roleId)) {
				return true;
			}
		}

		return false;
	}
};


closeRoom: async ({ comment, tags }: { comment: string; tags: string[] }): Promise<void> => {

roomInfo && (await voipCloseRoomEndpoint({ rid: roomInfo.rid, token: roomInfo.v.token || '', comment: comment || '', tags }));

const queueAggregator = voipClient.getAggregator();

keep keep keep keep keep replace replace keep keep keep keep keep

closeRoom: async (data?: { comment: string; tags: string[] }): Promise<void> => {


import type { IExternalComponent } from '@rocket.chat/apps-engine/definition/externalComponent';

export type AppsEndpoints = {
	'/apps/externalComponents': {
		GET: () => { externalComponents: IExternalComponent[] };
	};
};


import { Meteor } from 'meteor/meteor';

import { hasPermission } from '../../../../authorization/server';
import { Users } from '../../../../models/server';
import { Integrations } from '../../../../models/server/raw';
import { integrations } from '../../../lib/rocketchat';

Meteor.methods({
	async addOutgoingIntegration(integration) {
		if (!hasPermission(this.userId, 'manage-outgoing-integrations') && !hasPermission(this.userId, 'manage-own-outgoing-integrations')) {
			throw new Meteor.Error('not_authorized');
		}

		integration = integrations.validateOutgoing(integration, this.userId);

		integration._createdAt = new Date();
		integration._createdBy = Users.findOne(this.userId, { fields: { username: 1 } });

		const result = await Integrations.insertOne(integration);
		integration._id = result.insertedId;

		return integration;
	},
});


import './inputs.html';
import './templates';
import AutoComplete from './autocomplete-client';
import './autocomplete.css';

export { AutoComplete };