import { EJSON } from 'meteor/ejson';
import { Db, Collection } from 'mongodb';

import { IStreamerConstructor } from './modules/streamer/streamer.module';

/* eslint-disable @typescript-eslint/interface-name-prefix */
declare module 'meteor/random' {
	namespace Random {
		function _randomString(numberOfChars: number, map: string): string;
	}
}

declare module 'meteor/mongo' {
	namespace MongoInternals {
		function defaultRemoteCollectionDriver(): any;
	}
}

declare module 'meteor/accounts-base' {
	namespace Accounts {
		function _bcryptRounds(): number;

		function _getLoginToken(connectionId: string): string | undefined;

		function insertUserDoc(options: Record<string, any>, user: Record<string, any>): string;

		function _generateStampedLoginToken(): {token: string; when: Date};
	}
}

declare module 'meteor/meteor' {
	type globalError = Error;
	namespace Meteor {
		interface ErrorStatic {
			new (error: string | number, reason?: string, details?: any): Error;
		}
		interface Error extends globalError {
			error: string | number;
			reason?: string;
			details?: string | undefined | Record<string, string>;
		}

		const Streamer: IStreamerConstructor;

		const server: any;

		const runAsUser: (userId: string, scope: Function) => any;

		interface MethodThisType {
			twoFactorChecked: boolean | undefined;
		}
	}
}

declare module 'meteor/ddp-common' {
	namespace DDPCommon {
		function stringifyDDP(msg: EJSON): string;
		function parseDDP(msg: string): EJSON;
	}
}

declare module 'meteor/routepolicy' {
	export class RoutePolicy {
		static declare(urlPrefix: string, type: string): void;
	}
}

declare module 'meteor/rocketchat:tap-i18n' {
	namespace TAPi18n {
		function __(s: string, options: { lng: string }): string;
	}
}

declare module 'meteor/promise' {
	namespace Promise {
		function await(): any;
	}
}

declare module 'meteor/littledata:synced-cron' {
	interface ICronAddParameters {
		name: string;
		schedule: Function;
		job: Function;
	}
	namespace SyncedCron {
		function add(params: ICronAddParameters): string;
		function remove(name: string): string;
	}
}

declare module 'meteor/mongo' {
	interface RemoteCollectionDriver {
		mongo: MongoConnection;
	}
	interface OplogHandle {
		stop(): void;
		onOplogEntry(trigger: Record<string, any>, callback: Function): void;
		onSkippedEntries(callback: Function): void;
		waitUntilCaughtUp(): void;
		_defineTooFarBehind(value: number): void;
	}
	interface MongoConnection {
		db: Db;
		_oplogHandle: OplogHandle;
		rawCollection(name: string): Collection;
	}

	namespace MongoInternals {
		function defaultRemoteCollectionDriver(): RemoteCollectionDriver;

		class ConnectionClass {}

		function Connection(): ConnectionClass;
	}
}

declare module 'async_hooks' {
	export class AsyncLocalStorage<T> {
		disable(): void;

		getStore(): T | undefined;

		run(store: T, callback: (...args: any[]) => void, ...args: any[]): void;

		exit(callback: (...args: any[]) => void, ...args: any[]): void;

		runSyncAndReturn<R>(store: T, callback: (...args: any[]) => R, ...args: any[]): R;

		exitSyncAndReturn<R>(callback: (...args: any[]) => R, ...args: any[]): R;

		enterWith(store: T): void;
	}
}


const department = LivechatDepartment.findOneById(departmentId);

const { maxNumberSimultaneousChat } = department || {};

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

const user = Users.getAgentInfo(agentId);

const { livechat: { maxNumberSimultaneousChat } = {} } = user || {};

function PASS() {
	this.log('Received PASS command, continue registering...');

	this.registerSteps.push('PASS');
}

function SERVER(parsedMessage) {
	this.log('Received SERVER command, waiting for first PING...');

	this.serverPrefix = parsedMessage.prefix;

	this.registerSteps.push('SERVER');
}

function PING() {
	if (!this.isRegistered && this.registerSteps.length === 2) {
		this.log('Received first PING command, server is registered!');

		this.isRegistered = true;

		this.emit('registered');
	}

	this.write({
		prefix: this.config.server.name,
		command: 'PONG',
		parameters: [this.config.server.name],
	});
}

function NICK(parsedMessage) {
	let command;

	// Check if the message comes from the server,
	// which means it is a new user
	if (parsedMessage.prefix === this.serverPrefix) {
		command = {
			identifier: 'userRegistered',
			args: {
				nick: parsedMessage.args[0],
				username: parsedMessage.args[2],
				host: parsedMessage.args[3],
				name: parsedMessage.args[6],
			},
		};
	} else { // Otherwise, it is a nick change
		command = {
			identifier: 'nickChanged',
			args: {
				nick: parsedMessage.nick,
				newNick: parsedMessage.args[0],
			},
		};
	}

	return command;
}

function JOIN(parsedMessage) {
	const command = {
		identifier: 'joinedChannel',
		args: {
			roomName: parsedMessage.args[0].substring(1),
			nick: parsedMessage.prefix,
		},
	};

	return command;
}

function PART(parsedMessage) {
	const command = {
		identifier: 'leftChannel',
		args: {
			roomName: parsedMessage.args[0].substring(1),
			nick: parsedMessage.prefix,
		},
	};

	return command;
}

function PRIVMSG(parsedMessage) {
	const command = {
		identifier: 'sentMessage',
		args: {
			nick: parsedMessage.prefix,
			message: parsedMessage.args[1],
		},
	};

	if (parsedMessage.args[0][0] === '#') {
		command.args.roomName = parsedMessage.args[0].substring(1);
	} else {
		command.args.recipientNick = parsedMessage.args[0];
	}

	return command;
}

function QUIT(parsedMessage) {
	const command = {
		identifier: 'disconnected',
		args: {
			nick: parsedMessage.prefix,
		},
	};

	return command;
}

export default { PASS, SERVER, PING, NICK, JOIN, PART, PRIVMSG, QUIT };


import { api } from '../api';

type FunctionPropertyNames<T> = {
	[K in keyof T]: T[K] extends Function ? K : never;
}[keyof T];

type Prom<T> = {
	[K in FunctionPropertyNames<T>]: ReturnType<T[K]> extends Promise<any> ? T[K] : (...params: Parameters<T[K]>) => Promise<ReturnType<T[K]>>;
}

type PromOrError<T> = {
	[K in FunctionPropertyNames<T>]: ReturnType<T[K]> extends Promise<any> ? (...params: Parameters<T[K]>) => ReturnType<T[K]> | Promise<Error> : (...params: Parameters<T[K]>) => Promise<ReturnType<T[K]> | Error>;
}

function handler<T extends object>(namespace: string, waitService: boolean): ProxyHandler<T> {
	return {
		get: (_target: T, prop: string): any => (...params: any): Promise<any> => api[waitService ? 'waitAndCall' : 'call'](`${ namespace }.${ prop }`, params),
	};
}

export function proxifyWithWait<T>(namespace: string): Prom<T> {
	return new Proxy({}, handler(namespace, true)) as unknown as Prom<T>;
}

export function proxify<T>(namespace: string): PromOrError<T> {
	return new Proxy({}, handler(namespace, false)) as unknown as Prom<T>;
}


if (!this.isActive || this.$refs.content.contains(target)) return false

// If we made it here, the click is outside

// and is active. If persistent, and the

keep keep keep replace keep keep keep keep keep

if (this._isDestroyed || !this.isActive || this.$refs.content.contains(target)) return false

// Styles
import './VNavigationDrawer.sass'

// Components
import VImg, { srcObject } from '../VImg/VImg'

// Mixins
import Applicationable from '../../mixins/applicationable'
import Colorable from '../../mixins/colorable'
import Dependent from '../../mixins/dependent'
import Overlayable from '../../mixins/overlayable'
import SSRBootable from '../../mixins/ssr-bootable'
import Themeable from '../../mixins/themeable'

// Directives
import ClickOutside from '../../directives/click-outside'
import Resize from '../../directives/resize'
import Touch, { TouchWrapper } from '../../directives/touch'

// Utilities
import { convertToUnit, getSlot } from '../../util/helpers'
import mixins from '../../util/mixins'

// Types
import { VNode, VNodeDirective } from 'vue'
import { PropValidator } from 'vue/types/options'

const baseMixins = mixins(
  Applicationable('left', [
    'isActive',
    'isMobile',
    'miniVariant',
    'expandOnHover',
    'permanent',
    'right',
    'temporary',
    'width',
  ]),
  Colorable,
  Dependent,
  Overlayable,
  SSRBootable,
  Themeable
)

