SmartSnippet

The SmartSnippet controller allows to manage the excerpt of a document that would be most likely to answer a particular query .

Methods

beginDelayedSelectSource

Prepares to select the source after a certain delay, sending analytics if it was never selected before.

In a DOM context, we recommend calling this method on the touchstart event.

cancelPendingSelectSource

Cancels the pending selection caused by beginDelayedSelect.

In a DOM context, we recommend calling this method on the touchend event.

closeFeedbackModal

Allows the user to signal that they no longer wish to send feedback about why a particular answer was not relevant.

collapse

Collapse the snippet.

dislike

Allows the user to signal that a particular answer was not relevant.

expand

Expand the snippet.

like

Allows the user to signal that a particular answer was relevant.

openFeedbackModal

Allows the user to signal that they wish to send feedback about why a particular answer was not relevant.

selectSource

Selects the source, logging a UA event to the Coveo Platform if the source wasn’t already selected before.

In a DOM context, we recommend calling this method on all of the following events: * contextmenu * click * mouseup * mousedown

sendDetailedFeedback

Allows the user to send detailed feedback about why a particular answer was not relevant.

Parameters

  • details: string

    A personalized message from the end user about the relevance of the answer.

sendFeedback

Allows the user to send feedback about why a particular answer was not relevant.

Parameters

  • feedback: 'does_not_answer' | 'partially_answers' | 'was_not_a_question'

    The generic feedback that the end user wishes to send.

subscribe

Adds a callback that’s invoked on state change.

Parameters

  • listener: () => void

    A callback that’s invoked on state change.

Returns Unsubscribe: A function to remove the listener.

Attributes

state

The state of the SmartSnippet controller.

Properties

  • answer: string

    The answer, or snippet, related to the question.

  • answerFound: boolean

    Determines of there is an available answer for the current query.

  • disliked: boolean

    Determines if the snippet was disliked, or downvoted by the end user.

  • documentId: QuestionAnswerDocumentIdentifier

    The index identifier for the document that provided the answer.

  • expanded: boolean

    Determines if the snippet is currently expanded.

  • feedbackModalOpen: boolean

    Determines if the feedback modal with the purpose of explaining why the end user disliked the snippet is currently opened.

  • liked: boolean

    Determines if the snippet was liked, or upvoted by the end user.

  • question: string

    The question related to the smart snippet.

  • source?: Result

    Provides the source of the smart snippet.

Initialize

buildSmartSnippet

Creates a SmartSnippet controller instance.

Parameters

  • engine: SearchEngine

    The headless engine.

  • props: SmartSnippetProps

    The configurable SmartSnippet properties.

Returns SmartSnippet

SmartSnippetProps

The configurable SmartSnippet properties.

Properties

SmartSnippetOptions

The options for the SmartSnippet controller.

Properties

  • selectionDelay?: number

    The amount of time in milliseconds to wait before selecting the source after calling beginDelayedSelect.

    Default: 1000

HighlightKeyword

Properties

  • length: number

    The length of the offset.

  • offset: number

    The 0 based offset inside the string where the highlight should start.

QuestionAnswerDocumentIdentifier

Properties

  • contentIdKey: string

    The content identifier key. Typically, permanentid or urihash.

  • contentIdValue: string

    The content identifier value.

Raw

Properties

  • [key: string]: unknown

    Custom keys that depend on the documents in the index.

Result

Properties

  • absentTerms: string[]

    The basic query expression terms which this query result item does not match. Note: This property is populated by terms from the query pipeline-processed q value (not from the original q value).

  • clickUri: string

    The hyperlinkable item URI. Notes: Use the clickUri value when you want to create hyperlinks to the item, rather than the uri or printableUri value.

  • excerpt: string

    The contextual excerpt generated for the item (see the excerptLength query parameter).

  • excerptHighlights: HighlightKeyword[]

    The length and offset of each word to highlight in the item excerpt string.

  • firstSentences: string

    The first sentences retrieved from the item (see the retrieveFirstSentences query parameter).

  • firstSentencesHighlights: HighlightKeyword[]

    The length and offset of each word to highlight in the item firstSentences string.

  • flags: string

    The flags that are set on the item by the index. Distinct values are separated by semicolons.

  • hasHtmlVersion: boolean

    Whether the index contains an HTML version of this item.

  • isRecommendation: boolean

    Whether the item score was boosted as a Coveo ML recommendation.

  • isTopResult: boolean

    Whether the item score was boosted by a featured result rule in the query pipeline.

  • percentScore: number

    The item ranking score expressed as a percentage (see the sortCriteria and rankingFunctions query parameters).

  • printableUri: string

    The human readable item URI. Note: Avoid using the printableUri value to create hyperlinks to the item. Use the clickUri value instead.

  • printableUriHighlights: HighlightKeyword[]

    The length and offset of each word to highlight in the item printableUri string.

  • rankingInfo: string | null

    The raw debug information generated by the index to detail how the item was ranked. This property is null unless the debug query parameter is set to true.

  • raw: Raw

    The values of the fields which were retrieved for this item (see the fieldsToInclude and fieldsToExclude query parameters).

  • score: number

    The total ranking score computed for the item (see the sortCriteria and rankingFunctions query parameters).

  • summary: null

    The item summary (see the summaryLength query parameter).

  • summaryHighlights: HighlightKeyword[]

    The length and offset of each word to highlight in the item summary string.

  • title: string

    Contains the title of the item.

  • titleHighlights: HighlightKeyword[]

    The length and offset of each word to highlight in the item title string.

  • uniqueId: string

    The unique item identifier. You should consider the uniqueId value as an opaque string.

  • uri: string

    The item URI. Notes: Avoid using the uri value to create hyperlinks to the item. Use the clickUri value instead.

  • rankingModifier?: string

    If applicable, represents the type of ranking modification that was applied to this result.

