Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Visual loader API #25374

Closed
5 tasks
timroes opened this issue Nov 8, 2018 · 3 comments
Closed
5 tasks

New Visual loader API #25374

timroes opened this issue Nov 8, 2018 · 3 comments
Labels
discuss Feature:ExpressionLanguage Interpreter expression language (aka canvas pipeline)

Comments

@timroes
Copy link
Contributor

timroes commented Nov 8, 2018

When switching to using the canvas expressions for all visualizations (see #19813) we want to provide a new API as a replacement for the existing Visualize Loader. The API should fulfill the following purposes:

  • Allow embedding saved visualizations in a DOM node
  • Allow embedding unsaved visualizations (just by specifying an expression) in a DOM node
  • Using a saved or unsaved expression just for data fetching (and not rendering)

This is the draft of the API (in TypeScript) that we want to use.

import { Observable } from 'rxjs';
import { PersistedState } from '../../persisted_state';

type InspectorSession = any; // Is actually a different type

type Ast = any;
type RenderId = number;
type Data = any;
type Query = { language: string; query: string; };
type Filters = any; // Should be our actual filters format

/**
 * The search context describes a specific context (filters, time range and query)
 * that will be applied to the expression for execution. Not every expression will
 * be effected by that. You have to use special functions (currently called `kibanaContext`)
 * that will pick up this search context and forward it to following functions that understand
 * it.
 */
interface SearchContext {
  filters?: Filters[];
  query?: Query;
  timeRange?: { from: string; to: string };
}

interface Handler {
  data$: Observable<Data>;
  expression$: Observable<{ expression: string; ast: Ast }>;
  render$: Observable<RenderId>;

  destroy(): void;
  getExpression(): string;
  getAst(): Ast;
  getElement(): HTMLElement;

  hasInspector(): boolean;
  openInspector(): InspectorSession;

  update(params: LoaderParams): void;

  execute(params?: { disableCaching?: boolean }): Promise<Data>;
  render(element: HTMLElement): RenderId;

  // Not sure if we need that method to basically render with specific data.
  // renderWithData(element: HTMLElement, data: Data);
}

interface LoaderParams {
  searchContext?: SearchContext;
  cssClass?: string;
  dataAttrs?: { [key: string]: string };
  // Final state handling still needs to be discussed
  uiState?: PersistedState;
}

// The following methods are the high level method you'll use to create a loader (Handler):

/**
 * Load a saved visualization by its saved object id.
 * @param savedObjectId the id of the saved object
 * @param params The initial parameters used for the loader (some of them can be changed later).
 * @returns Returns a promise that will resolve with the loader as soon as the saved object has been loaded.
 */
export type loadById = (savedObjectId: string, params: LoaderParams) => Promise<Handler>;
/**
 * Initiate a loader to render (or gather data) from an unsaved expression.
 * @param expression The expression as a plain string, that should be used for rendering.
 * @param params The initial parameters used for the loader (some of them can be changed later).
 * @returns Returns a handler to interact with the loader.
 */
export type loadExpression = (expression: string, params: LoaderParams) => Handler;
/**
 * Initiate a loader to render (or gather data) from an unsaved expression specified in its
 * AST form. This is especially useful for editor implementations, who usually would build
 * the expression as an AST from its UI. That way they don't need to convert it to a string
 * before the loader converts it back to an AST again.
 *
 * We don't consider this method part of the public API for now, and would not recommend using
 * this outside of Kibana, to prevent potential breakage if we might need to update the AST format
 * in the beginning.
 *
 * @ignore
 * @param expression The expression as a plain string, that should be used for rendering.
 * @param params The initial parameters used for the loader (some of them can be changed later).
 * @returns Returns a handler to interact with the loader.
 */
export type loadExpressionAst = (ast: Ast, params: LoaderParams) => Handler;

TODOs

  • How should we name the top level file/object? Vis loader might not be the right name anymore, if you can also use it to purely load data from expressions.
  • Shall we split up update into multiple functions instead of one (e.g. having a separate function to update only parts of the SearchContext)?
  • Can Data be typed anyhow more specific since it's the output of the expression?
  • Do we need easier "one method wrappers" to, e.g. just load a vis in a DOM element, without caring about the handler?
  • Do we need React components to encapsulate the vis rendering use-case?
@timroes timroes added discuss Feature:ExpressionLanguage Interpreter expression language (aka canvas pipeline) Team:Visualizations Visualization editors, elastic-charts and infrastructure labels Nov 8, 2018
@elasticmachine
Copy link
Contributor

Pinging @elastic/kibana-app

@elasticmachine
Copy link
Contributor

Pinging @elastic/kibana-app-arch (Team:AppArch)

@ppisljar
Copy link
Member

ppisljar commented Mar 9, 2020

expression service offer similar interface to what was proposed here

@ppisljar ppisljar closed this as completed Mar 9, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
discuss Feature:ExpressionLanguage Interpreter expression language (aka canvas pipeline)
Projects
None yet
Development

No branches or pull requests

3 participants