/* @vue/component */
export default baseMixins.extend({
  name: 'v-navigation-drawer',

  provide (): object {
    return {
      isInNav: this.tag === 'nav',
    }
  },

  directives: {
    ClickOutside,
    Resize,
    Touch,
  },

  props: {
    bottom: Boolean,
    clipped: Boolean,
    disableResizeWatcher: Boolean,
    disableRouteWatcher: Boolean,
    expandOnHover: Boolean,
    floating: Boolean,
    height: {
      type: [Number, String],
      default (): string {
        return this.app ? '100vh' : '100%'
      },
    },
    miniVariant: Boolean,
    miniVariantWidth: {
      type: [Number, String],
      default: 80,
    },
    mobileBreakPoint: {
      type: [Number, String],
      default: 1264,
    },
    permanent: Boolean,
    right: Boolean,
    src: {
      type: [String, Object],
      default: '',
    } as PropValidator<string | srcObject>,
    stateless: Boolean,
    tag: {
      type: String,
      default (): string {
        return this.app ? 'nav' : 'aside'
      },
    },
    temporary: Boolean,
    touchless: Boolean,
    width: {
      type: [Number, String],
      default: 256,
    },
    value: { required: false } as PropValidator<any>,
  },

  data: () => ({
    isMouseover: false,
    touchArea: {
      left: 0,
      right: 0,
    },
    stackMinZIndex: 6,
  }),

  computed: {
    /**
     * Used for setting an app value from a dynamic
     * property. Called from applicationable.js
     */
    applicationProperty (): string {
      return this.right ? 'right' : 'left'
    },
    classes (): object {
      return {
        'v-navigation-drawer': true,
        'v-navigation-drawer--absolute': this.absolute,
        'v-navigation-drawer--bottom': this.bottom,
        'v-navigation-drawer--clipped': this.clipped,
        'v-navigation-drawer--close': !this.isActive,
        'v-navigation-drawer--fixed': !this.absolute && (this.app || this.fixed),
        'v-navigation-drawer--floating': this.floating,
        'v-navigation-drawer--is-mobile': this.isMobile,
        'v-navigation-drawer--is-mouseover': this.isMouseover,
        'v-navigation-drawer--mini-variant': this.miniVariant || (this.expandOnHover && !this.isMouseover),
        'v-navigation-drawer--open': this.isActive,
        'v-navigation-drawer--open-on-hover': this.expandOnHover,
        'v-navigation-drawer--right': this.right,
        'v-navigation-drawer--temporary': this.temporary,
        ...this.themeClasses,
      }
    },
    computedMaxHeight (): number | null {
      if (!this.hasApp) return null

      const computedMaxHeight = (
        this.$vuetify.application.bottom +
        this.$vuetify.application.footer +
        this.$vuetify.application.bar
      )

      if (!this.clipped) return computedMaxHeight

      return computedMaxHeight + this.$vuetify.application.top
    },
    computedTop (): number {
      if (!this.hasApp) return 0

      let computedTop = this.$vuetify.application.bar

      computedTop += this.clipped
        ? this.$vuetify.application.top
        : 0

      return computedTop
    },
    computedTransform (): number {
      if (this.isActive) return 0
      if (this.isBottom) return 100
      return this.right ? 100 : -100
    },
    computedWidth (): string | number {
      if (
        (this.expandOnHover && !this.isMouseover) ||
        this.miniVariant
      ) return this.miniVariantWidth

      return this.width
    },
    hasApp (): boolean {
      return (
        this.app &&
        (!this.isMobile && !this.temporary)
      )
    },
    isBottom (): boolean {
      return this.bottom && this.isMobile
    },
    isMobile (): boolean {
      return (
        !this.stateless &&
        !this.permanent &&
        this.$vuetify.breakpoint.width < parseInt(this.mobileBreakPoint, 10)
      )
    },
    reactsToClick (): boolean {
      return (
        !this.stateless &&
        !this.permanent &&
        (this.isMobile || this.temporary)
      )
    },
    reactsToMobile (): boolean {
      return (
        this.app &&
        !this.disableResizeWatcher &&
        !this.permanent &&
        !this.stateless &&
        !this.temporary
      )
    },
    reactsToResize (): boolean {
      return !this.disableResizeWatcher && !this.stateless
    },
    reactsToRoute (): boolean {
      return (
        !this.disableRouteWatcher &&
        !this.stateless &&
        (this.temporary || this.isMobile)
      )
    },
    showOverlay (): boolean {
      return (
        this.isActive &&
        (this.isMobile || this.temporary)
      )
    },
    styles (): object {
      const translate = this.isBottom ? 'translateY' : 'translateX'
      const styles = {
        height: convertToUnit(this.height),
        top: !this.isBottom ? convertToUnit(this.computedTop) : 'auto',
        maxHeight: this.computedMaxHeight != null
          ? `calc(100% - ${convertToUnit(this.computedMaxHeight)})`
          : undefined,
        transform: `${translate}(${convertToUnit(this.computedTransform, '%')})`,
        width: convertToUnit(this.computedWidth),
      }

      return styles
    },
  },

  watch: {
    $route: 'onRouteChange',
    isActive (val) {
      this.$emit('input', val)
    },
    /**
     * When mobile changes, adjust the active state
     * only when there has been a previous value
     */
    isMobile (val, prev) {
      !val &&
        this.isActive &&
        !this.temporary &&
        this.removeOverlay()

      if (prev == null ||
        !this.reactsToResize ||
        !this.reactsToMobile
      ) return

      this.isActive = !val
    },
    permanent (val) {
      // If enabling prop enable the drawer
      if (val) this.isActive = true
    },
    showOverlay (val) {
      if (val) this.genOverlay()
      else this.removeOverlay()
    },
    value (val) {
      if (this.permanent) return

      if (val == null) {
        this.init()
        return
      }

      if (val !== this.isActive) this.isActive = val
    },
  },

  beforeMount () {
    this.init()
  },

  methods: {
    calculateTouchArea () {
      const parent = this.$el.parentNode as Element

      if (!parent) return

      const parentRect = parent.getBoundingClientRect()

      this.touchArea = {
        left: parentRect.left + 50,
        right: parentRect.right - 50,
      }
    },
    closeConditional () {
      return this.isActive && this.reactsToClick
    },
    genAppend () {
      return this.genPosition('append')
    },
    genBackground () {
      const props = {
        height: '100%',
        width: '100%',
        src: this.src,
      }

      const image = this.$scopedSlots.img
        ? this.$scopedSlots.img(props)
        : this.$createElement(VImg, { props })

      return this.$createElement('div', {
        staticClass: 'v-navigation-drawer__image',
      }, [image])
    },
    genDirectives (): VNodeDirective[] {
      const directives = [{
        name: 'click-outside',
        value: () => (this.isActive = false),
        args: {
          closeConditional: this.closeConditional,
          include: this.getOpenDependentElements,
        },
      }]

      if (!this.touchless && !this.stateless) {
        directives.push({
          name: 'touch',
          value: {
            parent: true,
            left: this.swipeLeft,
            right: this.swipeRight,
          },
        } as any)
      }

      return directives
    },
    genListeners () {
      const on: Record<string, (e: Event) => void> = {
        transitionend: (e: Event) => {
          if (e.target !== e.currentTarget) return
          this.$emit('transitionend', e)

          // IE11 does not support new Event('resize')
          const resizeEvent = document.createEvent('UIEvents')
          resizeEvent.initUIEvent('resize', true, false, window, 0)
          window.dispatchEvent(resizeEvent)
        },
      }

      if (this.miniVariant) {
        on.click = () => this.$emit('update:mini-variant', false)
      }

      if (this.expandOnHover) {
        on.mouseenter = () => (this.isMouseover = true)
        on.mouseleave = () => (this.isMouseover = false)
      }

      return on
    },
    genPosition (name: 'prepend' | 'append') {
      const slot = getSlot(this, name)

      if (!slot) return slot

      return this.$createElement('div', {
        staticClass: `v-navigation-drawer__${name}`,
      }, slot)
    },
    genPrepend () {
      return this.genPosition('prepend')
    },
    genContent () {
      return this.$createElement('div', {
        staticClass: 'v-navigation-drawer__content',
      }, this.$slots.default)
    },
    genBorder () {
      return this.$createElement('div', {
        staticClass: 'v-navigation-drawer__border',
      })
    },
    init () {
      if (this.permanent) {
        this.isActive = true
      } else if (this.stateless ||
        this.value != null
      ) {
        this.isActive = this.value
      } else if (!this.temporary) {
        this.isActive = !this.isMobile
      }
    },
    onRouteChange () {
      if (this.reactsToRoute && this.closeConditional()) {
        this.isActive = false
      }
    },
    swipeLeft (e: TouchWrapper) {
      if (this.isActive && this.right) return
      this.calculateTouchArea()

      if (Math.abs(e.touchendX - e.touchstartX) < 100) return
      if (this.right &&
        e.touchstartX >= this.touchArea.right
      ) this.isActive = true
      else if (!this.right && this.isActive) this.isActive = false
    },
    swipeRight (e: TouchWrapper) {
      if (this.isActive && !this.right) return
      this.calculateTouchArea()

      if (Math.abs(e.touchendX - e.touchstartX) < 100) return
      if (!this.right &&
        e.touchstartX <= this.touchArea.left
      ) this.isActive = true
      else if (this.right && this.isActive) this.isActive = false
    },
    /**
     * Update the application layout
     */
    updateApplication () {
      if (
        !this.isActive ||
        this.isMobile ||
        this.temporary ||
        !this.$el
      ) return 0

      const width = Number(this.computedWidth)

      return isNaN(width) ? this.$el.clientWidth : width
    },
  },

  render (h): VNode {
    const children = [
      this.genPrepend(),
      this.genContent(),
      this.genAppend(),
      this.genBorder(),
    ]

    if (this.src || getSlot(this, 'img')) children.unshift(this.genBackground())

    return h(this.tag, this.setBackgroundColor(this.color, {
      class: this.classes,
      style: this.styles,
      directives: this.genDirectives(),
      on: this.genListeners(),
    }), children)
  },
})


// Styles
import './VTextField.sass'

// Extensions
import VInput from '../VInput'

// Components
import VCounter from '../VCounter'
import VLabel from '../VLabel'

// Mixins
import Loadable from '../../mixins/loadable'

// Directives
import ripple from '../../directives/ripple'

// Utilities
import { convertToUnit, keyCodes } from '../../util/helpers'
import { breaking, consoleWarn } from '../../util/console'

// Types
import mixins from '../../util/mixins'
import { VNode } from 'vue/types'

const baseMixins = mixins(
  VInput,
  Loadable
)
interface options extends InstanceType<typeof baseMixins> {
  $refs: {
    label: HTMLElement
    input: HTMLInputElement
    'prepend-inner': HTMLElement
    prefix: HTMLElement
    suffix: HTMLElement
  }
}

const dirtyTypes = ['color', 'file', 'time', 'date', 'datetime-local', 'week', 'month']