Unsubscribe

Call signatures

  • (): void

Example Implementation

smart-snippet.fn.tsx

import {useEffect, useState, FunctionComponent, useRef} from 'react';
import {SmartSnippet as HeadlessSmartSnippet} from '@coveo/headless';
import {filterProtocol} from '../../utils/filter-protocol';
 
interface SmartSnippetProps {
  controller: HeadlessSmartSnippet;
}
 
export const SmartSnippet: FunctionComponent<SmartSnippetProps> = (props) => {
  const {controller} = props;
  const [state, setState] = useState(controller.state);
  const detailedAnswerRef = useRef<HTMLTextAreaElement>(null);
 
  useEffect(() => controller.subscribe(() => setState(controller.state)), []);
 
  const answerStyles = (expanded: boolean) => {
    const maskImage = () =>
      expanded
        ? 'none'
        : 'linear-gradient(to bottom, black 50%, transparent 100%)';
 
    return {
      maxHeight: expanded ? '100%' : '100px',
      maxWidth: '200px',
      overflow: 'hidden',
      marginBottom: '10px',
      maskImage: maskImage(),
      WebkitMaskImage: maskImage(),
    };
  };
 
  const {
    answerFound,
    answer,
    question,
    liked,
    disliked,
    expanded,
    source,
    feedbackModalOpen,
  } = state;
 
  if (!answerFound) {
    return <div>Sorry, no answer has been found for this query.</div>;
  }
 
  function renderSource() {
    if (!source) {
      return;
    }
    return (
      <a
        href={filterProtocol(source.clickUri)}
        onClick={() => controller.selectSource()}
        onContextMenu={() => controller.selectSource()}
        onMouseDown={() => controller.selectSource()}
        onMouseUp={() => controller.selectSource()}
        onTouchStart={() => controller.beginDelayedSelectSource()}
        onTouchEnd={() => controller.cancelPendingSelectSource()}
      >
        Source
      </a>
    );
  }
 
  if (feedbackModalOpen) {
    return (
      <div role="dialog">
        <h1>What's wrong with this snippet?</h1>
        <fieldset>
          <legend>Give a simple answer</legend>
          <ul>
            <li>
              <button
                onClick={() => controller.sendFeedback('does_not_answer')}
              >
                It does not answer my question
              </button>
            </li>
            <li>
              <button
                onClick={() => controller.sendFeedback('partially_answers')}
              >
                It only partially answers my question
              </button>
            </li>
            <li>
              <button
                onClick={() => controller.sendFeedback('was_not_a_question')}
              >
                I was not asking a question
              </button>
            </li>
          </ul>
        </fieldset>
        OR
        <fieldset>
          <legend>Give a detailed answer</legend>
          <textarea ref={detailedAnswerRef}></textarea>
          <button
            onClick={() =>
              detailedAnswerRef.current &&
              controller.sendDetailedFeedback(detailedAnswerRef.current.value)
            }
          >
            Send feedback
          </button>
        </fieldset>
        <button onClick={() => controller.closeFeedbackModal()}>Cancel</button>
      </div>
    );
  }
 
  return (
    <div style={{textAlign: 'left'}}>
      <dl>
        <dt>{question}</dt>
        <dd>
          <div
            dangerouslySetInnerHTML={{__html: answer}}
            style={answerStyles(expanded)}
          ></div>
          <button
            style={{display: expanded ? 'none' : 'block'}}
            onClick={() => controller.expand()}
          >
            Show complete answer
          </button>
          <button
            style={{display: expanded ? 'block' : 'none'}}
            onClick={() => controller.collapse()}
          >
            Collapse answer
          </button>
          <button
            style={{fontWeight: liked ? 'bold' : 'normal'}}
            onClick={() => controller.like()}
          >
            Thumbs up
          </button>
          <button
            style={{fontWeight: disliked ? 'bold' : 'normal'}}
            onClick={() => controller.dislike()}
          >
            Thumbs down
          </button>
          {renderSource()}
          {disliked ? (
            <button onClick={() => controller.openFeedbackModal()}>
              Explain why
            </button>
          ) : (
            []
          )}
        </dd>
      </dl>
    </div>
  );
};
 
// usage
 
/**
 * ```tsx
 * const controller = buildSmartSnippet(engine);
 *
 * <SmartSnippet controller={controller} />;
 * ```
 */
What's Next for Me?