<commit_before>/**
 * @file
 *
 * @brief dialog to modify metadata of keys
 *
 * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
 */

import React, { Component } from 'react'

import FlatButton from 'material-ui/FlatButton'
import TextField from 'material-ui/TextField'
import SelectField from 'material-ui/SelectField'
import MenuItem from 'material-ui/MenuItem'
import Checkbox from 'material-ui/Checkbox'
import FocusTrapDialog from './FocusTrapDialog.jsx'

import SavedIcon from '../SavedIcon.jsx'
import EnumSubDialog from './EnumSubDialog.jsx'
import NumberSubDialog from './NumberSubDialog.jsx'
import AdditionalMetakeysSubDialog from './AdditionalMetakeysSubDialog.jsx'

import debounce from '../../debounce'
import { VISIBILITY_LEVELS, visibility, toElektraBool, fromElektraBool, isNumberType } from '../../../utils'
import { KEY_TYPES } from './utils'
import { validateRange } from '../fields/validateType'

const DebouncedTextField = debounce(TextField)

const IMMEDIATE = 'IMMEDIATE'
const DEBOUNCED = 'DEBOUNCED'

export default class SettingsDialog extends Component {
  constructor (...args) {
    super(...args)
    this.state = { regexError: false, rangeError: false, regexStr: false, rangeStr: false, paused: false }
  }

  componentWillReceiveProps (nextProps) {
    const { regexError, rangeError, regexStr, rangeStr } = this.state
    if (regexError) {
      this.handleEdit('check/validation', IMMEDIATE)(regexStr)
      setTimeout(() => this.handleEdit('check/validation', DEBOUNCED)(regexStr), 500)
    }
    if (rangeError) {
      this.handleEdit('check/range', IMMEDIATE)(rangeStr)
      setTimeout(() => this.handleEdit('check/range', DEBOUNCED)(rangeStr), 500)
    }
  }

  ensureRegex = (regexStr, data) => {
    if (regexStr) {
      // ensure key value matches regex
      let validationRegex
      try {
        validationRegex = new RegExp(regexStr)
      } catch (e) {}
      if (!validationRegex) {
        return this.setState({ regexError: 'invalid regex code', regexStr })
      } else if (!validationRegex.test(data)) {
        return this.setState({ regexError: 'current value does not match regex', regexStr })
      }
    }
    this.setState({ regexError: false, regexStr: false })
  }

  ensureRange = (rangeStr, data) => {
    if (rangeStr) {
      const err = validateRange(rangeStr, data)
      if (err) {
        return this.setState({ rangeError: err, rangeStr })
      }
    }
    this.setState({ rangeError: false, rangeStr: false })
  }

  handleEdit = (key, debounced = false) => (value) => {
    const { data, setMeta, deleteMeta } = this.props

    if (!debounced || debounced === IMMEDIATE) {
      // set value of field
      this.setState({ [key]: { ...this.state[key], value } })

      if (key === 'check/validation') {
        this.ensureRegex(value, data)
      }

      if (key === 'check/range') {
        this.ensureRange(value, data)
      }
    }

    if (!debounced || debounced === DEBOUNCED) {
      if (key === 'check/validation' && this.state.regexError) {
        return // do not save regex that does not match
      }
      if (key === 'check/range' && this.state.rangeError) {
        return // do not save range that does not match
      }
      // persist value to kdb and show notification
      const { timeout } = this.state[key] || {}

      // remove metakey when setting to 0
      const action = (key.startsWith('restrict/') && value === '0')
        ? deleteMeta
        : setMeta
      action(key, value)
        .then(() => {
          if (timeout) clearTimeout(timeout)
          this.setState({ [key]: {
            ...this.state[key],
            saved: true,
            timeout: setTimeout(() => {
              this.setState({ [key]: { ...this.state[key], saved: false } })
            }, 1500),
          } })
        })
    }
  }