/* @vue/component */
export default baseMixins.extend<options>().extend({
  name: 'v-text-field',

  directives: { ripple },

  inheritAttrs: false,

  props: {
    appendOuterIcon: String,
    autofocus: Boolean,
    clearable: Boolean,
    clearIcon: {
      type: String,
      default: '$vuetify.icons.clear',
    },
    counter: [Boolean, Number, String],
    filled: Boolean,
    flat: Boolean,
    fullWidth: Boolean,
    label: String,
    outlined: Boolean,
    placeholder: String,
    prefix: String,
    prependInnerIcon: String,
    reverse: Boolean,
    rounded: Boolean,
    shaped: Boolean,
    singleLine: Boolean,
    solo: Boolean,
    soloInverted: Boolean,
    suffix: String,
    type: {
      type: String,
      default: 'text',
    },
  },

  data: () => ({
    badInput: false,
    labelWidth: 0,
    prefixWidth: 0,
    prependWidth: 0,
    initialValue: null,
    isBooted: false,
    isClearing: false,
  }),

  computed: {
    classes (): object {
      return {
        ...VInput.options.computed.classes.call(this),
        'v-text-field': true,
        'v-text-field--full-width': this.fullWidth,
        'v-text-field--prefix': this.prefix,
        'v-text-field--single-line': this.isSingle,
        'v-text-field--solo': this.isSolo,
        'v-text-field--solo-inverted': this.soloInverted,
        'v-text-field--solo-flat': this.flat,
        'v-text-field--filled': this.filled,
        'v-text-field--is-booted': this.isBooted,
        'v-text-field--enclosed': this.isEnclosed,
        'v-text-field--reverse': this.reverse,
        'v-text-field--outlined': this.outlined,
        'v-text-field--placeholder': this.placeholder,
        'v-text-field--rounded': this.rounded,
        'v-text-field--shaped': this.shaped,
      }
    },
    counterValue (): number {
      return (this.internalValue || '').toString().length
    },
    internalValue: {
      get (): any {
        return this.lazyValue
      },
      set (val: any) {
        this.lazyValue = val
        this.$emit('input', this.lazyValue)
      },
    },
    isDirty (): boolean {
      return (this.lazyValue != null &&
        this.lazyValue.toString().length > 0) ||
        this.badInput
    },
    isEnclosed (): boolean {
      return (
        this.filled ||
        this.isSolo ||
        this.outlined ||
        this.fullWidth
      )
    },
    isLabelActive (): boolean {
      return this.isDirty || dirtyTypes.includes(this.type)
    },
    isSingle (): boolean {
      return this.isSolo || this.singleLine || this.fullWidth
    },
    isSolo (): boolean {
      return this.solo || this.soloInverted
    },
    labelPosition (): Record<'left' | 'right', string | number | undefined> {
      let offset = (this.prefix && !this.labelValue) ? this.prefixWidth : 0

      if (this.labelValue && this.prependWidth) offset -= this.prependWidth

      return (this.$vuetify.rtl === this.reverse) ? {
        left: offset,
        right: 'auto',
      } : {
        left: 'auto',
        right: offset,
      }
    },
    showLabel (): boolean {
      return this.hasLabel && (!this.isSingle || (!this.isLabelActive && !this.placeholder))
    },
    labelValue (): boolean {
      return !this.isSingle &&
        Boolean(this.isFocused || this.isLabelActive || this.placeholder)
    },
  },

  watch: {
    labelValue: 'setLabelWidth',
    outlined: 'setLabelWidth',
    label () {
      this.$nextTick(this.setLabelWidth)
    },
    prefix () {
      this.$nextTick(this.setPrefixWidth)
    },
    isFocused (val) {
      // Sets validationState from validatable
      this.hasColor = val

      if (val) {
        this.initialValue = this.lazyValue
      } else if (this.initialValue !== this.lazyValue) {
        this.$emit('change', this.lazyValue)
      }
    },
    value (val) {
      this.lazyValue = val
    },
  },

  created () {
    /* istanbul ignore next */
    if (this.$attrs.hasOwnProperty('box')) {
      breaking('box', 'filled', this)
    }

    /* istanbul ignore next */
    if (this.$attrs.hasOwnProperty('browser-autocomplete')) {
      breaking('browser-autocomplete', 'autocomplete', this)
    }

    /* istanbul ignore if */
    if (this.shaped && !(this.filled || this.outlined || this.isSolo)) {
      consoleWarn('shaped should be used with either filled or outlined', this)
    }
  },

  mounted () {
    this.autofocus && this.onFocus()
    this.setLabelWidth()
    this.setPrefixWidth()
    this.setPrependWidth()
    requestAnimationFrame(() => (this.isBooted = true))
  },

  methods: {
    /** @public */
    focus () {
      this.onFocus()
    },
    /** @public */
    blur (e?: Event) {
      // https://github.com/vuetifyjs/vuetify/issues/5913
      // Safari tab order gets broken if called synchronous
      window.requestAnimationFrame(() => {
        this.$refs.input && this.$refs.input.blur()
      })
      this.onBlur(e)
    },
    clearableCallback () {
      this.internalValue = null
      this.$nextTick(() => this.$refs.input && this.$refs.input.focus())
    },
    genAppendSlot () {
      const slot = []

      if (this.$slots['append-outer']) {
        slot.push(this.$slots['append-outer'] as VNode[])
      } else if (this.appendOuterIcon) {
        slot.push(this.genIcon('appendOuter'))
      }

      return this.genSlot('append', 'outer', slot)
    },
    genPrependInnerSlot () {
      const slot = []

      if (this.$slots['prepend-inner']) {
        slot.push(this.$slots['prepend-inner'] as VNode[])
      } else if (this.prependInnerIcon) {
        slot.push(this.genIcon('prependInner'))
      }

      return this.genSlot('prepend', 'inner', slot)
    },
    genIconSlot () {
      const slot = []

      if (this.$slots['append']) {
        slot.push(this.$slots['append'] as VNode[])
      } else if (this.appendIcon) {
        slot.push(this.genIcon('append'))
      }

      return this.genSlot('append', 'inner', slot)
    },
    genInputSlot () {
      const input = VInput.options.methods.genInputSlot.call(this)

      const prepend = this.genPrependInnerSlot()

      if (prepend) {
        input.children = input.children || []
        input.children.unshift(prepend)
      }

      return input
    },
    genClearIcon () {
      if (!this.clearable) return null

      const icon = this.isDirty ? 'clear' : ''

      return this.genSlot('append', 'inner', [
        this.genIcon(
          icon,
          this.clearableCallback
        ),
      ])
    },
    genCounter () {
      if (this.counter === false || this.counter == null) return null

      const max = this.counter === true ? this.$attrs.maxlength : this.counter

      return this.$createElement(VCounter, {
        props: {
          dark: this.dark,
          light: this.light,
          max,
          value: this.counterValue,
        },
      })
    },
    genDefaultSlot () {
      return [
        this.genFieldset(),
        this.genTextFieldSlot(),
        this.genClearIcon(),
        this.genIconSlot(),
        this.genProgress(),
      ]
    },
    genFieldset () {
      if (!this.outlined) return null

      return this.$createElement('fieldset', {
        attrs: {
          'aria-hidden': true,
        },
      }, [this.genLegend()])
    },
    genLabel () {
      if (!this.showLabel) return null

      const data = {
        props: {
          absolute: true,
          color: this.validationState,
          dark: this.dark,
          disabled: this.disabled,
          focused: !this.isSingle && (this.isFocused || !!this.validationState),
          for: this.computedId,
          left: this.labelPosition.left,
          light: this.light,
          right: this.labelPosition.right,
          value: this.labelValue,
        },
      }

      return this.$createElement(VLabel, data, this.$slots.label || this.label)
    },
    genLegend () {
      const width = !this.singleLine && (this.labelValue || this.isDirty) ? this.labelWidth : 0
      const span = this.$createElement('span', {
        domProps: { innerHTML: '' },
      })

      return this.$createElement('legend', {
        style: {
          width: !this.isSingle ? convertToUnit(width) : undefined,
        },
      }, [span])
    },
    genInput () {
      const listeners = Object.assign({}, this.$listeners)
      delete listeners['change'] // Change should not be bound externally

      return this.$createElement('input', {
        style: {},
        domProps: {
          value: this.lazyValue,
        },
        attrs: {
          ...this.$attrs,
          autofocus: this.autofocus,
          disabled: this.disabled,
          id: this.computedId,
          placeholder: this.placeholder,
          readonly: this.readonly,
          type: this.type,
        },
        on: Object.assign(listeners, {
          blur: this.onBlur,
          input: this.onInput,
          focus: this.onFocus,
          keydown: this.onKeyDown,
        }),
        ref: 'input',
      })
    },
    genMessages () {
      if (this.hideDetails) return null

      return this.$createElement('div', {
        staticClass: 'v-text-field__details',
      }, [
        VInput.options.methods.genMessages.call(this),
        this.genCounter(),
      ])
    },
    genTextFieldSlot () {
      return this.$createElement('div', {
        staticClass: 'v-text-field__slot',
      }, [
        this.genLabel(),
        this.prefix ? this.genAffix('prefix') : null,
        this.genInput(),
        this.suffix ? this.genAffix('suffix') : null,
      ])
    },
    genAffix (type: 'prefix' | 'suffix') {
      return this.$createElement('div', {
        class: `v-text-field__${type}`,
        ref: type,
      }, this[type])
    },
    onBlur (e?: Event) {
      this.isFocused = false
      e && this.$emit('blur', e)
    },
    onClick () {
      if (this.isFocused || this.disabled) return

      this.$refs.input.focus()
    },
    onFocus (e?: Event) {
      if (!this.$refs.input) return

      if (document.activeElement !== this.$refs.input) {
        return this.$refs.input.focus()
      }

      if (!this.isFocused) {
        this.isFocused = true
        e && this.$emit('focus', e)
      }
    },
    onInput (e: Event) {
      const target = e.target as HTMLInputElement
      this.internalValue = target.value
      this.badInput = target.validity && target.validity.badInput
    },
    onKeyDown (e: KeyboardEvent) {
      if (e.keyCode === keyCodes.enter) this.$emit('change', this.internalValue)

      this.$emit('keydown', e)
    },
    onMouseDown (e: Event) {
      // Prevent input from being blurred
      if (e.target !== this.$refs.input) {
        e.preventDefault()
        e.stopPropagation()
      }

      VInput.options.methods.onMouseDown.call(this, e)
    },
    onMouseUp (e: Event) {
      if (this.hasMouseDown) this.focus()

      VInput.options.methods.onMouseUp.call(this, e)
    },
    setLabelWidth () {
      if (!this.outlined || !this.$refs.label) return

      this.labelWidth = this.$refs.label.offsetWidth * 0.75 + 6
    },
    setPrefixWidth () {
      if (!this.$refs.prefix) return

      this.prefixWidth = this.$refs.prefix.offsetWidth
    },
    setPrependWidth () {
      if (!this.outlined || !this.$refs['prepend-inner']) return

      this.prependWidth = this.$refs['prepend-inner'].offsetWidth
    },
  },
})


const listeners = Menuable.options.methods.genActivatorListeners.call(this)

keep keep keep add keep keep keep keep keep

// Styles
import '../VTextField/VTextField.sass'
import './VSelect.sass'

// Components
import VChip from '../VChip'
import VMenu from '../VMenu'
import VSelectList from './VSelectList'

// Extensions
import VTextField from '../VTextField/VTextField'

// Mixins
import Comparable from '../../mixins/comparable'
import Filterable from '../../mixins/filterable'

// Directives
import ClickOutside from '../../directives/click-outside'

// Utilities
import { getPropertyFromItem, keyCodes } from '../../util/helpers'
import { consoleError } from '../../util/console'

