@sinequa/atomic

Tabs, scopes and sorting

The three selectors the server configures for you — what each one restricts, and why their options should never be hardcoded.

Three properties of a query, three server-configured lists of options, and one rule: read the options from the configuration rather than writing them in your code. An administrator changes them, and an interface that hardcoded a list quietly stops matching the deployment.

PropertyRestrictsOptions come from
tabA top-level slice of the corpus, with its own countCCQuery.tabSearch.tabs
scopeA server-defined subset the user switches betweenCCQuery.scopes
sortThe ordering — by name, not by clauseCCQuery.sortingChoices

Tabs

Concept — a tab

A tab is a distribution presented as navigation: "All (1 240)", "Documents (830)", "People (78)". The server counts each one, so the numbers come back with the results — you do not run a query per tab.

result.tabs carries each tab with its count; result.tab is the one that was applied.

Tabs with their counts
src/tabs.ts
import { createAtomicClient, sysLang } from "@sinequa/atomic";
import type { Result } from "@sinequa/atomic";

const client = createAtomicClient({
  app: "<your-app>",
  backendUrl: "https://<your-sinequa-server>",
});

await client.initializeConfig();
await client.auth.login();

const state = { text: "report", tab: undefined as string | undefined, page: 1 };

export async function search(): Promise<Result> {
  return client.api.query.search({
    name: "<your-query>",
    text: state.text,
    tab: state.tab,
    page: state.page,
    pageSize: 10,
  });
}

export async function selectTab(value: string) {
  state.tab = value;
  // A different tab is a different result set: page 7 of it may not exist.
  state.page = 1;
  return search();
}

const result = await search();

for (const tab of result.tabs ?? []) {
  const selected = tab.value === result.tab;
  // Labels are multilingual strings — decode before displaying.
  console.log(`${selected ? ">" : " "} ${sysLang(tab.display, "en-US")} (${tab.count})`);
}

What the tab configuration decides

CCQuery.tabSearch holds more than the list, and two of its keys change what you receive:

Prop

Type

A CCTab also carries excludedAggregations and excludedIndices: selecting that tab drops those facets from the response and those indexes from the search. So a facet disappearing when a tab is selected is configuration, not a bug.

Scopes

A scope is a restriction the administrator defined and named — a subset of the corpus the user can switch between, without expressing it as a filter. Options come from CCQuery.scopes, each with name, an optional display, and isDefault.

applying a scope
const result = await client.api.query.search({
  name: "<your-query>",
  text: "report",
  scope: "internal-only", // a CCScope name
});

result.scope reports the one applied. Use scopes for restrictions the server owns, and filters for everything the user builds.

Sorting

sort takes the name of a sorting choice, not an ordering clause:

sorting by name
const app = await client.api.app.get();
const choices = app.queries["<your-query>"].sortingChoices ?? [];

// ["relevance", "date", "title"] — whatever the administrator configured
console.log(choices.map((c) => c.name));

const result = await client.api.query.search({
  name: "<your-query>",
  text: "report",
  sort: "date",
});

Which choice is the default depends on the query

Two flags on CCSortingChoice, and the one that applies is decided by whether the query had text to rank by:

FlagApplies when
isDefaultWithRelevanceThe query had search text — result.hasRelevance is true
isDefaultNoRelevanceIt did not: a corpus listing has no relevance to sort on

So a "sort by relevance" option must be hidden, or disabled, when hasRelevance is false — there is nothing to sort by:

offering the right options
const available = choices.filter(
  (choice) => result.hasRelevance || choice.name !== "relevance",
);

const currentDefault = choices.find((choice) =>
  result.hasRelevance ? choice.isDefaultWithRelevance : choice.isDefaultNoRelevance,
);

Pitfalls

What's next

On this page