  handleBinary = (e, val) => {
    if (val) { // convert to binary
      const text = 'Converting a normal key to a binary key in Elektra Web ' +<commit_msg>remove certain metakeys when set to 0, empty value or default value<commit_after>/**
 * @file
 *
 * @brief dialog to modify metadata of keys
 *
 * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
 */

import React, { Component } from 'react'

import FlatButton from 'material-ui/FlatButton'
import TextField from 'material-ui/TextField'
import SelectField from 'material-ui/SelectField'
import MenuItem from 'material-ui/MenuItem'
import Checkbox from 'material-ui/Checkbox'
import FocusTrapDialog from './FocusTrapDialog.jsx'

import SavedIcon from '../SavedIcon.jsx'
import EnumSubDialog from './EnumSubDialog.jsx'
import NumberSubDialog from './NumberSubDialog.jsx'
import AdditionalMetakeysSubDialog from './AdditionalMetakeysSubDialog.jsx'

import debounce from '../../debounce'
import { VISIBILITY_LEVELS, visibility, toElektraBool, fromElektraBool, isNumberType } from '../../../utils'
import { KEY_TYPES } from './utils'
import { validateRange } from '../fields/validateType'

const DebouncedTextField = debounce(TextField)

const IMMEDIATE = 'IMMEDIATE'
const DEBOUNCED = 'DEBOUNCED'

export default class SettingsDialog extends Component {
  constructor (...args) {
    super(...args)
    this.state = { regexError: false, rangeError: false, regexStr: false, rangeStr: false, paused: false }
  }

  componentWillReceiveProps (nextProps) {
    const { regexError, rangeError, regexStr, rangeStr } = this.state
    if (regexError) {
      this.handleEdit('check/validation', IMMEDIATE)(regexStr)
      setTimeout(() => this.handleEdit('check/validation', DEBOUNCED)(regexStr), 500)
    }
    if (rangeError) {
      this.handleEdit('check/range', IMMEDIATE)(rangeStr)
      setTimeout(() => this.handleEdit('check/range', DEBOUNCED)(rangeStr), 500)
    }
  }

  ensureRegex = (regexStr, data) => {
    if (regexStr) {
      // ensure key value matches regex
      let validationRegex
      try {
        validationRegex = new RegExp(regexStr)
      } catch (e) {}
      if (!validationRegex) {
        return this.setState({ regexError: 'invalid regex code', regexStr })
      } else if (!validationRegex.test(data)) {
        return this.setState({ regexError: 'current value does not match regex', regexStr })
      }
    }
    this.setState({ regexError: false, regexStr: false })
  }

  ensureRange = (rangeStr, data) => {
    if (rangeStr) {
      const err = validateRange(rangeStr, data)
      if (err) {
        return this.setState({ rangeError: err, rangeStr })
      }
    }
    this.setState({ rangeError: false, rangeStr: false })
  }

  handleEdit = (key, debounced = false) => (value) => {
    const { data, setMeta, deleteMeta } = this.props

    if (!debounced || debounced === IMMEDIATE) {
      // set value of field
      this.setState({ [key]: { ...this.state[key], value } })

      if (key === 'check/validation') {
        this.ensureRegex(value, data)
      }

      if (key === 'check/range') {
        this.ensureRange(value, data)
      }
    }

    if (!debounced || debounced === DEBOUNCED) {
      if (key === 'check/validation' && this.state.regexError) {
        return // do not save regex that does not match
      }
      if (key === 'check/range' && this.state.rangeError) {
        return // do not save range that does not match
      }
      // persist value to kdb and show notification
      const { timeout } = this.state[key] || {}

      let action = setMeta

      // remove metakeys when setting to 0 or empty
      if (key.startsWith('restrict/')) {
        if (value === '0' || value.trim() === '') {
          action = deleteMeta
        }
      }

      // remove metakeys when setting to default value
      if (key === 'check/type' && value === 'any') {
        action = deleteMeta
      }
      if (key === 'visibility' && value === 'user') {
        action = deleteMeta
      }

      action(key, value)
        .then(() => {
          if (timeout) clearTimeout(timeout)
          this.setState({ [key]: {
            ...this.state[key],
            saved: true,
            timeout: setTimeout(() => {
              this.setState({ [key]: { ...this.state[key], saved: false } })
            }, 1500),
          } })
        })
    }
  }

  handleBinary = (e, val) => {
    if (val) { // convert to binary
      const text = 'Converting a normal key to a binary key in Elektra Web ' +
{'fraction_non_alphanumeric': 0.13625507523286362, 'fraction_numerical': 0.0029854310962502987, 'mean_word_length': 2.702475685234306, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 21, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6001637', 'n_tokens_mistral': 2513, 'n_tokens_neox': 2491, 'n_words': 688}