// Types
import mixins from '../../util/mixins'
import { PropValidator } from 'vue/types/options'
import { VNode, VNodeDirective } from 'vue'

export const defaultMenuProps = {
  closeOnClick: false,
  closeOnContentClick: false,
  disableKeys: true,
  openOnClick: false,
  maxHeight: 304,
}

// Types
type ItemProperty = PropValidator<string | (string | number)[] | ((item: object, fallback?: any) => any)>
const baseMixins = mixins(
  VTextField,
  Comparable,
  Filterable
)

interface options extends InstanceType<typeof baseMixins> {
  $refs: {
    menu: InstanceType<typeof VMenu>
    label: HTMLElement
    input: HTMLInputElement
    'prepend-inner': HTMLElement
    prefix: HTMLElement
    suffix: HTMLElement
  }
}

/* @vue/component */
export default baseMixins.extend<options>().extend({
  name: 'v-select',

  directives: {
    ClickOutside,
  },

  props: {
    appendIcon: {
      type: String,
      default: '$vuetify.icons.dropdown',
    },
    attach: {
      default: false,
    } as PropValidator<string | boolean | Element | VNode>,
    cacheItems: Boolean,
    chips: Boolean,
    clearable: Boolean,
    deletableChips: Boolean,
    dense: Boolean,
    eager: Boolean,
    hideSelected: Boolean,
    items: {
      type: Array,
      default: () => [],
    },
    itemColor: {
      type: String,
      default: 'primary',
    },
    itemDisabled: {
      type: [String, Array, Function],
      default: 'disabled',
    } as ItemProperty,
    itemText: {
      type: [String, Array, Function],
      default: 'text',
    } as ItemProperty,
    itemValue: {
      type: [String, Array, Function],
      default: 'value',
    } as ItemProperty,
    menuProps: {
      type: [String, Array, Object],
      default: () => defaultMenuProps,
    },
    multiple: Boolean,
    openOnClear: Boolean,
    returnObject: Boolean,
    smallChips: Boolean,
  },

  data () {
    return {
      cachedItems: this.cacheItems ? this.items : [],
      content: null as any,
      isBooted: false,
      isMenuActive: false,
      lastItem: 20,
      // As long as a value is defined, show it
      // Otherwise, check if multiple
      // to determine which default to provide
      lazyValue: this.value !== undefined
        ? this.value
        : this.multiple ? [] : undefined,
      selectedIndex: -1,
      selectedItems: [] as any[],
      keyboardLookupPrefix: '',
      keyboardLookupLastTime: 0,
    }
  },

  computed: {
    /* All items that the select has */
    allItems (): object[] {
      return this.filterDuplicates(this.cachedItems.concat(this.items))
    },
    classes (): object {
      return {
        ...VTextField.options.computed.classes.call(this),
        'v-select': true,
        'v-select--chips': this.hasChips,
        'v-select--chips--small': this.smallChips,
        'v-select--is-menu-active': this.isMenuActive,
      }
    },
    /* Used by other components to overwrite */
    computedItems (): object[] {
      return this.allItems
    },
    computedOwns (): string {
      return `list-${this._uid}`
    },
    counterValue (): number {
      return this.multiple
        ? this.selectedItems.length
        : (this.getText(this.selectedItems[0]) || '').toString().length
    },
    directives (): VNodeDirective[] | undefined {
      return this.isFocused ? [{
        name: 'click-outside',
        value: this.blur,
        args: {
          closeConditional: this.closeConditional,
        },
      } as VNodeDirective] : undefined
    },
    dynamicHeight () {
      return 'auto'
    },
    hasChips (): boolean {
      return this.chips || this.smallChips
    },
    hasSlot (): boolean {
      return Boolean(this.hasChips || this.$scopedSlots.selection)
    },
    isDirty (): boolean {
      return this.selectedItems.length > 0
    },
    listData (): object {
      const scopeId = this.$vnode && (this.$vnode.context!.$options as { [key: string]: any })._scopeId
      const attrs = scopeId ? {
        [scopeId]: true,
      } : {}

      return {
        attrs: {
          ...attrs,
          id: this.computedOwns,
        },
        props: {
          action: this.multiple,
          color: this.itemColor,
          dense: this.dense,
          hideSelected: this.hideSelected,
          items: this.virtualizedItems,
          noDataText: this.$vuetify.lang.t(this.noDataText),
          selectedItems: this.selectedItems,
          itemDisabled: this.itemDisabled,
          itemValue: this.itemValue,
          itemText: this.itemText,
        },
        on: {
          select: this.selectItem,
        },
        scopedSlots: {
          item: this.$scopedSlots.item,
        },
      }
    },
    staticList (): VNode {
      if (this.$slots['no-data'] || this.$slots['prepend-item'] || this.$slots['append-item']) {
        consoleError('assert: staticList should not be called if slots are used')
      }

      return this.$createElement(VSelectList, this.listData)
    },
    virtualizedItems (): object[] {
      return (this.$_menuProps as any).auto
        ? this.computedItems
        : this.computedItems.slice(0, this.lastItem)
    },
    menuCanShow: () => true,
    $_menuProps (): object {
      let normalisedProps = typeof this.menuProps === 'string'
        ? this.menuProps.split(',')
        : this.menuProps

      if (Array.isArray(normalisedProps)) {
        normalisedProps = normalisedProps.reduce((acc, p) => {
          acc[p.trim()] = true
          return acc
        }, {})
      }

      return {
        ...defaultMenuProps,
        eager: this.eager,
        value: this.menuCanShow && this.isMenuActive,
        nudgeBottom: normalisedProps.offsetY ? 1 : 0, // convert to int
        ...normalisedProps,
      }
    },
  },

  watch: {
    internalValue (val) {
      this.initialValue = val
      this.setSelectedItems()
    },
    isBooted () {
      this.$nextTick(() => {
        if (this.content && this.content.addEventListener) {
          this.content.addEventListener('scroll', this.onScroll, false)
        }
      })
    },
    isMenuActive (val) {
      this.$nextTick(() => this.onMenuActiveChange(val))

      if (!val) return

      this.isBooted = true
    },
    items: {
      immediate: true,
      handler (val) {
        if (this.cacheItems) {
          // Breaks vue-test-utils if
          // this isn't calculated
          // on the next tick
          this.$nextTick(() => {
            this.cachedItems = this.filterDuplicates(this.cachedItems.concat(val))
          })
        }

        this.setSelectedItems()
      },
    },
  },

  mounted () {
    this.content = this.$refs.menu && (this.$refs.menu as { [key: string]: any }).$refs.content
  },

  methods: {
    /** @public */
    blur (e?: Event) {
      VTextField.options.methods.blur.call(this, e)
      this.isMenuActive = false
      this.isFocused = false
      this.selectedIndex = -1
    },
    /** @public */
    activateMenu () {
      if (
        this.disabled ||
        this.readonly ||
        this.isMenuActive
      ) return

      this.isMenuActive = true
    },
    clearableCallback () {
      this.setValue(this.multiple ? [] : undefined)
      this.$nextTick(() => this.$refs.input && this.$refs.input.focus())

      if (this.openOnClear) this.isMenuActive = true
    },
    closeConditional (e: Event) {
      return (
        // Click originates from outside the menu content
        this.content &&
        !this.content.contains(e.target) &&

        // Click originates from outside the element
        this.$el &&
        !this.$el.contains(e.target as Node) &&
        e.target !== this.$el
      )
    },
    filterDuplicates (arr: any[]) {
      const uniqueValues = new Map()
      for (let index = 0; index < arr.length; ++index) {
        const item = arr[index]
        const val = this.getValue(item)

        // TODO: comparator
        !uniqueValues.has(val) && uniqueValues.set(val, item)
      }
      return Array.from(uniqueValues.values())
    },
    findExistingIndex (item: object) {
      const itemValue = this.getValue(item)

      return (this.internalValue || []).findIndex((i: object) => this.valueComparator(this.getValue(i), itemValue))
    },
    genChipSelection (item: object, index: number) {
      const isDisabled = (
        this.disabled ||
        this.readonly ||
        this.getDisabled(item)
      )

      return this.$createElement(VChip, {
        staticClass: 'v-chip--select',
        attrs: { tabindex: -1 },
        props: {
          close: this.deletableChips && !isDisabled,
          disabled: isDisabled,
          inputValue: index === this.selectedIndex,
          small: this.smallChips,
        },
        on: {
          click: (e: MouseEvent) => {
            if (isDisabled) return

            e.stopPropagation()

            this.selectedIndex = index
          },
          focus,
          'click:close': () => this.onChipInput(item),
        },
        key: JSON.stringify(this.getValue(item)),
      }, this.getText(item))
    },
    genCommaSelection (item: object, index: number, last: boolean) {
      const color = index === this.selectedIndex && this.color
      const isDisabled = (
        this.disabled ||
        this.getDisabled(item)
      )

      return this.$createElement('div', this.setTextColor(color, {
        staticClass: 'v-select__selection v-select__selection--comma',
        class: {
          'v-select__selection--disabled': isDisabled,
        },
        key: JSON.stringify(this.getValue(item)),
      }), `${this.getText(item)}${last ? '' : ', '}`)
    },
    genDefaultSlot (): (VNode | VNode[] | null)[] {
      const selections = this.genSelections()
      const input = this.genInput()

      // If the return is an empty array
      // push the input
      if (Array.isArray(selections)) {
        selections.push(input)
      // Otherwise push it into children
      } else {
        selections.children = selections.children || []
        selections.children.push(input)
      }

      return [
        this.genFieldset(),
        this.$createElement('div', {
          staticClass: 'v-select__slot',
          directives: this.directives,
        }, [
          this.genLabel(),
          this.prefix ? this.genAffix('prefix') : null,
          selections,
          this.suffix ? this.genAffix('suffix') : null,
          this.genClearIcon(),
          this.genIconSlot(),
        ]),
        this.genMenu(),
        this.genProgress(),
      ]
    },
    genInput (): VNode {
      const input = VTextField.options.methods.genInput.call(this)

      input.data!.domProps!.value = null
      input.data!.attrs!.readonly = true
      input.data!.attrs!.type = 'text'
      input.data!.attrs!['aria-readonly'] = true
      input.data!.on!.keypress = this.onKeyPress

      return input
    },
    genInputSlot (): VNode {
      const render = VTextField.options.methods.genInputSlot.call(this)

      render.data!.attrs = {
        ...render.data!.attrs,
        role: 'button',
        'aria-haspopup': 'listbox',
        'aria-expanded': String(this.isMenuActive),
        'aria-owns': this.computedOwns,
      }

      return render
    },
    genList (): VNode {
      // If there's no slots, we can use a cached VNode to improve performance
      if (this.$slots['no-data'] || this.$slots['prepend-item'] || this.$slots['append-item']) {
        return this.genListWithSlot()
      } else {
        return this.staticList
      }
    },
    genListWithSlot (): VNode {
      const slots = ['prepend-item', 'no-data', 'append-item']
        .filter(slotName => this.$slots[slotName])
        .map(slotName => this.$createElement('template', {
          slot: slotName,
        }, this.$slots[slotName]))
      // Requires destructuring due to Vue
      // modifying the `on` property when passed
      // as a referenced object
      return this.$createElement(VSelectList, {
        ...this.listData,
      }, slots)
    },
    genMenu (): VNode {
      const props = this.$_menuProps as any
      props.activator = this.$refs['input-slot']

      // Attach to root el so that
      // menu covers prepend/append icons
      if (
        // TODO: make this a computed property or helper or something
        this.attach === '' || // If used as a boolean prop (<v-menu attach>)
        this.attach === true || // If bound to a boolean (<v-menu :attach="true">)
        this.attach === 'attach' // If bound as boolean prop in pug (v-menu(attach))
      ) {
        props.attach = this.$el
      } else {
        props.attach = this.attach
      }

      return this.$createElement(VMenu, {
        attrs: { role: undefined },
        props,
        on: {
          input: (val: boolean) => {
            this.isMenuActive = val
            this.isFocused = val
          },
        },
        ref: 'menu',
      }, [this.genList()])
    },
    genSelections (): VNode {
      let length = this.selectedItems.length
      const children = new Array(length)

      let genSelection
      if (this.$scopedSlots.selection) {
        genSelection = this.genSlotSelection
      } else if (this.hasChips) {
        genSelection = this.genChipSelection
      } else {
        genSelection = this.genCommaSelection
      }

      while (length--) {
        children[length] = genSelection(
          this.selectedItems[length],
          length,
          length === children.length - 1
        )
      }

      return this.$createElement('div', {
        staticClass: 'v-select__selections',
      }, children)
    },
    genSlotSelection (item: object, index: number): VNode[] | undefined {
      return this.$scopedSlots.selection!({
        attrs: {
          class: 'v-chip--select',
        },
        parent: this,
        item,
        index,
        select: (e: Event) => {
          e.stopPropagation()
          this.selectedIndex = index
        },
        selected: index === this.selectedIndex,
        disabled: this.disabled || this.readonly,
      })
    },
    getMenuIndex () {
      return this.$refs.menu ? (this.$refs.menu as { [key: string]: any }).listIndex : -1
    },
    getDisabled (item: object) {
      return getPropertyFromItem(item, this.itemDisabled, false)
    },
    getText (item: object) {
      return getPropertyFromItem(item, this.itemText, item)
    },
    getValue (item: object) {
      return getPropertyFromItem(item, this.itemValue, this.getText(item))
    },
    onBlur (e?: Event) {
      e && this.$emit('blur', e)
    },
    onChipInput (item: object) {
      if (this.multiple) this.selectItem(item)
      else this.setValue(null)
      // If all items have been deleted,
      // open `v-menu`
      if (this.selectedItems.length === 0) {
        this.isMenuActive = true
      } else {
        this.isMenuActive = false
      }
      this.selectedIndex = -1
    },
    onClick () {
      if (this.isDisabled) return

      this.isMenuActive = true

      if (!this.isFocused) {
        this.isFocused = true
        this.$emit('focus')
      }
    },
    onEscDown (e: Event) {
      e.preventDefault()
      if (this.isMenuActive) {
        e.stopPropagation()
        this.isMenuActive = false
      }
    },
    onKeyPress (e: KeyboardEvent) {
      if (
        this.multiple ||
        this.readonly
      ) return

      const KEYBOARD_LOOKUP_THRESHOLD = 1000 // milliseconds
      const now = performance.now()
      if (now - this.keyboardLookupLastTime > KEYBOARD_LOOKUP_THRESHOLD) {
        this.keyboardLookupPrefix = ''
      }
      this.keyboardLookupPrefix += e.key.toLowerCase()
      this.keyboardLookupLastTime = now

      const index = this.allItems.findIndex(item => {
        const text = (this.getText(item) || '').toString()

        return text.toLowerCase().startsWith(this.keyboardLookupPrefix)
      })
      const item = this.allItems[index]
      if (index !== -1) {
        this.setValue(this.returnObject ? item : this.getValue(item))
        setTimeout(() => this.setMenuIndex(index))
      }
    },
    onKeyDown (e: KeyboardEvent) {
      const keyCode = e.keyCode
      const menu = this.$refs.menu

      // If enter, space, open menu
      if ([
        keyCodes.enter,
        keyCodes.space,
      ].includes(keyCode)) this.activateMenu()

      if (!menu) return

      // If menu is active, allow default
      // listIndex change from menu
      if (this.isMenuActive && keyCode !== keyCodes.tab) {
        menu.changeListIndex(e)
      }

      // If menu is not active, up and down can do
      // one of 2 things. If multiple, opens the
      // menu, if not, will cycle through all
      // available options
      if (
        !this.isMenuActive &&
        [keyCodes.up, keyCodes.down].includes(keyCode)
      ) return this.onUpDown(e)

      // If escape deactivate the menu
      if (keyCode === keyCodes.esc) return this.onEscDown(e)

      // If tab - select item or close menu
      if (keyCode === keyCodes.tab) return this.onTabDown(e)

      // If space preventDefault
      if (keyCode === keyCodes.space) return this.onSpaceDown(e)
    },
    onMenuActiveChange (val: boolean) {
      // If menu is closing and mulitple
      // or menuIndex is already set
      // skip menu index recalculation
      if (
        (this.multiple && !val) ||
        this.getMenuIndex() > -1
      ) return

      const menu = this.$refs.menu

      if (!menu || !this.isDirty) return

      // When menu opens, set index of first active item
      for (let i = 0; i < menu.tiles.length; i++) {
        if (menu.tiles[i].getAttribute('aria-selected') === 'true') {
          this.setMenuIndex(i)
          break
        }
      }
    },
    onMouseUp (e: MouseEvent) {
      if (this.hasMouseDown && e.which !== 3) {
        const appendInner = this.$refs['append-inner']

        // If append inner is present
        // and the target is itself
        // or inside, toggle menu
        if (this.isMenuActive &&
          appendInner &&
          (appendInner === e.target ||
          (appendInner as { [key: string]: any }).contains(e.target))
        ) {
          this.$nextTick(() => (this.isMenuActive = !this.isMenuActive))
        // If user is clicking in the container
        // and field is enclosed, activate it
        } else if (this.isEnclosed && !this.isDisabled) {
          this.isMenuActive = true
        }
      }

      VTextField.options.methods.onMouseUp.call(this, e)
    },
    onScroll () {
      if (!this.isMenuActive) {
        requestAnimationFrame(() => (this.content.scrollTop = 0))
      } else {
        if (this.lastItem >= this.computedItems.length) return

        const showMoreItems = (
          this.content.scrollHeight -
          (this.content.scrollTop +
          this.content.clientHeight)
        ) < 200

        if (showMoreItems) {
          this.lastItem += 20
        }
      }
    },
    onSpaceDown (e: KeyboardEvent) {
      e.preventDefault()
    },
    onTabDown (e: KeyboardEvent) {
      const menu = this.$refs.menu

      if (!menu) return

      const activeTile = menu.activeTile

      // An item that is selected by
      // menu-index should toggled
      if (
        !this.multiple &&
        activeTile &&
        this.isMenuActive
      ) {
        e.preventDefault()
        e.stopPropagation()

        activeTile.click()
      } else {
        // If we make it here,
        // the user has no selected indexes
        // and is probably tabbing out
        this.blur(e)
      }
    },
    onUpDown (e: KeyboardEvent) {
      const menu = this.$refs.menu

      if (!menu) return

      e.preventDefault()

      // Multiple selects do not cycle their value
      // when pressing up or down, instead activate
      // the menu
      if (this.multiple) return this.activateMenu()

      const keyCode = e.keyCode

      // Cycle through available values to achieve
      // select native behavior
      menu.getTiles()
      keyCodes.up === keyCode ? menu.prevTile() : menu.nextTile()
      menu.activeTile && menu.activeTile.click()
    },
    selectItem (item: object) {
      if (!this.multiple) {
        this.setValue(this.returnObject ? item : this.getValue(item))
        this.isMenuActive = false
      } else {
        const internalValue = (this.internalValue || []).slice()
        const i = this.findExistingIndex(item)

        i !== -1 ? internalValue.splice(i, 1) : internalValue.push(item)
        this.setValue(internalValue.map((i: object) => {
          return this.returnObject ? i : this.getValue(i)
        }))

        // When selecting multiple
        // adjust menu after each
        // selection
        this.$nextTick(() => {
          this.$refs.menu &&
            (this.$refs.menu as { [key: string]: any }).updateDimensions()
        })

        // We only need to reset list index for multiple
        // to keep highlight when an item is toggled
        // on and off
        if (!this.multiple) return

        const listIndex = this.getMenuIndex()

        this.setMenuIndex(-1)

        // There is no item to re-highlight
        // when selections are hidden
        if (this.hideSelected) return

        this.$nextTick(() => this.setMenuIndex(listIndex))
      }
    },
    setMenuIndex (index: number) {
      this.$refs.menu && ((this.$refs.menu as { [key: string]: any }).listIndex = index)
    },
    setSelectedItems () {
      const selectedItems = []
      const values = !this.multiple || !Array.isArray(this.internalValue)
        ? [this.internalValue]
        : this.internalValue

      for (const value of values) {
        const index = this.allItems.findIndex(v => this.valueComparator(
          this.getValue(v),
          this.getValue(value)
        ))

        if (index > -1) {
          selectedItems.push(this.allItems[index])
        }
      }

      this.selectedItems = selectedItems
    },
    setValue (value: any) {
      const oldValue = this.internalValue
      this.internalValue = value
      value !== oldValue && this.$emit('change', value)
    },
  },
})


