<commit_before>import React from 'react'
import schema from 'part:@sanity/base/schema?'
import client from 'part:@sanity/base/client?'
import Preview from 'part:@sanity/base/preview?'
import Multicast from '@sanity/observable/multicast'
import {IntentLink} from 'part:@sanity/base/router'
import {union, flatten} from 'lodash'
import SearchIcon from 'part:@sanity/base/search-icon'
import Spinner from 'part:@sanity/components/loading/spinner'
import enhanceClickOutside from 'react-click-outside'
import Ink from 'react-ink'

function isParentOf(possibleParent, possibleChild) {
  let current = possibleChild
  while (current) {
    if (current === possibleParent) {
      return true
    }
    current = current.parentNode
  }
  return false
}

import styles from './styles/Search.css'

export const DRAFTS_FOLDER = 'drafts'
const DRAFTS_PREFIX = `${DRAFTS_FOLDER}.`

function isDraftId(id) {
  return id.startsWith(DRAFTS_PREFIX)
}

function getPublishedId(id) {
  return isDraftId(id) ? id.slice(DRAFTS_PREFIX.length) : id
}

function getDraftId(id) {
  return isDraftId(id) ? id : DRAFTS_PREFIX + id
}

// Removes published documents that also has a draft
function removeDupes(documents) {
  const drafts = documents.map(doc => doc._id).filter(isDraftId)

  return documents
    .filter(doc => {
      const draftId = getDraftId(doc._id)
      const publishedId = getPublishedId(doc._id)
      const hasDraft = drafts.includes(draftId)
      const isPublished = doc._id === publishedId
      return isPublished ? !hasDraft : true
    })
}

function search(query) {
  if (!client) {
    throw new Error('Sanity client is missing')
  }

  // Get all fields that we want to search in (text and string)
  const searchableFields = flatten(
    schema.getTypeNames()
      .filter(typeName => !typeName.startsWith('sanity.'))
      .map(typeName => schema.get(typeName))
      .filter(type => type.type && type.type.name === 'object')
      .map(type => type.fields
        .filter(field => field.type.jsonType === 'string')
        .map(field => field.name))
  )

  const terms = query.split(/\s+/).filter(Boolean)
  const uniqueFields = union(searchableFields)
  const constraints = terms.map(term => uniqueFields.map(field => `${field} match '${term}*'`))
  const constraintString = constraints.map(constraint => `(${constraint.join(' || ')})`).join(' && ')
  return client.observable.fetch(`*[${constraintString}][0...10]`)
}


export default enhanceClickOutside(class Search extends React.Component {
  input$ = new Multicast()
  componentWillUnmount$ = new Multicast()

  state = {
    isOpen: false,
    hits: [],<commit_msg>[default-layout] Include string fields of documents in search.<commit_after>import React from 'react'
import schema from 'part:@sanity/base/schema?'
import client from 'part:@sanity/base/client?'
import Preview from 'part:@sanity/base/preview?'
import Multicast from '@sanity/observable/multicast'
import {IntentLink} from 'part:@sanity/base/router'
import {flatten, union} from 'lodash'
import SearchIcon from 'part:@sanity/base/search-icon'
import Spinner from 'part:@sanity/components/loading/spinner'
import enhanceClickOutside from 'react-click-outside'
import Ink from 'react-ink'
import styles from './styles/Search.css'

function isParentOf(possibleParent, possibleChild) {
  let current = possibleChild
  while (current) {
    if (current === possibleParent) {
      return true
    }
    current = current.parentNode
  }
  return false
}

export const DRAFTS_FOLDER = 'drafts'
const DRAFTS_PREFIX = `${DRAFTS_FOLDER}.`

function isDraftId(id) {
  return id.startsWith(DRAFTS_PREFIX)
}

function getPublishedId(id) {
  return isDraftId(id) ? id.slice(DRAFTS_PREFIX.length) : id
}

function getDraftId(id) {
  return isDraftId(id) ? id : DRAFTS_PREFIX + id
}

// Removes published documents that also has a draft
function removeDupes(documents) {
  const drafts = documents.map(doc => doc._id).filter(isDraftId)

  return documents
    .filter(doc => {
      const draftId = getDraftId(doc._id)
      const publishedId = getPublishedId(doc._id)
      const hasDraft = drafts.includes(draftId)
      const isPublished = doc._id === publishedId
      return isPublished ? !hasDraft : true
    })
}

function is(typeName, type) {
  return type.name === typeName || (type.type && is(typeName, type.type))
}

function search(query) {
  if (!client) {
    throw new Error('Sanity client is missing')
  }

  const candidateTypes = schema.getTypeNames()
    .filter(typeName => !typeName.startsWith('sanity.'))
    .map(typeName => schema.get(typeName))

  const hasDocuments = candidateTypes.some(type => is('document', type))

  const filterFn = hasDocuments
    ? type => is('document', type)
    : type => is('object', type) /* this is only for maintaining backwards compatibility after
                                    introducing the 'document' type. Should be removed eventually
                                  */

  const searchableFields = flatten(
    candidateTypes.filter(filterFn)
      .map(type => type.fields
        .filter(field => field.type.jsonType === 'string')
        .map(field => field.name))
  )

  const terms = query.split(/\s+/).filter(Boolean)
  const uniqueFields = union(searchableFields)
  const constraints = terms.map(term => uniqueFields.map(field => `${field} match '${term}*'`))
  const constraintString = constraints.map(constraint => `(${constraint.join(' || ')})`).join(' && ')
  return client.observable.fetch(`*[${constraintString}][0...10]`)
}

export default enhanceClickOutside(class Search extends React.Component {
  input$ = new Multicast()
  componentWillUnmount$ = new Multicast()

  state = {
    isOpen: false,
    hits: [],
{'fraction_non_alphanumeric': 0.13090654532726637, 'fraction_numerical': 0.0010500525026251313, 'mean_word_length': 3.9738903394255876, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2400198', 'n_tokens_mistral': 1806, 'n_tokens_neox': 1777, 'n_words': 435}