import { createSimpleFunctional } from '../../util/helpers'
import VCard from './VCard'

const VCardActions = createSimpleFunctional('v-card__actions')
const VCardText = createSimpleFunctional('v-card__text')
const VCardTitle = createSimpleFunctional('v-card__title')

export { VCard, VCardTitle, VCardActions, VCardText }

export default {
  $_vuetify_subcomponents: {
    VCard,
    VCardTitle,
    VCardActions,
    VCardText,
  },
}


`v-footer`компонент используется для отображения общей информации, которую пользователь может захотеть получить с любой страницы вашего сайта.

Компонент footer как базовый footer компании со ссылками.

Компонент footer с цветом фона индиго и значками социальных сетей и кнопкой.

Компонент footer с заголовком цвета Teal и столбцами и строками ссылок.

Позиционирует смещение toolbar (панели инструментов) от приложения `v-navigation-drawer`


return this.isActive && this.reactsToClick

keep keep keep keep replace keep keep keep keep keep

return this.isActive && !this._isDestroyed && this.reactsToClick

import './VDialog.sass'

// Mixins
import Activatable from '../../mixins/activatable'
import Dependent from '../../mixins/dependent'
import Detachable from '../../mixins/detachable'
import Overlayable from '../../mixins/overlayable'
import Returnable from '../../mixins/returnable'
import Stackable from '../../mixins/stackable'
import Toggleable from '../../mixins/toggleable'

// Directives
import ClickOutside from '../../directives/click-outside'

// Helpers
import { convertToUnit, keyCodes } from '../../util/helpers'
import ThemeProvider from '../../util/ThemeProvider'
import mixins from '../../util/mixins'

// Types
import { VNode } from 'vue'

const baseMixins = mixins(
  Activatable,
  Dependent,
  Detachable,
  Overlayable,
  Returnable,
  Stackable,
  Toggleable
)

/* @vue/component */
export default baseMixins.extend({
  name: 'v-dialog',

  directives: {
    ClickOutside,
  },

  props: {
    dark: Boolean,
    disabled: Boolean,
    fullscreen: Boolean,
    fullWidth: Boolean,
    light: Boolean,
    maxWidth: {
      type: [String, Number],
      default: 'none',
    },
    noClickAnimation: Boolean,
    origin: {
      type: String,
      default: 'center center',
    },
    persistent: Boolean,
    retainFocus: {
      type: Boolean,
      default: true,
    },
    scrollable: Boolean,
    transition: {
      type: [String, Boolean],
      default: 'dialog-transition',
    },
    width: {
      type: [String, Number],
      default: 'auto',
    },
  },

  data () {
    return {
      activatedBy: null as EventTarget | null,
      animate: false,
      animateTimeout: -1,
      isActive: !!this.value,
      stackMinZIndex: 200,
    }
  },

  computed: {
    classes (): object {
      return {
        [(`v-dialog ${this.contentClass}`).trim()]: true,
        'v-dialog--active': this.isActive,
        'v-dialog--persistent': this.persistent,
        'v-dialog--fullscreen': this.fullscreen,
        'v-dialog--scrollable': this.scrollable,
        'v-dialog--animated': this.animate,
      }
    },
    contentClasses (): object {
      return {
        'v-dialog__content': true,
        'v-dialog__content--active': this.isActive,
      }
    },
    hasActivator (): boolean {
      return Boolean(
        !!this.$slots.activator ||
        !!this.$scopedSlots.activator
      )
    },
  },

  watch: {
    isActive (val) {
      if (val) {
        this.show()
        this.hideScroll()
      } else {
        this.removeOverlay()
        this.unbind()
      }
    },
    fullscreen (val) {
      if (!this.isActive) return

      if (val) {
        this.hideScroll()
        this.removeOverlay(false)
      } else {
        this.showScroll()
        this.genOverlay()
      }
    },
  },

  beforeMount () {
    this.$nextTick(() => {
      this.isBooted = this.isActive
      this.isActive && this.show()
    })
  },

  beforeDestroy () {
    if (typeof window !== 'undefined') this.unbind()
  },

  methods: {
    animateClick () {
      this.animate = false
      // Needed for when clicking very fast
      // outside of the dialog
      this.$nextTick(() => {
        this.animate = true
        window.clearTimeout(this.animateTimeout)
        this.animateTimeout = window.setTimeout(() => (this.animate = false), 150)
      })
    },
    closeConditional (e: Event) {
      const target = e.target as HTMLElement
      // If the dialog content contains
      // the click event, or if the
      // dialog is not active
      if (!this.isActive || this.$refs.content.contains(target)) return false

      // If we made it here, the click is outside
      // and is active. If persistent, and the
      // click is on the overlay, animate
      this.$emit('click:outside')

      if (this.persistent) {
        if (!this.noClickAnimation &&
          this.overlay === target
        ) this.animateClick()

        return false
      }

      // close dialog if !persistent, clicked outside and we're the topmost dialog.
      // Since this should only be called in a capture event (bottom up), we shouldn't need to stop propagation
      return this.activeZIndex >= this.getMaxZIndex()
    },
    hideScroll () {
      if (this.fullscreen) {
        document.documentElement.classList.add('overflow-y-hidden')
      } else {
        Overlayable.options.methods.hideScroll.call(this)
      }
    },
    show () {
      !this.fullscreen && !this.hideOverlay && this.genOverlay()
      this.$refs.content.focus()
      this.bind()
    },
    bind () {
      window.addEventListener('focusin', this.onFocusin)
    },
    unbind () {
      window.removeEventListener('focusin', this.onFocusin)
    },
    onKeydown (e: KeyboardEvent) {
      if (e.keyCode === keyCodes.esc && !this.getOpenDependents().length) {
        if (!this.persistent) {
          this.isActive = false
          const activator = this.getActivator()
          this.$nextTick(() => activator && (activator as HTMLElement).focus())
        } else if (!this.noClickAnimation) {
          this.animateClick()
        }
      }
      this.$emit('keydown', e)
    },
    onFocusin (e: Event) {
      if (!e || !this.retainFocus) return

      const target = e.target as HTMLElement

      if (
        !!target &&
        // It isn't the document or the dialog body
        ![document, this.$refs.content].includes(target) &&
        // It isn't inside the dialog body
        !this.$refs.content.contains(target) &&
        // We're the topmost dialog
        this.activeZIndex >= this.getMaxZIndex() &&
        // It isn't inside a dependent element (like a menu)
        !this.getOpenDependentElements().some(el => el.contains(target))
        // So we must have focused something outside the dialog and its children
      ) {
        // Find and focus the first available element inside the dialog
        const focusable = this.$refs.content.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])')
        focusable.length && (focusable[0] as HTMLElement).focus()
      }
    },
  },

  render (h): VNode {
    const children = []
    const data = {
      class: this.classes,
      ref: 'dialog',
      directives: [
        {
          name: 'click-outside',
          value: () => { this.isActive = false },
          args: {
            closeConditional: this.closeConditional,
            include: this.getOpenDependentElements,
          },
        },
        { name: 'show', value: this.isActive },
      ],
      on: {
        click: (e: Event) => { e.stopPropagation() },
      },
      style: {},
    }

    if (!this.fullscreen) {
      data.style = {
        maxWidth: this.maxWidth === 'none' ? undefined : convertToUnit(this.maxWidth),
        width: this.width === 'auto' ? undefined : convertToUnit(this.width),
      }
    }

    children.push(this.genActivator())

    let dialog = h('div', data, this.showLazyContent(this.getContentSlot()))
    if (this.transition) {
      dialog = h('transition', {
        props: {
          name: this.transition,
          origin: this.origin,
        },
      }, [dialog])
    }

    children.push(h('div', {
      class: this.contentClasses,
      attrs: {
        role: 'document',
        tabindex: 0,
        ...this.getScopeIdAttrs(),
      },
      on: {
        keydown: this.onKeydown,
      },
      style: { zIndex: this.activeZIndex },
      ref: 'content',
    }, [
      this.$createElement(ThemeProvider, {
        props: {
          root: true,
          light: this.light,
          dark: this.dark,
        },
      }, [dialog]),
    ]))

    return h('div', {
      staticClass: 'v-dialog__container',
      attrs: { role: 'dialog' },
      style: {
        display: (!this.hasActivator || this.fullWidth) ? 'block' : 'inline-block',
      },
    }, children)
  },
})


<template>
  <v-layout>
    <v-flex>
      <v-sheet height="400">
        <v-calendar
          ref="calendar"
          :now="today"
          :value="today"
          :events="events"
          color="primary"
          type="week"
        >

          <template v-slot:day-header="{ date }">
            <template v-for="event in eventsMap[date]">

            </template>
          </template>

          <template v-slot:day-body="{ date, timeToY, minutesToPixels }">
            <template v-for="event in eventsMap[date]">

            </template>
          </template>
        </v-calendar>
      </v-sheet>
    </v-flex>
  </v-layout>
</template>


if (this.openOnClear) this.isMenuActive = true

// Click originates from outside the menu content

keep keep keep keep add keep keep keep keep


<div class="pull-start margin-end avatar-container">

<img onerror="this.onerror=null;this.className='avatar hide'" data-ls-attrs="src={{env.API}}/avatars/browsers/{{session.clientCode|lowercase}}?width=60&height=60&project={{env.PROJECT}},title={{session.clientName}},alt={{session.clientName}}" class="avatar" loading="lazy" width="60" height="60" />

<div data-ls-if="{{session.provider}} !== 'email'" class="corner">

keep keep keep keep replace replace keep keep keep keep

<img onerror="this.onerror=null;this.className='avatar hide'" data-ls-attrs="src={{env.API}}/avatars/browsers/{{session.clientCode|lowercase}}?width=120&height=120&project={{env.PROJECT}},title={{session.clientName}},alt={{session.clientName}}" class="avatar" loading="lazy" width="60" height="60" data-ls-if="{{session.clientCode|lowercase}} !== 'cli'"/>

<img onerror="this.onerror=null;this.className='avatar hide'" data-ls-attrs="src=/images/clients/terminal.png?buster=<?php echo APP_CACHE_BUSTER; ?>,title={{session.clientName}},alt={{session.clientName}}" class="avatar" loading="lazy" width="60" height="60" data-ls-if="{{session.clientCode|lowercase}} === 'cli'" >

         Home

        Your Account

Overview

                                <form name="account.update"
                                    data-analytics
                                    data-analytics-activity
                                    data-analytics-event="submit"
                                    data-analytics-category="console"
                                    data-analytics-label="Update Account Name"
                                    data-service="account.updateName"
                                    data-scope="console"
                                    data-event="submit"
                                    data-success="trigger,alert"
                                    data-success-param-alert-text="Your name was updated successfully"
                                    data-success-param-trigger-events="account.update"
                                    data-failure="alert"
                                    data-failure-param-alert-text="Failed to update your name"
                                    data-failure-param-alert-classname="error">

                                    Name

                                            <input name="name" id="name" type="text" autocomplete="off" data-ls-bind="{{account.name}}" required class="margin-bottom-no" maxlength="128">

                                            <button type="submit" class="fill margin-bottom-no">Update Name</button>

                                </form>

                            <form name="update-email"
                                data-analytics
                                data-analytics-activity
                                data-analytics-event="submit"
                                data-analytics-category="console"
                                data-analytics-label="Update Account Email"
                                data-service="account.updateEmail"
                                data-scope="console"
                                data-event="submit"
                                data-success="trigger,alert"
                                data-success-param-alert-text="Email address updated successfully"
                                data-success-param-trigger-events="account-update,modal-close"
                                data-failure="alert"
                                data-failure-param-alert-text="Failed updating email address"
                                data-failure-param-alert-classname="error">

                                Email

                                        <input name="email" type="email" class="margin-bottom-no" autocomplete="off" placeholder="me@example.com" data-ls-bind="{{account.email}}" required>

Confirm Password

                                            Password
                                            <input name="password" type="password" class="full-width" autocomplete="off" placeholder="" required>

                                            <button type="submit" class="margin-bottom-no">Update</button>   <button data-ui-modal-close="" type="button" class="reverse">Cancel</button>

                            </form>

Update Password

                                <form name="update-password"
                                    data-analytics
                                    data-analytics-activity
                                    data-analytics-event="submit"
                                    data-analytics-category="console"
                                    data-analytics-label="Update Account Password"
                                    data-service="account.updatePassword"
                                    data-scope="console"
                                    data-event="submit"
                                    data-success="trigger,alert,reset"
                                    data-success-param-trigger-events="account-update"
                                    data-success-param-alert-text="Password updated successfully"
                                    data-failure="alert"
                                    data-failure-param-alert-text="Failed updating password"
                                    data-failure-param-alert-classname="error">

                                    Current Password
                                    <input name="oldPassword" type="password" class="full-width" autocomplete="off" placeholder="" required>

                                    New Password
                                    <input name="password" type="password" class="full-width" autocomplete="off" placeholder="" required data-forms-password-meter>

                                        <button type="submit">Update Password</button>   <button data-ui-modal-close="" type="button" class="reverse">Cancel</button>

                                </form>

                            <form class="margin-top"
                                data-analytics
                                data-analytics-activity
                                data-analytics-event="submit"
                                data-analytics-category="console"
                                data-analytics-label="Delete Account Current Session"
                                data-service="account.deleteSession"
                                data-scope="console"
                                data-event="submit"
                                data-success="trigger"
                                data-success-param-trigger-events="account.deleteSession"
                                data-failure="alert"
                                data-failure-param-alert-text="Logout failed"
                                data-failure-param-alert-classname="error">

                                <input type="hidden" name="sessionId" value="current">

                                <button class="fill danger icon fill"> Logout</button>
                            </form>

Danger Zone

This is the area where you can delete your account.

By deleting your account you will lose access to any of your teams and shared data.

PLEASE NOTE: Account deletion is irreversible.

                            <form class="inline"
                                data-analytics
                                data-analytics-activity
                                data-analytics-event="submit"
                                data-analytics-category="console"
                                data-analytics-label="Delete Account"
                                data-service="account.delete"
                                data-scope="console"
                                data-event="submit"
                                data-confirm="Are you sure you want to delete your account?"
                                data-success="trigger"
                                data-success-param-trigger-events="account.delete"
                                data-failure="alert"
                                data-failure-param-alert-text="Account deactivation failed"
                                data-failure-param-alert-classname="error">
                                <button class="danger reverse">Delete Account</button>
                            </form>

Sessions

                            <form class="pull-end"
                                data-analytics
                                data-analytics-activity
                                data-analytics-event="submit"
                                data-analytics-category="console"
                                data-analytics-label="Delete Account Session"
                                data-service="account.deleteSession"
                                data-scope="console"
                                data-event="submit"
                                data-loading="Loading..."
                                data-success="trigger"
                                data-success-param-trigger-events="account.deleteRemoteSession"
                                data-failure="alert"
                                data-failure-param-alert-text="Logout from Session Failed"
                                data-failure-param-alert-classname="error">

                                <input type="hidden" name="sessionId" data-ls-bind="{{session.$id}}">
                                <button class="danger">Logout</button>
                            </form>

                            <form class="pull-end"
                                data-analytics
                                data-analytics-activity
                                data-analytics-event="submit"
                                data-analytics-category="console"
                                data-analytics-label="Delete Account Current Session"
                                data-service="account.deleteSession"
                                data-scope="console"
                                data-event="submit"
                                data-loading="Loading..."
                                data-success="trigger,redirect"
                                data-success-param-trigger-events="account.deleteSession"
                                data-success-param-redirect-url="/"
                                data-failure="alert"
                                data-failure-param-alert-text="Logout from Session Failed"
                                data-failure-param-alert-classname="error">
                                <input type="hidden" name="sessionId" data-ls-bind="{{session.$id}}">
                                <button class="danger">Logout</button>
                            </form>

                                <img data-ls-attrs="src=/images/users/{{session.provider}}.png?buster=<?php echo APP_CACHE_BUSTER; ?>,title={{session.provider}},alt={{session.provider}}"  class="avatar xs" loading="lazy" width="30" height="30" />

                        Unknown
                          on

                            Current Session

                             /

            <form class="inline margin-bottom-large"
                data-analytics
                data-analytics-activity
                data-analytics-event="submit"
                data-analytics-category="console"
                data-analytics-label="Delete Account Sessions"
                data-service="account.deleteSessions"
                data-scope="console"
                data-event="submit"
                data-success="trigger,redirect"
                data-success-param-trigger-events="account.deleteSession"
                data-success-param-redirect-url="/"
                data-failure="alert"
                data-failure-param-alert-text="Logout from All Sessions Failed"
                data-failure-param-alert-classname="error">
                <input type="hidden" name="id" value="0">
                <button class="danger">Logout from all sessions</button>
            </form>

Activity

                                Date
                                Event
                                Client
                                Location
                                IP

                                    Unknown

                    <form
                        data-service="account.getLogs"
                        data-event="submit"
                        data-param-limit="<?php echo APP_PAGING_LIMIT; ?>"
                        data-param-offset="{{router.params.offset}}"
                        data-scope="console"
                        data-name="securityLogs"
                        data-success="state"
                        data-success-param-state-keys="offset">
                        <button name="offset" data-paging-back data-offset="{{router.params.offset}}" data-sum="{{securityLogs.sum}}" class="margin-end round small" aria-label="Back"></button>
                    </form>

                    <form
                        data-service="account.getLogs"
                        data-event="submit"
                        data-param-limit="<?php echo APP_PAGING_LIMIT; ?>"
                        data-param-offset="{{router.params.offset}}"
                        data-scope="console"
                        data-name="securityLogs"
                        data-success="state"
                        data-success-param-state-keys="offset">
                        <button name="offset" data-paging-next data-offset="{{router.params.offset}}" data-sum="{{securityLogs.sum}}" class="margin-start round small" aria-label="Next"></button>
                    </form>


import 'package:appwrite/appwrite.dart';

void main() { // Init SDK
  Client client = Client();
  Account account = Account(client);

  client
    .setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
    .setProject('5df5acd0d48c2') // Your project ID
  ;
  Future result = account.getPrefs();

  result
    .then((response) {
      print(response);
    }).catchError((error) {
      print(error.response);
  });
}


const sdk = new Appwrite();

sdk
    .setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
    .setProject('5df5acd0d48c2') // Your project ID
;

let promise = sdk.users.updateName('[USER_ID]', '[NAME]');

promise.then(function (response) {
    console.log(response); // Success
}, function (error) {
    console.log(error); // Failure
});


let sdk = new Appwrite();

sdk
    .setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
    .setProject('5df5acd0d48c2') // Your project ID
;

let promise = sdk.functions.create('[NAME]', [], 'dotnet-3.1');

promise.then(function (response) {
    console.log(response); // Success
}, function (error) {
    console.log(error); // Failure
});


<img onerror="this.onerror=null;this.className='avatar hide'" data-ls-attrs="src={{env.API}}/avatars/browsers/{{log.clientCode|lowercase}}?width=80&height=80&project={{env.PROJECT}},title={{log.clientName}},alt={{log.clientName}}" class="avatar xxs inline margin-end-small" />

<img onerror="this.onerror=null;this.className='avatar xxs hide'" data-ls-attrs="src={{env.API}}/avatars/flags/{{log.countryCode}}?width=80&height=80&project={{env.PROJECT}}" class="avatar xxs inline margin-end-small" />

<img onerror="this.onerror=null;this.className='avatar hide'" data-ls-attrs="src={{env.API}}/avatars/browsers/{{log.clientCode|lowercase}}?width=80&height=80&project={{env.PROJECT}},title={{log.clientName}},alt={{log.clientName}}" class="avatar xxs inline margin-end-small" data-ls-if="{{log.clientCode|lowercase}} !== 'cli'"/>

<img onerror="this.onerror=null;this.className='avatar hide'" data-ls-attrs="src=/images/clients/terminal.png?buster=<?php echo APP_CACHE_BUSTER; ?>,title={{log.clientName}},alt={{log.clientName}}" class="avatar xxs inline margin-end-small" data-ls-if="{{log.clientCode|lowercase}} === 'cli'" />


import Appwrite

func main() {
    let client = Client()
      .setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
      .setProject("5df5acd0d48c2") // Your project ID

    let account = Account(client)
    account.updateVerification(
        userId: "[USER_ID]",
        secret: "[SECRET]"
    ) { result in
        switch result {
        case .failure(let error):
            print(error.message)
        case .success(let token):
            print(String(describing: token)
        }
    }
}


import * as sdk from "https://deno.land/x/appwrite/mod.ts";

// Init SDK
let client = new sdk.Client();

let teams = new sdk.Teams(client);

client
    .setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
    .setProject('5df5acd0d48c2') // Your project ID
    .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key
;

let promise = teams.get('[TEAM_ID]');

promise.then(function (response) {
    console.log(response);
}, function (error) {
    console.log(error);
});


let sdk = new Appwrite();

sdk
    .setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
    .setProject('5df5acd0d48c2') // Your project ID
    .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key
;

let result = sdk.avatars.getImage('https://example.com');

console.log(result); // Resource URL


<img onerror="this.onerror=null;this.className='avatar hide'" data-ls-if="{{log.clientCode|lowercase}} !== 'cli'" data-ls-attrs="src={{env.API}}/avatars/browsers/{{log.clientCode|lowercase}}?width=80&height=80&project={{env.PROJECT}},title={{log.clientName}},alt={{log.clientName}}" class="avatar xxs inline margin-end-small" />

keep keep keep keep keep replace keep keep keep keep

<img onerror="this.onerror=null;this.className='avatar hide'" data-ls-if="{{log.clientCode|lowercase}} === 'cli'" data-ls-attrs="src=/images/clients/terminal.png?buster=<?php echo APP_CACHE_BUSTER; ?>,title={{log.clientName}},alt={{log.clientName}}" class="avatar xxs inline margin-end-small" />

             Users

            Unknown
            Anonymous User

        <button type="button" class="close pull-end" data-ui-modal-close=""></button>

Update name

        <form name="users.updateName"
            data-analytics
            data-analytics-activity
            data-analytics-event="submit"
            data-analytics-category="console"
            data-analytics-label="Update User Name"
            data-service="users.updateName"
            data-scope="sdk"
            data-event="submit"
            data-success="trigger,alert"
            data-success-param-alert-text="User name was updated successfully"
            data-success-param-trigger-events="users.update"
            data-failure="alert"
            data-failure-param-alert-text="Failed to update user name"
            data-failure-param-alert-classname="error">

            <input type="hidden" disabled name="userId" data-ls-bind="{{user.$id}}">

            Name
            <input name="name" id="name" type="text" autocomplete="off" data-ls-bind="{{user.name}}" required class="full-width" maxlength="128">

                <button type="submit" class="">Update</button>   <button data-ui-modal-close="" type="button" class="reverse">Cancel</button>

        </form>

        <button type="button" class="close pull-end" data-ui-modal-close=""></button>

Update Email

        <form name="users.updateEmail"
            data-analytics
            data-analytics-activity
            data-analytics-event="submit"
            data-analytics-category="console"
            data-analytics-label="Update User Email"
            data-service="users.updateEmail"
            data-scope="sdk"
            data-event="submit"
            data-success="trigger,alert"
            data-success-param-alert-text="User email was updated successfully"
            data-success-param-trigger-events="users.update"
            data-failure="alert"
            data-failure-param-alert-text="Failed to update user email"
            data-failure-param-alert-classname="error">

            <input type="hidden" disabled name="userId" data-ls-bind="{{user.$id}}">

            Email
            <input name="email" id="email" type="text" autocomplete="off" data-ls-bind="{{user.email}}" required class="full-width" maxlength="128">

                <button type="submit" class="">Update</button>   <button data-ui-modal-close="" type="button" class="reverse">Cancel</button>

        </form>

        <button type="button" class="close pull-end" data-ui-modal-close=""></button>

Update Password

        <form name="users.updatePassword"
            data-analytics
            data-analytics-activity
            data-analytics-event="submit"
            data-analytics-category="console"
            data-analytics-label="Update User Password"
            data-service="users.updatePassword"
            data-scope="sdk"
            data-event="submit"
            data-success="trigger,alert"
            data-success-param-alert-text="User password was updated successfully"
            data-success-param-trigger-events="users.update"
            data-failure="alert"
            data-failure-param-alert-text="Failed to update user password"
            data-failure-param-alert-classname="error">

            <input type="hidden" disabled name="userId" data-ls-bind="{{user.$id}}">

            Password
            <input name="password" id="password" type="password" autocomplete="off" required class="full-width" maxlength="128">

                <button type="submit" class="">Update</button>   <button data-ui-modal-close="" type="button" class="reverse">Cancel</button>

        </form>

        <button type="button" class="close pull-end" data-ui-modal-close=""></button>

JSON View

            <input type="hidden" data-ls-bind="{{user}}" data-forms-code />

        <button data-ui-modal-close="" type="button" class="reverse">Cancel</button>

Overview

                    This user account is blocked.

                                        Verified

                                        Unverified

Preferences

                                            Key
                                            Value

                                No user preferences found

Danger Zone

This is the area where you can delete this user.

By deleting this user you will lose all data associated with this user.

PLEASE NOTE: User deletion is irreversible.

                            <form class="inline"
                                data-analytics
                                data-analytics-activity
                                data-analytics-event="submit"
                                data-analytics-category="console"
                                data-analytics-label="Delete User"
                                data-service="users.delete"
                                data-event="submit"
                                data-param-user-id="{{router.params.id}}"
                                data-success="alert,trigger,redirect"
                                data-confirm="Are you sure you want to delete this user?"
                                data-success-param-alert-text="Deleted user successfully"
                                data-success-param-trigger-events="users.delete"
                                data-success-param-redirect-url="/console/users?project={{router.params.project}}"
                                data-failure="alert"
                                data-failure-param-alert-text="Failed to delete user"
                                data-failure-param-alert-classname="error">
                                <input type="hidden" name="projectId" data-ls-bind="{{router.params.project}}" />

                                <button class="danger reverse" type="submit">Delete User</button>
                            </form>

                        User ID

                            <input id="uid" type="text" autocomplete="off" placeholder="" data-ls-bind="{{user.$id}}" disabled data-forms-copy>

 <button data-ls-ui-trigger="open-update-name" class="link text-size-small">Update name</button>

 <button data-ls-ui-trigger="open-update-email" class="link text-size-small">Update Email</button>

 <button data-ls-ui-trigger="open-update-password" class="link text-size-small">Update Password</button>

 <button data-ls-ui-trigger="open-json" class="link text-size-small">View as JSON</button>

                            <form name="users.updateStatus" class="margin-bottom"
                                data-analytics
                                data-analytics-activity
                                data-analytics-event="submit"
                                data-analytics-category="console"
                                data-analytics-label="Update User Status"
                                data-service="users.updateStatus"
                                data-event="submit"
                                data-param-user-id="{{router.params.id}}"
                                data-success="alert,trigger"
                                data-success-param-alert-text="Blocked user successfully"
                                data-success-param-trigger-events="users.update"
                                data-failure="alert"
                                data-failure-param-alert-text="Failed to block user"
                                data-failure-param-alert-classname="error">

                                <button name="status" type="submit" class="danger fill" value="false" data-cast-to="boolean">Block Account</button>
                            </form>

                            <form name="users.updateStatus" class="margin-bottom"
                                data-analytics
                                data-analytics-activity
                                data-analytics-event="submit"
                                data-analytics-category="console"
                                data-analytics-label="Update User Status"
                                data-service="users.updateStatus"
                                data-event="submit"
                                data-param-user-id="{{router.params.id}}"
                                data-success="alert,trigger"
                                data-success-param-alert-text="Activated user successfully"
                                data-success-param-trigger-events="users.update"
                                data-failure="alert"
                                data-failure-param-alert-text="Failed to activate user"
                                data-failure-param-alert-classname="error">

                                <button name="status" type="submit" class="fill" value="true" data-cast-to="boolean">Activate Account</button>
                            </form>

Sessions

                        No sessions available.

                                    <form class="pull-end"
                                        data-analytics
                                        data-analytics-activity
                                        data-analytics-event="submit"
                                        data-analytics-category="console"
                                        data-analytics-label="Delete User Session"
                                        data-service="users.deleteSession"
                                        data-event="submit"
                                        data-loading="Loading..."
                                        data-success="trigger"
                                        data-success-param-trigger-events="users.update"
                                        data-failure="alert"
                                        data-failure-param-alert-text="Failed to logout session"
                                        data-failure-param-alert-classname="error">

                                        <input type="hidden" name="userId" data-ls-bind="{{router.params.id}}">
                                        <input type="hidden" name="sessionId" data-ls-bind="{{session.$id}}">
                                        <button class="danger">Logout</button>
                                    </form>

                                        <img onerror="this.onerror=null;this.className='avatar hide'" data-ls-if="{{session.clientCode|lowercase}} === 'cli'" data-ls-attrs="src=/images/clients/terminal.png?buster=<?php echo APP_CACHE_BUSTER; ?>,title={{session.clientName}},alt={{session.clientName}}" class="avatar" loading="lazy" width="60" height="60" />

                                            <img data-ls-attrs="src=/images/users/{{session.provider}}.png?buster=<?php echo APP_CACHE_BUSTER; ?>,title={{session.provider}},alt={{session.provider}}"  class="avatar xs" loading="lazy" width="30" height="30" />

                                      on

                                         /

                        <form class="inline margin-bottom-large"
                            data-analytics
                            data-analytics-activity
                            data-analytics-event="submit"
                            data-analytics-category="console"
                            data-analytics-label="Delete User Sessions"
                            data-service="users.deleteSessions"
                            data-param-user-id="{{router.params.id}}"
                            data-event="submit"
                            data-success="trigger"
                            data-success-param-trigger-events="users.update"
                            data-failure="alert"
                            data-failure-param-alert-text="Failed to logout all sessions"
                            data-failure-param-alert-classname="error">

                            <button class="danger">Logout from all sessions</button>
                        </form>

Activity

                        No logs available.

                                    Date
                                    Event
                                    Client
                                    Location
                                    IP

                                        <img onerror="this.onerror=null;this.className='avatar hide'" data-ls-if="{{log.clientCode|lowercase}} === 'cli'" data-ls-attrs="src=/images/clients/terminal.png?buster=<?php echo APP_CACHE_BUSTER; ?>,,title={{log.clientName}},alt={{log.clientName}}" class="avatar xxs inline margin-end-small" />

Unknown


const sdk = new Appwrite();

sdk
    .setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
    .setProject('5df5acd0d48c2') // Your project ID
;

let promise = sdk.functions.delete('[FUNCTION_ID]');

promise.then(function (response) {
    console.log(response); // Success
}, function (error) {
    console.log(error); // Failure
});


<?php

use Appwrite\Client;
use Appwrite\Services\Database;

$client = new Client();

$client
    ->setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
    ->setProject('5df5acd0d48c2') // Your project ID
    ->setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key
;

$database = new Database($client);

$result = $database->updateCollection('[COLLECTION_ID]', '[NAME]');


const sdk = require('node-appwrite');

// Init SDK
let client = new sdk.Client();

let users = new sdk.Users(client);

client
    .setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
    .setProject('5df5acd0d48c2') // Your project ID
    .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key
;

let promise = users.updateStatus('[USER_ID]', 1);

promise.then(function (response) {
    console.log(response);
}, function (error) {
    console.log(error);
});